[공부의흔적]_Buffer
자바에서 입력받을 때 Scanner 클래스로 입력을 받으며 사용했는데, 속도 측면에서 BufferedReader를 사용하면 훨씬 더 시간이 줄어듦.
BufferedReader : Scanner와 유사
BufferedWriter : System.out.println()과 유사
버퍼를 사용하지 않는 입력은 키보드의 키를 누르는 즉시 바로 프로그램에 전달.
버퍼를 사용하는 입력은 키보드의 입력이 있을 때마다 한 문자씩 버퍼로 전송. → 버퍼 가득 차거나 혹은 개행 문자가 나타나면 버퍼의 내용을 한 번에 프로그램에 전달.
버퍼를 거쳐 출력되는 것보다, 키보드 입력 받아 즉시 출력하는 것이 더 빠를 수 있다고 생각할 수 있음.
하드디스크는 속도가 느림. 그리고 외부장치(키보드, 마우스, 모니터 ...)와 데이터 입출력도 생각보다 시간이 오래 걸림.
그렇기 때문에 키보드의 입력이 있을 때마다 바로 이동시키는 것보다, 중간에 버퍼를 두어 한 번에 묶어 보내는 것이 더 효율적이고 빠른 방법.
쓰레기통도 쓰레기 하나씩 생길 때마다 버리는 것보다는 가득 찬 뒤 한 번에 버리는 것이 더 효율적이라고 생각하면 됨.
▶ Scanner
처음에 배웠던 것이 Scanner임.
Scanner는 띄어쓰기와 개행문자를 경계로 하여 입력 값을 인식하기 때문에 따로 가공할 필요가 없어 편리함.
가공할 필요가 없다는 뜻은, int형 변수를 받고자 하면 int x = scanner.nextInt()를 사용하여 바로 원하는 타입의 입력을 받을 수 있음.
Scanner는 BufferedReader와 다르게 지원해주는 메서드가 많고, 사용하기 쉽게 때문에 많이 사용하지만 버퍼 사이즈가 1024 char 이기 때문에 많은 입력을 필요로 할 경우에는 성능상 좋지 못한 결과를 불러옴.
▶ BufferedReader
Scanner와 달리 BufferedReader는 개행문자만 경계로 인식하고 입력받은 데이터가 String으로 고정됨.
그렇기 때문에 따로 데이터를 가공해야 하는 경우가 많음. 하지만 Scanner보다 속도가 확실히 빠름.
Scanner와 다르게 버퍼 사이즈가 8192 char(16, 384byte)이기 때문에 입력받을 때는 BufferedReader가 유리함.
▶ BufferedWriter
일반적으로 출력할 때 System.out.println()을 많이 사용함.
적은 양의 출력에서는 편리하고, 그렇게 큰 성능 차이 없이 사용 가능. 하지만 많은 양을 출력할 때는 입력과 동일하게 버퍼 사용하는 것이 좋음.
BufferedReader는 System.out.println()처럼 출력과 개행을 동시에 해주지 않기 때문에, 개행을 위해서는 따로 newLine(); / bw.write("\n")을 사용해야 함. 그리고 BufferedWritre의 경우 버퍼를 잡아 놓았기 때문에 반드시 사용 후에, flush() / close()를 해주어야 함.
close()를 하게되면, 출력 스트림을 아예 닫아버리므로 한 번 출력 후, 다른 것도 출력하고자 한다면 flush()를 사용하면 됨.
■ 특징
- 둘은 기존에 쓰던 Scanner와 System.out.println()보다 속도 측면에서 훨씬 빠름.
- 입력된 데이터가 바로 전달되지 않고 버퍼를 거쳐 전달되므로 데이터 처리 효율성이 높음.
- 많은 양의 데이터를 처리할 때 유리.
■ 단점
- BufferedReader는 Enter만 경계로 인식하고, 받은 데이터가 String으로 고정되기 때문에 입력받은 데이터를 가공하는 작업이 필요함.
■ 주요용어
- Buffer : 데이터를 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로 그 데이터를 보관하는 임시 메모리 영역. 입출력 속도 향상 위해 버퍼 사용.
- Buffer flush : 버퍼네 남아 있는 데이터를 출력시킴. (버퍼를 비우는 동작)
- BufferedReader : 버퍼를 이용한 입력.
- BufferedWriter : 버퍼를 이용한 출력.
▶ StringBuilder
알고리즘 문제를 풀다보면 BufferedReader, BufferedWriter만큼 StringBuilder도 많이 사용하는 것을 볼 수 있음.
우선 String과 StringBuilder의 차이를 간단히 알아보면, String은 불변 속성을 갖고, StringBuffer/StringBuilder는 그렇지 않다는 차이가 있음.
String이 불변성을 갖는다는 것은, concat이나 +연산을 통해 값을 변경하면 원래 기존의 String 메모리에서 값이 바뀌는 것이 아닌 기존의 String에 들어있던 값을 버리고 새로운 값을 재할당하게 됨.
처음에 할당한 String의 메모리 영역은 Garbage로 남아있다가 GarbageCollection에 의해 없어짐.
String은 불변성을 가지기 때문에 변하지 않는 문자열을 자주 읽어들이는 경우 사용하면 유리함.
하지만 문자열 추가, 삭제, 수정 등의 연산이 자주 일어나는 경우 String을 사용하면 힙 메모리에 많은 Garbage가 생성되고, 이는 힙 메모리 부족으로 이어져 프로그램의 성능에 영향을 미침.
이를 해결하기 위해 나온 것이 StringBuffer/StringBuilder임.
StringBuffer/StringBuilder는 가변성을 가지기 때문에 .append(), .delete()등 동일 객체 내에서 문자열을 변경하는 것이 가능.
그렇기 때문에 문자열의 추가, 수정 삭제가 빈번하게 발생할 경우 사용하는 것이 좋음.
① StringBuffer : 동기화를 지원하여 멀티쓰레드 환경에서 안전.
② StringBuilder : 동기화를 지원하지 않아 멀티쓰레드 환경에 적합하지 않음. 대신, 동기화를 지원하지 않기에 단일쓰레드에서는 StringBuffer보다 성능 뛰어남.
정리하면, StringBuilder는 문자열의 연산이 자주 일어나는 단일쓰레드 환경에서 사용하는 것이 유리.
■ 사용방법
1) importimport java io.*;로 입력해도 상관없음.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
2) 주의사항
입력은 readLine()을 활용하는데, 주의해야 할 점은
첫 번째, readLine()의 리턴값은 String이기 때문에 다른 타입으로 입력받으려면 형변환을 해줘야 함.
두 번째, 예외처리를 꼭 해줘야 함. readLine()을 할 때마다 try&catch를 활용해도 되지만, 대개 throws IOException를 통하여 작업함.
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
}
}
3) BufferedReader
- 데이터 라인 단위로 읽기 가능.
- Scanner처럼 공백 단위로 끊어주지 못하고, 엔터만 경계로 인식.
- return 값이 String으로 고정되기 때문에 String이 아닌 다른 타입으로 입력받으려면 형변환 해줘야 함.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine(); // String
int num1 = Integer.parseInt(br.readLine()); // int
// 공백구분방법1
/*
nextToken()을 사용하면 readLine()을 통해 입력받은 값을 공백단위로 구분하여 순서대로 호출
*/
StringTokenizer st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken()); // 첫 번째 호출
int b = Integer.parseInt(st.nextToken()); // 두 번째 호출
// 공백구분방법2
String[] array = str.split(""); // 공백마다 데이터 끊어서 배열에 입력.
br.close(); // 입출력이 끝난 후 닫기
}
}
4) BufferedWriter
- 한 번에 모았다가 출력 가능.
- 버퍼로 정의해줬기 때문에 반드시 flush() / close()를 호출해줘야 함.
- System.out.println()처럼 자동개행 기능이 없으므로 필요한 경우 \n을 통해 따로 입력.
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class Main {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String s = "Hello world"; // 출력할 문자 선언
bw.write(s); // 출력
bw.newLine(); // 줄바꿈 (출력해서 \n을 입력해도 상관없음.) = bw.write(s + "\n");
bw.flush(); // 남아있는 데이터 모두 출력
bw.close(); // 스트림 닫음
}
}
5) StringBuilder
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
String str1 = "프로그래밍 - ";
String java = "자바";
String android = "안드로이드";
String result = java + android;
str1 += java += android;
System.out.println(result);
System.out.println(str1);
}
}
실행결과
자바안드로이드
프로그래밍 - 자바안드로이드
위에 코드는 문자열이 1개 이상 있어서, 이것들을 더하는 간단한 방법을 보여준 예시.
하지만 이렇게 String 객체끼리 더하는 방법은 메모리 할당과 해제를 발생시키는데, 덧셈 연산이 많아지면 성능이 좋아지지 않음.
그래서 이러한 일들을 예방하고자 StringBuilder에 대해 아래에서 설명함.
String은 변경 불가능한 문자열을 생성하지만 StringBuilder는 변경 가능한 문자열을 만들어주므로, String을 합치는 작업 시 하나의 대안이 될 수 있음.
아래 코드를 보기.
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
StringBuilder sb = new StringBuilder();
sb.append("문자열 ").append("연결");
//String str = sb; // String에 sb를 그대로 넣는건 물가능.
String str = sb.toString();
// 결과 출력하면 str이랑 sb는 같은 값 출력.
System.out.println("str : " + str);
System.out.println("sb : " + sb);
}
}
실행결과
str : 문자열 연결
sb : 문자열 연결
import java.io.IOException;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) throws IOException {
StringBuilder sb = new StringBuilder();
// 배열도 가능
ArrayList<String> list = new ArrayList<>();
list.add("첫 번째, ");
list.add("두 번째, ");
list.add("세 번째, ");
list.add("네 번째, ");
list.add("다섯 번째");
for(int i = 0; i < list.size(); i++) {
sb.append(list.get(i));
}
System.out.println(sb);
}
}
실행결과
첫 번째, 두 번째, 세 번째, 네 번째, 다섯 번째
[출처] https://m.blog.naver.com/ka28/221850826909
[JAVA] BufferedReader 와 Bufferedwriter 사용법
BufferedReader :Scanner와 유사. Bufferedwriter :System.out.println();과 유사 둘은 모두 기존에 ...
blog.naver.com