함수형 프로그래밍에 기초한 패러다임 표현력, 속도, 병렬성을 얻을 수 있음
변환 단계별 함수는 순수함수여야 한다
- 순수함수
- 입력만이 결과에 영향을 주는 함수
- 다른 가변객체 참조 x
- 함수 안에서 다른 상태들 변경 x
public class Item46 {
public static void main(String[] args) {
Map<String, Long> freq = new HashMap<>();
try (Stream<String> words = new Scanner("file").tokens()) {
words.forEach(word -> freq.merge(word.toLowerCase(), 1L, Long::sum));
}
}
}
- 스트림 코드를 가장한 반복적 코드
- 길고, 읽기 어렵고, 유지보수 못함
- 스트림의
forEach
는 종단연산 중- 기능이 가장 적다
- 가장 덜 스트림답다
- 계산하는 데는 쓰지 말자!
- 사용처
- 스트림 계산 결과를 보고할 때
- (가끔) 스트림 계산 결과를 기존 컬렉션에 추가
toMap, toList, toSet 등...
public class Item46 {
List<String> topTen = freq.keySet().stream()
.sorted(comparing(freq::get).reversed())
.limit(10)
.collect(Collectors.toList());
}
comparing
: 키 추출 함수를 받는 비교자 생성 메서드freq::get
: 입력받은 단어를 빈도표에서 찾아 그 빈도를 반환- 이후 비교자(
comparing
) 를 역순으로 정렬
맵으로 반환
toMap(Object::toString, e -> e))
- 스트림 원소가 고유 키에 매핑
toMap(keyMapper, valueMapper, BinaryOperator<U>)
- 3번째 인수 : 병합 함수(
BinaryOperator(U)
) - 키와 연관 원소 중 하나를 골라 연관짓는 맵을 만들 떄 유용
public class Item46 {
Map<Artist, Album> topHits = albums.collect(
toMap(Album::aritst, a -> a, maxBy(comparing(Album::sales))));
}
- 앨범 스트림을 맵으로 반환
- 자신의 키 추출 함수로는 Album::artist를 사용
- key로 추출된 음악가와 그 음악가의 베스트 앨범을 짝지음
- U는 해당 맵의 값 타입
public class Item46 {
//toMap(keyMapper, valueMapper, (oldVal, newVal) ->newVal);
}
- 4번쨰 인수 : 맵 팩토리
- 키와 연관 원소 중 하나를 골라 연관짓는 맵을 만들 떄 유용
- 인수로 받은 비교자를 이용
- 스트림에서 값이 가장 작은 / 가장 큰 원소를 찾아 반환
- 인자 : 분류함수
- 분류함수 : 입력받는 원소가 속하는 카테고리 반환
- 반환값 : 원소들을 카테고리(해당 함수의 맵 키) 별로 모아둔 맵을 담은 수집기
Collectors.groupingBy(Product::getAmount)
-
비슷한 거로
partitionBy()
-
1번째 인수
분류함수(classifier)
: 입력하는 원소가 속한 카테고리 반환- 카테고리는 해당 원소의 맵키로 쓰임
- 2번째 인수
다운스트림 수집기(downstream collector)
: 해당 카테고리의 모든 원소를 담은 스트림 으로부터 값 생성toSet()
,toCollection()
,counting()
...
- 리스트 외의 값을 갖는 맵 생성
- 3번째 인수 :
맵 팩터리(mapFactory)
점층적 인수 목록 패턴
에 어긋남- 맵, 그안 컬렉션 타입 모두 지정 가능
counting
메서드가 반환하는 수집기는 다운스트림 수집기 전용collect(counting())
형태로 사용 xCollections
에는 이런 속성의 메서드가 16개나 더 있다.
- 원소들 연결시 구분문자를 삽입
- prefix, suffix 인수 추가 가능