JDK8부터 Stream API와 람다식, 함수형 인터페이스 등을 지원하면서 Java를 이용해 함수형 프로그래밍을 할 수 있는 API들을 제공하고 있다. 그 중 Stream API는 데이터를 추상화하고, 처리하는데 자주 사용되는 함수들을 정의해두었다. (데이터 종류에 상관 없이 같은 방식으로 데이터 처리 가능)
String[] a = {"Jeong", "Kim", "Choi", "Seok"}
List<String> list = Arrays.asList(a);
// 별도의 Stream 생성
Stream<String> aStream = a.stream();
Stream<String> listStream = Arrays.stream(list);
// 복사된 데이터 정렬하여 출력
aStream.sorted().forEach(System.out::println);
listStream.sorted().forEach(System.out::println);
다음과 같이 Stream API를 통해 가독성을 높이고 코드의 라인 수도 줄일 수 있다.
List<String> list = listStream.sorted().colloct(Collections.toList());
listStream.sort().forEach(System.out::println);
// 스트림이 사용되어 닫힘
int count = listStream.count(); // -> IllegalStateException 발생
listStream.forEach(System.out::println);
Stream은 데이터를 처리하기 위해 다양한 연산들을 지원한다. Stream이 제공하는 연산을 이용하면 복잡합 작업들을 간단히 처리할 수 있는데, 스트림에 대한 연산은 크게 3가지 단계로 나뉜다.
생성하기
- Stream 객체를 생성하는 단계
- Stream은 재사용이 불가능하므로, 닫히면 다시 생성해주어야 한다.
Stream 연산을 하기 위해서는 먼저 Stream객체를 생성해줘야 한다. 배열, 컬렉션, 임의의 수, 파일 등 거의 모든 것을 가지고 스트림을 생성할 수 있다. 여기서 주의할 점은 연산이 끝나면 Stream이 닫히기 때문에, Stream이 닫혔을 경우 다시 Stream을 생성해야 한다.
가공하기
- 원본의 데이터를 별도의 데이터로 가공하기 위한 중간 연산
- 연산 결과를 Stream으로 다시 반환하기 때문에 연속해서 중간 연산을 이어갈 수 있다.
가공하기 단계는 원본의 데이터를 별도의 데이터로 가공하기 위한 중간 연산의 단계이다. 어떤 객체의 Stream을 원하는 형태로 처리할 수 있으며, 중간 연산의 반환값은 Stream이기 때문에 필요한 만큼 중간 연산을 연결하여 사용할 수 있다.
결과만들기
List<String> list = Arrays.asList("x1", "y1", "y2", "z1", "z2);
list.stream() // 생성하기
.filter(s -> s.startsWith("y")) // 가공하기
.map(String::toUpperCase) // 가공하기
.sorted() // 가공하기
.count(); // 결과만들기