Stream (1) - 기본적인 특징
업데이트:
Effective Java에서 배웠던 Stream을 정리한 포스트입니다.
Stream이란?
Java 8부터 지원하는 API로 컬렉션, 배열 등에 대해 요소 하나씩 반복적인 처리를 하도록 도와주는 기능. for문과 비슷하면서도 여러가지 다른 기능들이 있는데 하나 씩 차근차근 알아보도록 하겠습니다.
Stream의 특징
원본 데이터를 변경하지 않는다.
Stream은 원본 데이터를 변경하지 않습니다. 컬렉션, 배열 등의 요소를 읽어 특정 처리를 할 뿐 원본 컬렉션이나 배열을 변경하지 않습니다.
@Test
void Stream_테스트코드() {
List<Integer> integers = List.of(1, 2, 3, 4, 5);
Stream<Integer> intStream = integers.stream().map(i -> i + 1);
System.out.println(">>>>>>>>>> integers");
integers.stream().forEach(System.out::println);
System.out.println(">>>>>>>>>> intStream");
intStream.forEach(System.out::println);
}
위의 코드를 보면 integers
를 변환하는 map()
메소드를 사용하였지만 integers
를 그대로 있고, 반환된 intStream
만 변환되어 출력되는 것을 확인할 수 있습니다.
일회용이다.
이번에는 위의 코드에서 intStream
을 다시 한번 사용해보도록 하겠습니다.
System.out.println(">>>>>>>>>> intStream1");
intStream.forEach(System.out::println);
System.out.println(">>>>>>>>>> intStream2");
intStream.forEach(System.out::println);
그러면 다음과 같은 에러를 확인할 수 있습니다.
메시지에 적힌대로 stream은 이미 사용되었거나 닫혀 있다는 것을 확인할 수 있습니다.
즉, 재사용이 불가능 합니다.
Lazy 하다
먼저 Stream에는 중간 연산 메소드, 최종 연산 메소드가 있습니다.
중간 연산 메소드
- 반환 타입이 Stream
filter()
,map()
,flatMap()
등
최종 연산 메소드
- 반환 타입이 Stream이 아닌 다른 타입
findFirst()
,allMatch()
,collect()
,count()
등
여기서 “Lazy 하다”라는 것은 마지막에 어떤 연산을 필요로 하는 것인지를 보고 연산을 시작한다는 의미로 받아들이시면 됩니다.
사바라다님의 블로그에서 좋은 예시가 있어 차용했습니다.
[java] Java와 Lazy evaluation - Java8 Stream
문제는 다음과 같습니다.
1부터 10까지 숫자 중 2의 배수 3개만 추출할 것.
먼저 forEach
를 사용한 코드와 결과를 보겠습니다.
@Test
void lazy_테스트_for문() {
int count = 0;
List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> result = new ArrayList<>();
for (int i : list) {
System.out.println("i = " + i);
if (i % 2 == 0 && count++ < 3) {
result.add(i);
}
}
System.out.println("result = " + Arrays.toString(result.toArray()));
}
결과는 의도한 대로 2, 4, 6를 잘 반환했고, list
에 담긴 10개의 요소 모두 반복한 것으로 확인할 수 있습니다.
다음은 stream
을 이용한 코드와 결과를 보겠습니다.
@Test
void lazy_테스트_stream() {
List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> result = list.stream()
.filter(i -> {
System.out.println("i = " + i);
return i % 2 == 0;
})
.limit(3)
.collect(Collectors.toList());
System.out.println("result = " + Arrays.toString(result.toArray()));
}
결과는 위와 마찬가지로 2, 4, 6를 잘 반환했지만 다른 점이 있습니다. 바로 6까지만 반복했다는 사실인데요, Stream은 마지막에 limit(3)
을 보고 3개의 결과가 나오면 더 이상 연산을 하지 않는다고 판단하고 6까지만 반복했다는 사실을 알 수 있습니다.
마무리
이번 포스트에선 Java 8에 추가된 Stream의 기본적인 내용에 대해 알아보았습니다. 다음은 자주 쓰이는 메소드에 대해 알아보도록 하겠습니다.
오늘도 제 포스트를 봐주셔서 감사합니다.😀
댓글남기기