Stream API는 JDK8 버전부터 람다(Lambda)와 함께 제공되기 시작한 기능입니다.
Stream API에 대해 간략히 설명하자면 데이터를 추상화하고,
데이터를 처리하는데 자주 사용되는 함수들을 미리 정의해놓은 API라고 할 수 있을 것 같습니다.
Stream API는 람다식과 함께 활용하여 저장된 요소들을 반복적으로 처리할 수 있습니다.
Stream을 사용할 시 멀티 스레드 환경과 동기화를 신경쓰지 않고도 데이터를 병렬로 처리할 수 있기 때문에 기존에 반복문을 통해 처리하던 방식보다 편리하고 빠르게 대량의 데이터를 처리할 수 있습니다.
기존에는 Java를 활용할 때 객체지향이라는 개념에 중점을 두었기에 함수형 인터페이스인 람다식을 사용하는 것이 조금 헷갈릴수도 있지만 Stream API를 활용하면 코드의 가독성을 높이고 효율적으로 코딩이 가능합니다.
이 Stream에는 대표적인 몇가지 특징이 있습니다.
예시를 들어 보겠습니다.
// 배열 선언
Integer[] temp = {1,2,3,4};
// 배열을 스트림으로 변환
Stream<Integer> stream = Arrays.stream(temp);
// 스트림을 활용한 프린트
stream.forEach(System.out::println);
결과
1
2
3
4
Integer 배열을 stream으로 변환하고 반복적으로 출력하는 명령을 수행합니다.
System.out과 println사이의 ::은 왼쪽 클래스의 오른쪽 이름을 가진 메소드를 수행한다는 의미입니다.
결과로 1, 2, 3, 4가 순서대로 출력되는 것을 확인할 수 있습니다.
stream은 필요할때 호출해서 forEach, filter, map등의 연산을 필요한 그 순간에 호출해서 사용하면 됩니다.
또한 컬렉션타입을 stream으로 변경해 새로운 객체를 만들어 연산을 수행하기 때문에, 원본 데이터를 변경하지 않습니다.
그런데 재사용이 불가능하다는 것은 무슨의미일까요?
stream.forEach(System.out::println)을 다시한번 사용해보겠습니다.
위의 stream을 객체로 선언했기 때문에 다시한번 사용이 가능합니다.
// 배열 선언
Integer[] temp = {1,2,3,4};
// 배열을 스트림으로 변환
Stream<Integer> stream = Arrays.stream(temp);
// 스트림을 활용한 프린트
stream.forEach(System.out::println);
// 스트림을 재사용
stream.forEach(System.out::println);
결과
1
2
3
4
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
at java.base/java.util.stream.AbstractPipeline.sourceStageSpliterator(AbstractPipeline.java:279)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
at 연습.Stream2.main(Stream2.java:35)
정상적으로 선언된 stream 객체를 다시 사용하는 것이므로 컴파일은 잘 진행됩니다.
하지만 stream을 재사용 했을 때 IllegalStateException이 발생하는 것을 확인할 수 있습니다.
stream은 오직 한번만 사용할 수 있기 때문에, 객체로 선언했다고 해서 stream을 다시 사용하면 오류가 발생합니다.