스트림
스트림 컬렉션 데이터를 처리하는 하나의 파이프라인
- SQL과 같이 반복문 없이 조건만으로 구현을 한다.
- 멀티코어를 활용한 컬렉션 요쇼 병렬처리
- 가독성이 좋아진다.
- filter, sorted, map, collect같은 여러 빌딩 블록 연산을 통해 파이프라인 구축이 가능하다.
- 데이터 처리 연산을 지원하도록 소스에서 추출된 연속 요소
- 연속된 요소: 컬렉션과 같은 연속된 데이터를 계산
- 소스: 제공받은 데이터들을 소비하며 데이터 소스의 순서를 유지한다.
- 데이터 처리 연산: 데이터베이스와 비슷한 연산을 가진다.
스트림 구조
- 파이프라이닝: 스트림 연산은 각 스트림 연산을 연결하여 파이프라인을 구성 가능
- 내부반복: 컬렉션과 달리 스트림은 내부 반복을 지원한다.
[스트림 vs 컬렉션]
- 가장 큰 차이 = 데이터를 언제 계산하느냐
- 컬렉션: 현재 자료구조가 표현하는 모든 값을 메모리에 저장
- 컬렉션의 모든 요소는 이미 계산된 후 추가된 것이다.
- 외부반복 ; 컬렉션은 직접 요소를 반복 (Ex, forEach)
- 스트림: 이론적으로 요청할 때만 요소를 계산, 스트림에 요소를 추가하거나 제거 불가
- 사용자가 요청한 값만 처리하여 추출
- 한번 사용하면 다시 사용 불가
- 내부반복: 내부 반복을 사용해서 반복구문을 생략한다.
[스트림 연산]
스트림에는 크게 중간 연산과 최종 연산이 존재한다.
1. 중간 연산 : 연결이 가능한 스트림 연산
중간 연산들은 또 다른 stream을 반환하여 연속된 파이프라인을 연결할 수있게 만든다. (Lazy: 실행하기 전까지 아무 연산도 하지 않는다.)
Lazy를 통해 얻을 수 있는 효과
- Loop fusion : 서로 다른 연산이어도 하나의 과정으로 병합
- Loop funsion으로 여러 조건에 의해 사전에 중단되는 쇼트서킷이 존재하여 최적화를 할 수 있다.
2. 최종 연산 : 스트림을 닫는 연산
여러 스트림을 통해 완성된 파이프라인을 닫는 역할을 한다.
[연산의 종류]
연산 | 형식 | 반환 형식 | 연산의 인수 | 함수 디스크립터 |
filter | 중간 연산 | Stream<T> | Predicate<T> | T -> boolean |
map | 중간 연산 | Stream<R> | Function<T,R> | T->R |
limit | 중간 연산 | Stream<T> | ||
sorted | 중간 연산 | Stream<T> | Comparator<T> | <T, T> -> int |
distinct | 중간 연산 | |||
연산 | 형식 | 반환 형식 | 목적 | |
forEach | 최종 연산 | void | 스트림의 각 요소를 소비하면서 람다를 적용 | |
count | 최종 연산 | long | 스트림의 요소를 1로 하여 모든 값을 합 | |
collect | 최종 연산 | 스트림을 reduce하여 컬렉션을 만든다. |
List<Dish> dishes = new ArrayList<>();
for (Dish dish: menu) {
if (dish.getCategories() < 400) {
dishes.add(dish);
}
}
dishes.sort(new Comparator<>(){
@Override
public int compare(Dish o1, Dish o2) {
return Integer.compare(o1.getCategories(), o2.getCategories());
}
});
// dishes.sort(Comparator.comparing(Dish::getCategories));
// dishes.sort((o1,o2)-> Integer.compare(o1.getCategories(),o2.getCategories()) );
List<String> getNames = new ArrayList<>();
int count = 0;
for (Dish dish: dishes) {
getNames.add(dish.getName());
if (++count == 3) {
break;
}
}
위의 예제를 보면
카테고리가 400 미만인 값을 정렬하여 이름을 3개만 가져온다 했을때를 나타냈습니다.
이렇게 되면 메서드 참조로 더 짧게 만들 수 있지만 그래도 가독성이 떨어지는 것은 사실입니다.
이를 만약 스트림을 사용하게 된다면
List<String> streamName = menu.stream()
.filter(dish -> dish.getCategories() < 400)
.sorted(Comparator.comparing(Dish::getCategories))
.limit(3)
.map(Dish::getName)
.collect(Collectors.toList());
와 같이 중간 연산인 filter, sorted, limit, map을 사용하여 파이프라인을 구축했고 이를 컬렉션으로 추출하기 위해 collect를 사용했습니다. 이를 통해 더 나은 가독성을 제공한는 것을 볼 수 있습니다.
'JAVA > Java in action' 카테고리의 다른 글
[자바 인 액션] 6. 스트림 데이터 수집 (0) | 2023.03.23 |
---|---|
[자바 인 액션] 5. 스트림 활용 (0) | 2023.03.23 |
[자바 인 액션] 3. 람다 표현식 (0) | 2023.03.23 |
[자바 인 액션] 2. 동작 파라미터화 (0) | 2023.03.22 |
[자바 인 액션] 1. 자바의 변화 (0) | 2023.03.22 |