[Java] 표준입력 STDIN

Published: by Creative Commons Licence

참고 문서

System.in.read()

시스템으로부터 1바이트를 입력받아 정수형으로 반환한다. 한글은 1바이트로 표현할 수 없기 때문에 숫자와 영문, 특수문자만 입력할 수 있다.

int input = System.in.read(); // 1을 입력하면 케릭터 '1'의 아스키코드인 49가 저장됨.
System.out.println(input); // 49

char ch = (char) input; // 아스키코드 49가 '1'로 바뀜
System.out.println(ch); // '1'

System.in.read()를 사용하면서 주의할 점은 버퍼다. 콘솔에서 1을 입력했다고 해서 실제로 1만 입력되는 것이 아니라는 것:

1 + <LINE BREAK>

위처럼 <LINE BREAK>가 버퍼에 남아버려서 다음과 같은 현상이 발생한다:

// OS가 윈도우일 때
System.in.read(); //입력대기
System.in.read(); //\r
System.in.read(); //\n
System.in.read(); //입력대기

따라서 콘솔에서 연속으로 입력을 받아야 하는 경우엔 InputStream의 skip() 메서드를 활용한다:

System.in.read();
System.in.skip(2);
System.in.read();

BufferedReader

문자, 배열, 행을 버퍼에 담은 후 문자형 입력 스트림으로 텍스트를 읽어 들인다.

// read() : 1바이트를 읽어온다. 따라서 연속으로 사용하려면 버퍼초기화가 필요함.
// 이 함수는 System.in.read()와 작동 방식, 특징이 같음
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

br.read(); //입력대기
br.read(); //\r
br.read(); //\n
br.read(); //입력대기

BufferedReader 또한 버퍼를 염두에 두고 사용해야 한다. read() 메서드는 사용자로부터 입력받은 입력버퍼를 한 문자씩만 반환한다. 버퍼가 비어있으면 새로 요구하고, 버퍼가 남아있으면 요구없이 스스로 다음 문자를 반환한다. 아래 예시에서 3문자를 입력하면 read()를 다시 호출했을 때 입력값을 요청하는게 아닌 이미 입력된 문자(버퍼)에서 값을 가져온다.

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

System.out.println(br.read());
System.out.println(br.read());
System.out.println(br.read());

// 여기서 123을 입력하면
-> 49
-> 50
-> 51

readLine()을 사용하면 버퍼초기화를 고려하지 않아도 되서 속편하다:

System.out.println(br.readLine());  // 입력대기
System.out.println(br.readLine());  // 입력대기

Scanner

Scanner scan = new Scanner(System.in);
String str1 = scan.next();
String str2 = scan.next();
String str3 = scan.next();

// 여기서 a b c 를 입력하면
// 첫 번째 next()는 a를,
// 두 번째 next()는 b를,
// 세 번째 next()는 c를 읽어옴

Scanner.next()

입력된 값 중 첫 단어만 읽어오며 나머지는 버퍼에 저장

Scanner.nextLine()

문자열(한 줄)을 읽는다. BufferedReader의 readLine()과 동일하다.

nextInt(), nextDouble(), 등 숫자형 데이터를 처리하는 메서드는 문자열을 읽어 해당 데이터형으로 변환한다. next() 처럼 공백을 기준으로 첫 어절만 읽어오며 나머지는 버퍼로 처리한다.

숫자입력과 문자입력을 격리된 지역에서 각각 사용한다면 상관없지만 숫자입력 직 후 같은 지역 내에서 문자입력을 받는다면 버퍼문제가 발생한다.

앞서 말했듯이 next()의 파생형인 nextInt() 등의 메서드는 어절 단위로 읽어오기 때문인데 만약 다음처럼:

int number = scn.nextInt();  // 여기서 123을 입력했다 가정

일 경우엔 버퍼에 <엔터>가 남아있는 상태다.

여기서 다시:

String str = scn.nextLine();

처럼 작성하면 nextLine()은 콘솔 입력을 기다리는게 아니라 일단 버퍼에 있는 값을 가져오게 된다. 따라서 숫자형 입력을 받은 직후 다시 문자를 입력받아야 한다면 반드시 다음처럼 버퍼 초기화를 고려해야 한다:

int number = scn.nextInt();
scn.nextLine();   // 버퍼 초기화
String str = scn.nextLine();