1. JLPT 단어 및 독해


공부 내용 및 문제 풀은것 등의 사진을 일단 내 컴퓨터에 파일형태로 킵;(저작권 문제)



2. 알고리즘 공부


백준 알고리즘 [1065번 한 수]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import java.io.*;
 
public class Main {
 
    public static void main(String[] args) throws IOException {
 
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 
        int cnt = 0;
        int x = Integer.parseInt(String.valueOf(br.readLine()));
 
        for(int i=1; i<x+1; i++){
            cnt += getHanNum(i);
        }
 
        bw.write(String.valueOf(cnt));
        bw.flush();
        bw.close();
    }
 
    private static int getHanNum(int num){
 
        int hanNum = num;
        int[] oneToEndArr = new int[String.valueOf(num).length()];      //index에 0부터 일의 자리의 숫자가 들어가는 배열
 
        if(oneToEndArr.length <= 2){        //어차피 0을 제외한 100 이하 자리는 전부 다 한수이기 때문에
            return 1;
        }else{
            int[] d = new int[oneToEndArr.length-1];        //100부터 1000까지는 여기에 들어와서 각 항의 차를 구한다.
            int j= 0, temp = 0;
 
            for(int i=0; i<oneToEndArr.length; i++){        //우선, 각 자릿수를 구해서 일의자리부터 끝자리까지에 해당하는 수를 oneToEndArr 배열에 넣어준다
                oneToEndArr[i] = hanNum%10;
                hanNum /= 10;
            }
 
            for(int i=oneToEndArr.length-1; i>0; i--){      //일의 자리와 십의 자리, 십의 자리와 백의 자리에 해당하는 차를 d 배열에 넣는다
                d[j] = oneToEndArr[i] - oneToEndArr[i-1];
                j++;
            }
            if(d[0== d[1]){                               //각 항의 차가 등차가 되는지 비교
                return 1;
            }else{
                return 0;
            }
        }
    }
}
cs

아쉬웠던 점: 입력이 1000이하의 숫자가 들어간다는게 조건이지만 1000이상의 자릿수가 입력이 됐을때에도 작동하게 만들고 싶어서 욕심을 내다보니 시간을 많이 잡아먹었다.

카테고리의 목적: 



   무엇을 할 것인가? 본 포스팅 카테고리에서는 JLPT와 알고리즘 공부한 내용을 포스팅 할 것인데, 사실 공부를 너무 게으르게 해서 목표치를 가지고 공부해서 JLPT N2 취득 및 알고리즘 공부 이 두 마리 토끼를 다 잡아볼 예정이다.


   어떻게 할 것인가? JLPT 시험에서 컷트라인을 넘겨도 N2 독해에서 과락이 나와서 취득이 어려우니 'JLPT 콕콕 찍어주마 N2 독해', '딱 한 권 JLPT N2단어장'으로 각각 20p, 1Day씩 공부하고, 알고리즘은 BOJ 단계별 풀어보기 부분에서 한 문제 이상씩 풀어서 공부한 내용을 간단히 사진첨부와 함께 시험 전 날인 12월 2일 전까지(일주일간) 포스팅할 것이다.


   왜 JLPT를 공부하나? 사실 공대생에게 어학능력이란 C, Java, React.js등 대중적인 컴퓨터언어능력을 높이는게 도움이 되지 어학능력은 크게 도움이 되질않는다. 하지만 나는 글로벌하게 인간관계를 구축하고 싶은 욕심이 있기도 하고, 나아가 이 능력을 증명해 추후 다른 분야에서도 활용하고 싶기떄문에 이 자격증을 따려고 한다. 굳이 JLPT만 준비하는 것도 아닐뿐더러, 해외 어학원 경험을 통해 외국인과도 편하게 말을 주고받을 수 있는 상태이다. 외국인 친구도 다수 사귀었고, 이 능력을 십분 활용해 OPIc시험에서도 공대생치고는 높은 점수를 받았다.(OPIc 시험을 준비할 떄엔 블로그를 쓸 생각을 하지않았으니 OPIc 포스팅은 패스)


   최종적으로? 일본어로 된 IT관련 기술블로그 포스팅 된 것을 번역해서 올려보자.



상세한 내용은 거두절미하고 오늘부터 스타트!


D-6



1. 일본어 단어 암기 및 문제 푼거


사진을 올리려했으나 저작권의 문제가 있으니 일단 올리고 비공개로 대체.... 하려했으나 최대 업로드 가능 용량이 10메가인 관계로 일단 킵;


2. 백준 알고리즘 [4673번 셀프넘버]


풀이 코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import java.io.*;
 
public class Main {
 
    public static void main(String[] args) throws IOException {
 
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 
        boolean[] isNotSelfNum = new boolean[10000];            //셀프넘버가 아닌건지를 물어보는 것이기 때문에 
                                                                // false -> 셀프넘버 , true -> 생성자가 있는 넘버
 
        for(int i=0; i<isNotSelfNum.length; i++){
            if(getDn(i)<10000){
                isNotSelfNum[getDn(i)] = true;
            }
        }
 
 
        for(int i=0; i<10000; i++){
            if(!isNotSelfNum[i]){
                bw.write(String.valueOf(i));
                bw.newLine();
                bw.flush();
            }
        }
        bw.close();
 
    }
 
    private static int getDn(int i){                //selfNumber가 아닌 수들을 반환
 
        int dn, thousand, hundred, ten, one;
 
        thousand = i/1000;
        hundred = i/100%10;
        ten = i/10%100%10;
        one = i%10;
 
        dn = i + thousand + hundred + ten + one;
 
        return dn;
    }
}
cs


헤맨 부분: 처음에는 12번째 for문의 진행이 아닌 while(true)문으로해서 getDn메소드로 반환받는 숫자가 10000보다 커지면 break문으로 탈출해서 더 이상 getDn의 매개변수로 숫자가 들어갈 일이 없게 즉, dn의 크기가 10000만 넘기만 한다면 다음 숫자를 적용시키지 않았다. 실제로 값을 넣어서 구해보면 d(9968) = 10000인데, d(9973) = 9999이다. 따라서 생성자가 있는데도 불구하고 셀프넘버로 들어가버린 숫자가 존재했고 그대로 출력해서 문제를 틀렸었던것.

시작하며


 알고리즘 공부를 하다보면 여러 숫자들을 비교해야하는 경우가 다분히 생기는데, 그 때마다 형변환을 해준다던지 Integer.valueOf나 Integer.parseInt를 사용해서 숫자를 비교하며 조건문을 넣어주는 경우가 많이 생긴다. 알고리즘을 공부하면서 그 둘의 차이점이 무엇인지 문득 궁금해졌는데 그 차이에 대해 알아보도록 하자.



들어가며

우선 parseInt와 valueOf의 주된 차이점에 대해 알아보자.


  • Integer.parseInt : Primitive type인 int형을 반환


1
2
3
public static int parseInt(String s) throws NumberFormatException {
        return parseInt(s,10);
}

cs



  • Integer.valueOf : Wrapper Object인 Integer를 반환

1
2
3
public static int parseInt(String s) throws NumberFormatException {
        return parseInt(s,10);
}

cs




  위의 두 가지 코드의 차이에 대해서 알아보자.

 


우선, 코드상에서 보이는 가장 큰 차이는 

  • 반환 타입이 int와 Integer Obejct로 다르다는 것이다.



♤그렇다면 여기서 int와 Integer는 어떻게 다른가?


간단하게 말하자면 int는 기본자료형(unboxed primitive type)

Integer는 참조자료형 또는 기본자료형들에 대응되는 객체화된 자료형(boxed primitive type) 이라고 할 수가 있겠다.

아니, 그동안 int형만 자주 쓰느라 참조자료형이랑 말은 생소한데 이건 또 뭐지.... 하는 의문이 생겼고


또, 그렇다면 기본 자료형과 객체화 된 자료형은 어떻게 다른가?로 귀결될 수 있는데!

보통 흔히 쓰는 int, long, boolean등의 자료형들을 기본 자료형이라 하고 Integer, Long, Boolean 등을 객체화 된 자료형이라고 한다.


이렇게만 설명을 들으면 이해하기가 힘들기 때문에 몇 가지 예시를 통해서 기본 자료형과 객체화 된 자료형의 차이를 보도록 하자.


1. 기본자료형은 값만 가지지만 객체환 된 자료형은 각각의 신원(identity)을 가진다.

 -> 즉, int a = 42, b = 42; 일때 a==b는 같지만 c==d는 다를 수 있다는것


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int a = 42;
int b = 42;
 
Integer c = new Integer(42);
Integer d = new Integer(42);
 
if(a==b){
    System.out.println("Success");
}
 
if(c==d){
    System.out.println("Success too");
}else{
    System.out.println("They have different identity");
}

cs




2. 기본 자료형은 int형 값을 가지기 때문에 산술연산을 할 수 있지만 객체화 된 자료형은 Integer클래스을 받기 때문에 

    unboxing(wrapper 클래스 -> primitive 자료형)을 해주지 않으면 산술연산을 할 수 없다. 하지만, 기본자료형과 달리 null값으로 처리할 수 있기

    때문에 SQL과 연동할 경우 처리가 용이하다.


1
2
int a = null;           // null값으로 초기화 할 수 없음
Integer b = null;       // null값으로 초기화 할 수 있음
cs



3. 굳이 객체화된 자료형을 사용할 이유가 없다면 primitive 타입을 쓰는 것이 공간효율적인 측면에서 좋다.


Integer의 사이즈 : 20byte

int의 사이즈 : 4byte



그렇다면 Integer(객체화 된 자료형)는 언제 쓰는가?

 

 Integer와 같은 객체화 된 자료형들은 아까 위에서 보았듯이,


첫째, null값으로의 처리가 유용하기 때문에 SQL과 연동할 경우 즉, DB를 사용해서 쿼리문을 짜줘야하는 경우에 유용하다.

둘째, ArrayList나 List등의 요소, 키, 값으로 사용할 때 이다. 다시 말해서 ArrayList<int>는 안되지만 ArrayList<Integer>로 사용할 수 있다는 말이다.


끝마치며

 처음에는 단순히 valueOf와 parseInt의 차이점에 대해서만 간단히 쓰고 넘어가고자 했는데 공부하면서 Integer(Wrapper Class)와 int(Primitive type)의 차이에 대해서 알아야된다는 것을 알게 되었고, 기본 자료형과 참조 자료형의 차이에 대해 비교를 하게 되었다. 그리고 결국엔 돌고돌아 parseInt와 valueOf의 정확한 return 타입과 그 쓰임새에 대해 이해할 수 있게 되었다.


 처음에는 단순히 이렇게 마냥 쓰는거구나 하면서 아무생각 없이 선언했었지만 이렇게 점점 깊게 파보게 되니 Auto-boxing, Auto-unboxing의 개념에 대해서도 알게 되었고 쓸데없이 객체를 만들거나 자바에서 객체화 비객체화가 일어나며 리소스를 낭비될 수 있다는 것도 이해하게 되어 시간은 오래걸렸지만 좀 더 기본기에 대한 이해도가 높아진 것에 대해 만족한다.

'알고리즘 공부 > 알고리즘 지식' 카테고리의 다른 글

Scanner와 BufferReader의 차이  (0) 2018.10.09


시작하며

 

 대외활동에서 프로젝트를 하면서 보안적인 측면의 안전과 서버의 부담을 줄이기 위해서 JSON Web Token을 이용하여 사용자 인증과정을 거쳤는데, 어떻게 하면 된다는 방식은 알고있었지만 자세히 정리하여 내 것으로 만든 적이 없었기 때문에 정리를 해보려고 한다.


들어가며

 

  JWT(JSON Web Token)기반의 회원인증 시스템 구현에 대해서 설명을 시작하기에 앞서 JWT를 포함한 총 3가지사용자 인증방식에 대해 알아보자.


  1. Cookie
  2. Session
  3. JWT

  • Cookie

 -쿠키(Cookie)란


 하이퍼 텍스트의 기록서(HTTP)의 일종으로서 사용자가 어떠한 웹사이트를 방문할 경우 그 사이트가 사용하고 있는 서버를통해 인터넷 사용자의 컴퓨터에 설치되는 작은 기록 정보 파일을 일컫는다. 이 기록 파일에 담긴 정보는 인터넷 사용자가 같은 웹사이트를 방문할 때마다 읽히고 수시로 새로운 정보 바뀐다.

[출처: 위키백과]


<Firefox 설정 -> 개인정보 및 보안 -> 데이타 관리에 들어갔을 때>


- 쿠키의 단점


 쿠키라는 용어는 IT쪽에 직접적인 관련이 없는 일반인들도 상당히 많이 들어봤을 법한 말이라고 생각하는데, 이는 요즘 스마트폰에서 용량을 확보하기 위해 '쿠키를 삭제하시겠습니까?' 라는 용어나 FIrefox나 Explorer에서도 사용자가 직접 쿠키를 삭제하는 방법도 꽤나 잘 알려져 있기 때문이라고 생각한다. 이렇듯 쿠키는 자주 사용되고 변경되는만큼 사용자 뿐만 아니라 악성 유저에게도 탈취될 가능성을 무시할 수 없는데, 혹시 보안이 허술한 웹사이트에 들어가게된다면 사용자의 개인정보에 관련된 쿠키가 쌓이게 되고 클라이언트와 서버가 쿠키를 주고 받는 과정에서 탈취되어 이는 악성유저에게 악용될 여지를 만들어낼 수 있다.


- 쿠키 사용의 예

 

 1. 방문 사이트에서 로그인을 했을 때, 아이디와 비밀번호를 저장하겠습니까?

 2. 팝업창이 떴을 때, 오늘 하루/일주일간 팝업창을 보지 않음.

  • Session

 -세션(Session)이란


 간단히 말하자면 해당 서버(웹)가 접근한 클라이언트(사용자)를 식별한 상태를 유지하는 방법이라고 할 수 있다. 즉, 사용자가 브라우저를 열어 서버에 접속한 후부터 접속을 종료한 시점까지를 말한다. Session은 설명보다는 동작원리를 보는 편이 이해가 더 편하다.


 -세션의 동작원리


 1. 유저(사용자)가 웹사이트에 접속하여 Request를 보낸다.

 2. 해당 웹사이트(서버)가 유저가 Session ID라는 문자열을 발급받았는지 여부를 검사하고, 발급 받지않은 경우 Memory Cookie형태로 Session ID라는 임의의 긴 문자열을 가진 쿠키(JSESSIONID)를 발급해준다.(Memory Cookie는 세션 종료 시 같이 소멸되는 휘발성을 가진 쿠키이다.)

 3. *HTTP 프로토콜은 비접속형 프로토콜로 매 접속시마다 새로운 연결을 필요로하는데 세션이 이 연결을 유지하도록 도와준다.


<Firefox 사용 시 F12키를 누른 후 저장소를 가서 세션을 확인가능>



*HTTP 프로토콜의 두 가지 특징 및 장점, 단점


 <특징>

  1. Connectionless: 클라가 서버에게 Request를 보내고 서버가 클라에게 Response를 보내고 나면 연결을 끊는다.

  2. Stateless: 접속을 끊는 순간 상태정보를 유지하지않는다.   

<장점 및 단점>

       위의 두 가지의 특징으로 인해 자원을 계속해서 낭비할 필요가 없어진 것이 장점이라고 할 수 있고, 단점은 상태를 유지하지않기때문에 매번

  통신할때마다 클라이언트의 신원을 체크해야한다.





-쿠키와 세션의 간단한 같은 점과 차이점


 쿠키와 세션은 어떻게 보면 둘 다 쿠키를 쓴다는 점과 상태를 유지시켜준다는 점에서 비슷하다고 할 수 있습니다.

 

 하지만 이 둘의 가장 큰 차이점은 저장되는 장소의 차이라고 볼 수있고, 이로 인해 보안성과 속도의 차이가 나타날 수 있다.


쿠키는 위에서 말했듯이 클라이언트에게 저장되기 때문에 서버요청시 처리 속도는 빠르지만 탈취 및 악용의 가능성을 이유로 개인의 신상정보나 로그인 정보등이 중요한 정보가 들어있어서는 안된다.


 이와 다르게 세션은 클라이언트에게 SessionID를 주고 서버 또한 SessionID를 가지고 있으므로 서버의 자원을 사용하게 되는데 세션은 쿠키 서버의 응답을 기다려야하는 만큼 처리속도도 느리고 이는 사용자 수가 많아졌을 경우 서버에게 부담을 줄 수 있다.



  • JWT(JSON Web Token)

 -JWT란?

 JSON Web Token의 줄임말로써, 인증정보를 암호화하여 전달하기때문에 쿠키에 비해 안전하고 서버의 자원을 쓰는 일도 없는 위의 두 가지 방법의 단점을 보완한 토큰을 이용한 인증방식이다.


 -JWT의 특징


1. 우선, JWT시스템에서 발급된 토큰은 토큰의 기본정보(typ, alg), 전달할 정보(로그인시 필요한 사용자의 정보) 그리고 토큰의 검증을 증명해줄 Signature(서명)까지 가지고 있어 자가수용적(Self-Contained)이라 할 수 있습니다.


2. JSON 포맷으로 통신을 하여 C, Java, Python, C++, R, C#, PHP, JavaScript, Ruby, Go, Swift 등 수많은 프로그래밍 언어에서 지원됩니다.


3. HTTP 헤더에 담아서 전달 혹은 URL의 파라미터로도 전달 가능하여 서버<->클라이언트간의 전달이 쉽습니다.




 -JWT의 구조


 우선, JWT의 구조는 http://jwt.io에 접속하기만 해도 간단하게 알 수 있는데, 다음의 사진과 같다.


 좌측의 Encoded는 우측의 HEADER.PAYLOAD.SIGNATURE 순으로 각각 암호화 하여 '.(콤마)'를 이용하여 나눈것이라고 볼 수 있다.

그럼 이제 각 부분별로 어떤 특징을 가지고 있는지에 대해 자세히 알아보자.


1. HEADER


 -헤더의 구성요소


헤더에는 alg, typ 이 두 가지 키가 존재하는데,


1. alg는 해싱 알고리즘을 뜻하며, Signature부분에서 검증을 위해 사용되는 해싱 알고리즘이다.

2. typ는 토큰의 타입이 무엇인지를 나타낸다.


 위의 사진의 HEADER와 비교해서 설명하자면 HS 256 해싱 알고리즘을 이용한 JWT타입의 토큰을 의미한다고 볼 수 있다.

그리고 하단의 VERIFY SIGNATURE에서 볼 수 있듯이 HMACSHA256 해싱 알고리즘을 이용하여 이정보를 base64로 인코딩하면

Encoded 부분의 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 부분이 완성이 된다.


2. PAYLOAD


-PAYLOAD의 구성요소


 PAYLOAD 혹은 Claim Set이라고도 하는데 이 부분에는 토큰에 담을 정보(Claim들의 Set)가 들어있다.


  • 등록 클레임(Registered)

-이미 등록 되어있는 클레임들을 의미하며 선택적으로 사용할 수 있다.

 1)iss : 토큰의 발급자를 의미(issuer)

 2)sub : 토큰의 제목을 의미(subject)

 3)aud : 토큰의 대상자를 의미(audience)

 4)exp : 토큰의 만료시간을 의미하며 Numeric Date형식으로 되어있다.(expiration)

 5)nbf : 토큰의 활성시간을 의미하며 Numeric Date형식으로 되어 이 날짜 이후부터 토큰이 활성화된다.(not before)

 6)iat : 토큰의 발급시간 즉, 토큰이 발급된지 얼마나 지났는지 등 토큰의 나이를 의미(issued at)

 7)jti : 토큰의 고유 식별자를 의미하며 일회용 토큰으로 사용시에 유용하다.(jwt identity)


  • 공개 클레임(Public)

  -충돌을 방지하기 위해 공개된 클레임이며, 보통 URI형식으로 짓는다. ex) "https://publicclaim.com/jwt_claims/is_admin" : true


  • 비공개 클레임(Private)

  -공개 클레임이나 등록된 클레임과 달리 충돌의 위험이 있으니 서버와 클라이언트간에 잘 협약하여 사용하여야하며 key : value형태로 되어있다.

   {

   ex)     "mytistory" : "ohmycode"

   }


  위의 클레임 들을 key : value 형태로 넣어주면 상단 jwt.io의 사진의 VERIFY SIGNATURE처럼 토큰의 정보에 해당하는 PAYLOAD에 base64방식으로 암Encoding된다.


3. SIGNATURE


 서명을 해주는 중요한 부분인데, 이 부분은 위의 두 가지처럼 약속이 되어있거나 특정한 key, value값이 존재하는 것이 아닌 그야말로 토큰의 서명을 위해서 존재하는 부분이다. 앞서 생성한 HEADERPAYLOAD를 '.(콤마)'를 구분자로 두고 (HEADER.PAYLOAD형식) HS 256해싱 알고리즘으로 해싱을 하고 사용자가 직접 지정한 secretkey를 써서 base64방식으로 Encoding해주면 토큰의 서명 부분까지 완성된다.


이렇게 해서 JWT 하나에 대한 HEADER(알고리즘 형식, 토큰의 타입), PAYLOAD(클레임 별 토큰의 정보), SIGNATURE(앞의 두 가지를 이용한 Secretkey를 포함한 서명)까지 완성하게 된다!



끝마치며

 처음에는 "전에 했던 앱에서 JWT를 사용한 회원의 인증방식에 대해서 간단히 쓰자"라고생각했지만 성격이 성격인지라; 꼼꼼하게 정리하지않으면 직성이 안풀리기 때문에 하나하나 다시 공부해가면서 적었고, 그로인해 시간이 많이 걸렸다... 다음 포스팅에는 본격적으로 JWT를 기반으로 Android에 적용한 부분까지 해보도록 하자.

백준 알고리즘 11781번


문제

입력 받은 대로 출력하는 프로그램을 작성하시오.

입력

입력이 주어진다. 입력은 최대 100줄로 이루어져 있고, 알파벳 소문자, 대문자, 공백, 숫자로만 이루어져 있다. 각 줄은 100글자를 넘지 않으며, 빈 줄은 주어지지 않는다. 또, 각 줄은 공백으로 시작하지 않고, 공백으로 끝나지 않는다.

출력

입력받은 그대로 출력한다.

예제 입력 1

Hello
Baekjoon
Online Judge

예제 출력 1

Hello
Baekjoon
Online Judge


제출한 답안(Java)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.io.*;
 
public class Main {
    public static void main(String[] args){
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);
 
        String str;
        try {
            while ((str = br.readLine())!=null){
                System.out.println(str);
            }
 
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
cs


끝마치며

: 사실 어려운 문제였다기보다는 생각치 못한 부분이 있었는데 while문 조건 안에 while((str = br.readLine())!=null)이라는 형태로 입력조건을 반복시켜서 돌리는 방법은 생각하지 못했고 계속 for문안에 혹은 while(true)로 반복을 돌리고 BufferedWriter를 써서 출력할 생각만 했는데, 차라리 System.out.println이 더 간단하고 코드수나 메모리도 줄일 수 있는 방법이었다.

시작하며


 Java에서는 흔히들 출력을 할 때, java.util 패키지에 있는 Scanner 클래스를 import하여 Scanner sc = new Scanner(System.in); 형식으로 출력을 하도록 배운다. 하지만, 위의 방식보다 java.io 패키지에서 BufferedReader클래스를 import하여 사용하는 것이 속도면에서 우월하다는 것을 알게 되었고 그에 대해 정리해보고자 한다.



들어가며


  • Scanner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.Scanner;
 
public class prac1 {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
 
        int a = sc.nextInt();
        float b = sc.nextFloat();
        String str = sc.next();
        String strWithSpace = sc.nextLine();        //공백을 포함
 
        sc.close();
 
        System.out.println(a);
        System.out.println(b);
        System.out.println(str);
        System.out.println(strWithSpace);
    }
}
 

cs


  • BufferedReader


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.io.*;
 
public class prac1 {
    public static void main(String[] args){
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);
 
        OutputStreamWriter osw = new OutputStreamWriter(System.out);
        BufferedWriter bw = new BufferedWriter(osw);
 
        try {
            String str = br.readLine();     //입력
 
            bw.write(str);                  //출력
            bw.flush();
            bw.close();
 
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 
cs


  위의 두 가지 코드의 차이에 대해서 알아보자.

 

우선, 코드상에서 보이는 가장 큰 차이는 

  • InputStreamReader를 인자로 갖는 BufferedReader
  • try/catch문의 유무이다.


1. InputStreamReader는 입력을 character로 받아오기 때문에 줄단위의 문자열을 입력으로 받아올 떄 불편한 점이 생기고, 이에 따라서 BufferedReader가 생겨나 함께 쓰이기 시작했다.

BufferedReader는 이런 InputStreamReader에 버퍼 기능을 추가한 것인데, 데이터를 한 번에 읽어서 버퍼에 보관시킨 후에 사용자의 요청에 따라 버퍼에서 읽어오게 된다.


2. BufferedReader는 throws Exception을 선언해주어야만 에러없이 사용할 수 있다.


장단점 비교를 하자면


Scanner의 장점은 쓰기 간략하고 편하다(?)를 생각할 수 있겠고, 단점은 속도가 BufferedReader보다 느리다.

BufferedReader의 장점은 Scanner에 비해 처리속도가 빠르다는 것이고, 단점은 InputStreamReader클래스와 BufferedReader클래스 두 가지를 불러오며 try/catch문으로 써야해서 Scanner보다 불편할 수 있다는 것이다.


이렇게 장단점만 비교한다면 Scanner가 하기쉽고 편해서 좋아보이지만


<백준 알고리즘 1000번 문제를 풀었을 때>


<출처 : algospot>


위의 사진들을 보면 알 수 있듯이 시간이 상당히 절약되는 것을 쉽게 알 수 있다.


왜 이러한 결과가 나타나는 걸까?

 

 그 이유는 Scanner는 Regex(Regular Expression)을 많이 사용하여 알아서 Tokenizing과 Parsing을 해주기 때문에 패턴을 분석하는 데에 있어서 시간을 많이 잡아먹기 때문인데, Regex를 이용하면 패턴을 이용해 문자열을 좀 더 세밀히 분석할 수 있다고 한다.



끝마치며

 알고리즘 문제를 풀다보면 str.toString()을 이용해 문자열에 문자를 추가하는 방법과 StringBuilder를 이용해 append로 붙이는 방법처럼 메모리나 시간을 절약해서 풀어야하는 경우가 많았고, 실제로 협업해서 코드를 진행할 때 위와 같은 요소들을 항상 체크하고 서로의 약속으로 만드는 경우가 많았다. 이처럼 항상 메모리와 런타임 시간을 고려하면서 푸는것이 앞으로를 위해 도움이 될 것 같다.


(※위의 toString()과 StringBuilder의 append의 차이에 대한 코드는 추후 작성 예정입니다.)

<SimpleStorage>

-SimpleStorage설명 및 코드

http://www.chaintalk.io/archive/lecture/86


<MyToken>

-이더리움 공식 사이트

https://ethereum.org/token


-자신만의 이더리움 만들기1

https://steemit.com/kr/@twinbraid/3odd6s-01

-자신만의 이더리움 만들기2

https://steemit.com/kr/@twinbraid/5ytoam-02


*코인과 토큰의 차이

https://steemit.com/kr/@worud/coin-token

블록체인 및 비트코인에 대한 이해
https://homoefficio.github.io/2017/11/19/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%ED%95%9C-%EB%B2%88%EC%97%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0/

이더리움으로 dApp만들어보기 예제강좌(1~6)
http://www.chaintalk.io/archive/lecture/1


Remix 테스트 개발 사이트

https://ethereum.github.io/browser-solidity/


메타마스크(브라우저 기반 이더리움 지갑)
https://metamask.io/

MIST(이더리움 개발하는 용으로 많이 쓰는 지갑)
https://github.com/ethereum/mist/releases

+ Recent posts