class Example1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter a line:");
String line = sc.nextLine();
System.out.println("You entered: " + line);
}
}
// 입력: Hello world! How are you?
// 출력: You entered: Hello world! How are you?
class Example2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter a word:");
String word = sc.next();
System.out.println("You entered: " + word);
}
}
// 입력: Hello world!
// 출력: You entered: Hello
nextLine()은 공백(스페이스)과 탭 등 모든 문자를 포함해서 한 줄 전체를 읽으며 사용자가 엔터키를 눌러 줄바꿈이 발생할 때까지의 모든 입력을 처리한다. 그러나 next_()는 공백(스페이스, 탭, 줄바꿈)을 기준으로 하나의 단어를 입력받는다.
hasNext()
hasNext()는 Scanner가 입력 스트림에 다음으로 읽을 토큰이 있을 때 true를 반환한다. 만약 입력 스트림에 더 이상 토큰이 없으면 false를 반환한다. 즉, 입력되는 토큰의 갯수가 확실하지 않은 경우 사용하면 좋을 것 같다.
class Example3 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
do {
System.out.println("a값을 입력해주세요.");
int a = sc.nextInt();
System.out.println("b값을 입력해주세요.");
int b = sc.nextInt();
System.out.println("두 값의 합: " + (a + b));
} while (sc.hasNextInt());
}
}
이때 Scanner.class는 위와 같이 다양한 메서드를 제공하면서 간단하게 입력값들을 처리할 수 있도록 도와주지만 토큰을 하나씩 직접 처리해줘야하해서 토큰의 갯수가 많아질 수록 효율이 떨어질 것 같고 성능도 더 안좋아지긴 할 것이다. 그래서 적절히 입력값이 간단하고 짧은 경우에 적합한 것 같다.
BufferedReader
Scanner에 비해 대량의 데이터를 빠르게 읽어오는 데 유리
"마치 큰 통에 음식을 가득 담아 한 번에 가져오는 것과 같아요. 예를 들어, 뷔페에서 접시를 가득 채워 한 번에 많이 가져오는 거예요. 이렇게 하면 여러 번 왔다 갔다 하지 않아도 되니까 훨씬 빠르게 음식을 먹을 수 있겠죠?" ➜ 타 블로그에서 들고온 말인데 가장 잘 설명한 것 같다.
데이터를 한번에 버퍼(메모리)라는 저장 공간에 저장하고 그 데이터를 꺼내 쓰는 것이다.
https://www.acmicpc.net/blog/view/56 여기 입력 속도 비교해놓은 블로그가 있는데 Java Scanner는 평균 4.8448초 Java BufferedReader, Integer.parseInt 평균 0.6585초 로 확연하게 BufferdReader가 빠른 것을 확인할 수 있다. 입력 처리 속도
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int a = Integer.parseInt(br.readLine());
주로 한줄 씩 입력 받기 위해 위와 같이 readLine() 메소드를 활용한다.
그러나 이때 정수와 같은 특정 데이터 형식을 직접적으로 읽는 메서드를 제공하지 않아 데이터를 읽어온 후, 문자열을 형변환해서 사용해야한다.
StringTokenizer
문자열을 특정 구분자(기본적으로 공백)로 분리하여 빠르게 처리할 수 있게 해주는 클래스로 여러 개의 숫자나 문자열이 공백으로 구분된 입력을 처리할 때 유용하다. 입력된 문자열을 토큰(token) 단위로 나누어 각 토큰을 순차적으로 처리할 수 있다.
그래서 공백으로 구분된 여러 값을 입력받아야 하는 경우 BufferedReader와 StringTokenizer를 함께 사용하면 효율적이다.(BufferedReader로 한 줄의 입력을 읽고, StringTokenizer를 사용해 공백을 기준으로 값을 나눈 후, 필요한 형식으로 변환)
// Only BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] inputs = br.readLine().split(" ");
int a = Integer.parseInt(inputs[0]);
int b = Integer.parseInt(inputs[1]);
int c = Integer.parseInt(inputs[2]);
// StringTokenizer
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
성능 면에서는 StringTokenizer가 약간 더 유리하다고 한다.
마지막으로 출력을 위한 클래스도 알아보겠다.
BufferedWriter
대량의 데이터를 출력해야 할 때, System.out.println()보다 성능상 이점이 있어, 효율적인 출력이 필요할 때 사용
파라미터로 char 값이나 String을 받을 수 있고 숫자를 출력하려면 String.valueOf()로 변환해야한다.
bw.flush()로 버퍼에 저장된 데이터를 비우고 해당 데이터를 출력하며 bw.close()로 스트림을 닫는다.
StringBuilder
문자열을 효율적으로 조작하기 위해 제공되는 클래스
내부 Buffer에 문자열 저장, buffer에서 추가, 수정, 삭제 append(String str): 문자열을 끝에 추가합니다. 다양한 자료형(문자, 정수 등)을 추가 insert(int offset, String str): 지정한 위치에 문자열을 삽입 delete(int start, int end): 지정한 범위의 문자열을 삭제 reverse(): 문자열의 순서를 뒤집기 toString(): StringBuilder 객체를 String 객체로 변환 subString(int start, int end): 지정한 범위의 문자열을 추출
public class Main {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
// 문자열 추가
sb.append("Hello");
sb.append(" ");
sb.append("World!");
// 특정 위치에 문자열 삽입
sb.insert(5, ",");
// 문자열을 뒤집기
sb.reverse();
// String으로 변환하여 출력
System.out.println(sb.toString());
}
}