자바로 알고리즘 풀이를 하던 와중 Scanner 외에도 BufferedReader를 알게 되었고, 효율성 및 시간 복잡도를 고려하게 되었다.
그렇다면 자바 입력과 출력은 어떤 상황에서 어떻게 써야할까?
우선 자바의 입출력부터 간단하게 알아보자.
입출력이란?
I/O란 Input과 Output의 약자로 입력과 출력, 간단히 줄여서 입출력이라고 한다. 입출력은 컴퓨터 내부 또는 외부의 장치와 프로그램 간의 데이터를 주고받는 것을 말한다.
자바의 모든 입출력은 스트림으로 이루어지는데, 스트림이란 데이터를 운반하는 데 사용되는 연결 통로이다. 스트림은 연속적인 데이터의 흐름을 물에 비유해 붙어진 이름인데, 흐르는 것처럼 단방향 통신만 가능하기 때문에 하나의 스트림으론 입력과 출력을 동시에 할 수 없다.
따라서, 입력 스트림과 출력 스트림이 각각 필요하며 데이터를 주고받을 때 큐(queue)와 같은 FIFO 구조로 되어있다고 생각하면 된다.
자바에는 수많은 입출력에 관한 스트림이 있지만, 그중 표준 입출력인 Scanner와 문자 기반의 보조 스트림인 BufferedReader에 대해서 자세히 알아보려고 한다.
입력
Scanner vs BufferedReader
// Scanner
Scanner scanner = new Scanner(System.in);
int a = scanner.nextInt();
Scanner의 특징
Scanner은 지원해주는 메서드가 많고 쉽기 때문에 자주 사용하게 된다. 예를 들면 정수 값으로 int, short, long 소수 값으론 float,double을 구분지어 읽을 수 있으며 String값도 읽을수 있다. 하지만 버퍼 사이즈가 1024이며 많은 작업을 요구할 땐 당연히 성능상 저하가 올 수 밖에 없다.
Scanner에 주요 메소드
메소드
|
설명
|
String next()
|
다음 토큰을 문자열로 리턴
|
byte nextByte()
|
다음 토큰을 byte 타입으로 리턴
|
short nextShort()
|
다음 토큰을 short 타입으로 리턴
|
int nextInt()
|
다음 토큰을 int 타입으로 리턴
|
long nextLong()
|
다음 토큰을 long 타입으로 리턴
|
float nextFloat()
|
다음 토큰을 float 타입으로 리턴
|
double nextDouble()
|
다음 토큰을 double 타입으로 리턴
|
String nextLine()
|
' \n '을 포함하는 한 라인을 읽고 ' \n '을 버린 나머지만 리턴
|
void close()
|
Scanner의 사용 종료
|
boolean hasNext()
|
현재 입력된 토큰이 있으면 true, 아니면 새로운 입력이 들어올 때까지 무한정 기다려서, 새로운 입력이 들어오면 그 때 true 리턴. ctrl + z 키가 입력되면 입력 끝이므로 false 리턴
|
BufferedReader의 특징
BufferedReader은 크기는 8KB로 즉, 긴 문자열이 포함된 파일을 읽을 시에는 BufferedReader을 추천하지만 내용이 짧을 경우 Scanner을 사용하는 것을 추천한다. 즉 여러 스레드 간에 Scanner은 공유할 수 없지만 BufferReader개체는 공유할 수 있다. 동기화를 사용하는 BufferedReader의 경우 싱글 스레드를 사용하는 Scanner보다 약간 느리다. 하지만 Scanner의 경우 정규식을 사용하여 값을 받으므로 이러한 속도 차이는 보상을 넘어 BufferedReader가 더 빠르게 문자열을 읽을 수 있게 된다. 하지만, BufferedReader은 오직 문자열 값만을 읽기 때문에 readLine() 함수만을 사용한다. 따라서 경계로 입력값을 Enter로만 받기 때문에 가공하는 작업이 필요할 수 있다.
// 문자기반 보조스트림 사용하기 위해 Import 해야 하는 명령어
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
BufferedReader 주요 메서드 및 특징
// BufferedReader
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); //버퍼리더 선언
String string = bufferedReader.readLine(); // 라인 단위로 입력받기
StringTokenizer stringTokenizer = new StringTokenizer(string);
// 토크나이져를 통해 파싱을 한다 지금은 띄어쓰기 단위로 잘라준다
// 혹은, String arr[] = str.split(" "); 으로 끊어서 받을 수도 있음
int a = Integer.parseInt(stringTokenizer.nextToken());
// readLine()시 리턴값이 String이므로 형변환이 필요함
※ 주의할 점
- readLine() 시 리턴 값을 String으로 고정되기에 String이 아닌 다른 타입으로 입력을 받으려면 형 변환을 꼭 해주어야 한다는 점이다.
- 예외처리를 꼭 해주어야한다는 점이다. readLine을 할 때마다 try & catch를 활용하여 예외처리를 해주어도 되지만 대개 throws IOException을 통하여 작업한다. (import java.io.IOException; or main 클래스 옆에 throws IOException작성)
- readLine() 함수로 경계를 구별하기 위해 두 가지 방법을 쓰는데, StringTokenizer에 nextToken() 함수를 쓰면 readLine()을 통해 입력받은 값을 공백 단위로 구분하여 순서대로 호출할 수 있다. 혹은 String.split()함수를 활용하여 배열에 공백단위로 끊어서 데이터를 넣고 사용하는 방식을 사용할 수 있다.
출력
Bufferedwriter
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); //할당된 버퍼에 값 넣어주기
String s = "abcdefg"; //출력할 문자열
bw.write(s+"\n"); //버퍼에 있는 값 전부 출력
bw.flush(); //남아있는 데이터를 모두 출력시킴
bw.close(); //스트림을 닫음
BufferedWriter의 경우 버퍼를 잡아놓았기 때문에 해제해주는 작업이 필요하다. flush() / close() 함수를 호출함으로써 처리해줄 수 있다. 또한 write()에는 println()과 같이 자동 개행 기능이 없기 때문에 개행이 필요한 경우 \n을 통해 해 주면 된다.
System.out.println()는 표준 출력에 평소에 많이 다뤄봤으므로 넘어가겠다.
StringTokenizer 메서드
BufferedReader로 읽을 때 StringTokenizer에 필요한 메서드를 알아보자.
메소드
|
설명
|
hasMoreTokens()
|
남아있는 토큰이 있으면 true 리턴, 아니면 false 리턴 (boolean)
|
nextToken()
|
객체에서 다음 토큰을 반환 (String)
|
nextElement()
|
nextToken 메서드와 동일하지만 문자열이 아닌 객체를 리턴 (Object)
|
countTokens()
|
총 토큰의 개수를 리턴 (int)
|
이를 토대로 백준 문제를 풀어본 후 확실히 이해해보자.
백준 15552번 빠른 A+B
https://www.acmicpc.net/problem/15552
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
int T = Integer.parseInt(br.readLine());
for(int i =0; i<T; i++)
{
st = new StringTokenizer(br.readLine());
bw.write((Integer.parseInt(st.nextToken()) + Integer.parseInt(st.nextToken())) + "\n");
}
bw.close();
}
}
출처: https://snupi.tistory.com/48 [SNUPI]
출처: https://friends-aihaja.tistory.com/entry/1-BufferReader-VS-Scanner-%EC%B0%A8%EC%9D%B4%EC%A0%90
'Language > Java' 카테고리의 다른 글
자바를 Job Uh!! - [열거 타입] (0) | 2022.01.04 |
---|---|
자바를 Job Uh!! - [다중 배열] (0) | 2022.01.03 |
자바를 Job Uh!! - [배열] (0) | 2022.01.03 |