티스토리 뷰
Java의 스트림은 왜 한 번만 읽을 수 있는가?
Java의 스트림이 한 번만 읽을 수 있는 이유는 스트림의 설계 방식과 데이터 처리 방법 때문이다. 스트림은 데이터를 한 방향으로 순차적으로 읽도록 설계되어 있으며, 한 번 읽은 데이터는 메모리에 저장되지 않기 때문에 다시 읽으려면 데이터를 재전송 받아야 한다. 이 방식은 스트림의 기본적인 동작 방식으로, 데이터를 처음부터 끝까지 한 번에 읽도록 설계되어 있다.
이유 1: 데이터 소비
스트림은 데이터를 한 번에 한 바이트씩 읽는다. 한 번 읽은 데이터는 소비되어 더 이상 스트림에 남아 있지 않게 된다. 이를 통해 메모리 사용을 최소화하면서 데이터를 처리할 수 있다.
이유 2: 메모리 효율성
스트림은 대량의 데이터를 메모리에 로드하지 않고 순차적으로 처리하기 때문에 메모리를 효율적으로 사용할 수 있다. 모든 데이터를 메모리에 저장하지 않기 때문에 한 번 읽은 데이터를 다시 읽을 수 없다.
이유 3: 설계 원칙
스트림의 설계 원칙은 단방향성과 비반복성을 기본으로 한다. 이는 스트림을 단순화하고, 메모리 사용을 최소화하며, 네트워크 스트림이나 파일 스트림과 같은 큰 데이터 소스를 효율적으로 처리할 수 있도록 한다.
스트림 관련 참고 자료
Java의 스트림에 대한 자세한 내용은 Java 공식 문서에서 확인할 수 있다. 공식 문서에서는 스트림의 동작 방식과 사용 방법에 대해 상세히 설명하고 있다. 예를 들어, InputStream 클래스의 javadoc을 보면 스트림의 기본적인 사용 방법과 제약 사항에 대해 자세히 설명하고 있다.
스트림을 여러 번 읽어야 할 때
만약 스트림을 여러 번 읽어야 하는 상황이라면, 데이터 복사나 버퍼링 기법을 사용할 수 있다. 예를 들어, InputStream을 ByteArrayOutputStream에 복사한 후, ByteArrayInputStream을 사용하여 여러 번 읽을 수 있다.
예제 코드
import java.io.*;
public class StreamExample {
public static void main(String[] args) throws IOException {
// 원래 InputStream (예: ServletInputStream)
InputStream originalInputStream = new ByteArrayInputStream("Hello, world!".getBytes());
// 스트림 데이터를 ByteArrayOutputStream으로 복사
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = originalInputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
}
// ByteArrayInputStream으로 변환하여 여러 번 읽기
ByteArrayInputStream copiedInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
// 첫 번째 읽기
System.out.println(readStream(copiedInputStream));
// 스트림을 다시 사용하려면 새로 생성
copiedInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
// 두 번째 읽기
System.out.println(readStream(copiedInputStream));
}
private static String readStream(InputStream inputStream) throws IOException {
StringBuilder result = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
return result.toString();
}
}
이 예제에서는 원래의 InputStream을 ByteArrayOutputStream으로 복사한 후, ByteArrayInputStream을 사용하여 스트림을 여러 번 읽는 방법을 보여준다. 이렇게 하면 스트림 데이터를 여러 번 읽을 수 있어 다양한 작업에 활용할 수 있다.
Java 8에서 추가된 Stream API
Java 8에서는 새로운 스트림 API가 추가되었다. 이 스트림 API는 컬렉션에 저장된 데이터를 처리할 때 유용하며, 스트림 파이프라인을 통해 데이터의 필터링, 매핑 등을 쉽게 할 수 있도록 도와준다. 하지만 이 스트림 또한 기본적으로 한 번만 소비할 수 있다.
스트림 API의 특징
- 한 번 소비: Java 8 스트림은 한 번만 소비할 수 있다. 스트림의 각 요소는 한 번 처리되며, 스트림을 다시 사용하려면 새로운 스트림을 생성해야 한다.
- 지연 연산: 스트림의 연산은 지연(Lazy)된다. 즉, 최종 연산(Terminal operation)이 호출되기 전까지는 중간 연산(Intermediate operation)이 실제로 수행되지 않는다.
- 함수형 프로그래밍 스타일: 스트림 API는 함수형 프로그래밍 스타일을 도입하여 코드의 가독성을 높이고, 병렬 처리를 쉽게 할 수 있도록 한다.
예제 코드
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamApiExample {
public static void main(String[] args) {
List<String> items = Arrays.asList("apple", "banana", "orange", "grape", "mango");
// 스트림 생성
Stream<String> stream = items.stream();
// 스트림 필터링 및 출력
stream.filter(item -> item.startsWith("a"))
.forEach(System.out::println);
// 스트림을 다시 사용하려면 새로운 스트림을 생성해야 함
stream = items.stream();
long count = stream.filter(item -> item.length() > 5).count();
System.out.println("Items with more than 5 characters: " + count);
}
}
이 예제에서는 Java 8의 스트림 API를 사용하여 리스트의 요소를 필터링하고 출력하는 방법을 보여준다. 스트림을 한 번 소비한 후에는 다시 사용할 수 없기 때문에 새로운 스트림을 생성해야 한다.
참고할 만한 공식 문서와 자료
- Total
- Today
- Yesterday
- 오라클
- mybatis
- Spring
- springboot
- Bash tab
- intellij
- Spring Security
- Github Status
- LocalDate
- k8s
- 베리 심플
- oracle
- window
- maven
- input
- svn
- mybatis config
- Mac
- docker
- Kotlin
- JavaScript
- config-location
- jQuery
- elasticsearch
- localtime
- Java
- rocky
- LocalDateTime
- Linux
- 북리뷰
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |