Stream이란 무엇인가?
Java 8에 새로 추가된 기능으로 스트림을 사용하면 선언형으로 Collection 데이터들을 처리 할 수 있다.
예를 들어 칼로리가 400 미만인 요리들을 정렬해 Collection에 저장한다고 가정을 했을 때 스트림을 사용하지 않으면 다음과 같이 구현할 수 있다.
List<Dish> lowCaloricDishes = new ArrayList<>();
for(Dish dish : menu) {
if (dish.getCalories() < 400){
lowCaloricDishes.add(dish);
}
}
Collections.sort(lowCaloricDishes, new Comparator<Dish>(){
public int compare(Dish dish1, Dish dish2){
return Integer.compare(dish1.getCalories(), dish2.getCalories());
}
}
스트림을 사용하면 다음과 같이 구현할 수 있다.
List<String> lowCaloricDishes =
menu.stream()
.filter(d -> d.getCalories() < 400)
.sorted(campring(Dishes::getCalories))
.collect(toList());
스트림 API의 특징은 다음과 같다.
- 선언형 : 더욱 간결하고 가독성이 좋아진다.
- 조립할 수 있음 : 유연성이 좋아진다.
- 병렬성 : 성능이 좋아진다.
Stream의 특징
1. 딱 한번만 탐색할 수 있다.
탐색된 스트림의 요소는 소비되므로, 반복자와 마찬가지로 스트림도 단 한번만 탐색 가능하다.
반복자와 마찬가지로 한번 탐색된 요소를 다시 탐색하려면 초기 데이터 소스에서 새로운 스트림을 만들어야 한다.
2. 내부 반복
Collection 인터페이스를 사용 할 때 사용자가 직접 요소를 반복하는 경우를 외부 반복이라 하며, 반복을 알아서 처리하고, 결과 스트림 값을 어딘가에 저장해 주는 경우를 내부 반복이라고 한다. Stream API는 내부 반복을 지원한다.
외부 반복 예시
List<String> names = new ArrayList<>();
for(Dish dish : menu) {
names.add(dish.getName()); // 사용자가 직접 추가해 주어야 한다.
}
내부 반복 예시
List<String> names = menu.stream()
.map(Dish::getName)
.collect(toList());
Stream 라이브러리의 경우 내부 반복은 데이터 표현과 하드웨어를 활용한 병렬성 구현을 자동으로 선택하기 때문에 병렬성을 따로 관리할 필요가 없다.
Stream 연산
연결할 수 있는 스트림 연산을 중간 연산이라고 하며, 스트림을 닫는 연산을 최종 연산이라고 한다.
중간 연산
중간 연산은 다른 스트림을 반환한다. 그렇기 때문에 여러 중간 연산을 연결해 질의를 만들 수 있다.
중간 연산은 게으르다. 다시 말해 단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다.
연산 | 형식 | 반환형식 | 연산의 인수 | 함수 디스크립터 |
filter | 중간 연산 | Stream<T> | Predicate<T> | T -> boolean |
map | 중간 연산 | Stream<T> | Function<T, R> | T -> R |
limit | 중간 연산 | Stream<T> | ||
sorted | 중간 연산 | Stream<T> | Comparator<T> | (T, T) -> int |
distinct | 중간 연산 | Stream<T> |
최종 연산
최종 연산은 스트림 파이프라인에서 결과를 도출한다. 보통 최종 연산에 의해 List, Integer, void등 스트림 이외의 결과가 반환된다.
연산 | 형식 | 반환 형식 | 목적 |
forEach | 최종 연산 | void | 스트림의 각 요소를 소비하며 람다를 적용 |
count | 최종 연산 | long(generic) | 스트림의 요소 개수를 반환 |
collect | 최종 연산 | 스트림을 reduce해 리스트, 맵, 정수 형식의 컬렉션 생성 |
'Java' 카테고리의 다른 글
[Java] Optional (0) | 2024.01.26 |
---|---|
[Java] 인터페이스 default method, static method (0) | 2024.01.18 |
[Java] 함수형 인터페이스, 람다, 메소드 레퍼런스에 대하여 (1) | 2024.01.15 |
[Java] Enum 전용 Map, Set이 있다? (0) | 2023.06.20 |
[Java] final 키워드 그리고 effectively final (0) | 2023.06.13 |