n 이하의 자연수를 소수와 비소수로 분류하기
public Map<Boolean, List<Integer>> partitionPrimes(int n) {
return IntStream.rangeClosed(2, n)
.boxed()
.collect(partitioningBy(candidate -> isPrime(candidate));
}
.boxed()
: returns a Stream consisting of the elements of this stream, each boxed to an Integer지금까지 발견된 소수 리스트에 접근해 이 값들로 나눠떨어지는지 확인해서 범위 좁히기
public static boolean isPrime(List<Integer> primes, int candidate) {
return primes.stream().noneMatch(i -> candidate % i == 0);
}
정렬된 리스트와 predicate을 인수로 받아 리스트의 첫 요소에서 시작해서 predicate을 만족하는 가장 긴 요소로 이루어진 리스트 반환하는 메서드 구현
public static boolean isPrime(List<Integer> primes, int candidate) {
int candidateRoot = (int) Math.sqrt((double) candidate);
return primes.stream()
.takeWhile(i -> i <= candidateRoot)
.noneMatch(i -> candidate % i == 0);
}
noneMatch
: 모든 요소들이 주어진 조건을 만족하지 않는지 Collector 인터페이스는 public interface Collector<T, A, R>
로 정의
T
: 스트림 요소의 형식A
: 중간 결과를 누적하는 객체의 형식R
: collect
연산의 최종 결과 형식예시)
public class PrimeNumbersCollector
implements Collector<Integer, Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>>
Collector
인터페이스에서 선언된 다섯 메서드 구현
supplier
메서드는 누적자를 만드는 함수 반환
true
, false
키와 빈 리스트로 초기화public Supplier<Map<Boolean, List<Integer>>> supplier() {
return () -> new HashMap<Boolean, List<Integer>>() {{
put(true, new ArrayList<Integer>());
put(false, new ArrayList<Integer>());
}};
}
accumulator
메서드는 스트림의 요소를 어떻게 수집할지 결정
public BiConsumer<Map<Boolean, List<Integer>> accumulator() {
return (Map<Boolean, List<Integer>> acc, Integer candidate) -> {
acc.get(isPrime(acc.get(true), candidate)) // isPrime의 결과에 따라 소수 리스트와 비소수 리스트 만들기
.add(candidate); // candidate를 알맞는 리스트에 추가
}
}
병렬 수집 과정에서 두 부분 누적자를 합칠 수 있는 메서드 만들기
예시) 두번째 맵의 소수 리스트와 비소수 리스트의 모든 수를 첫번째 맵에 추가하기만 하면됨
public BinaryOperator<Map<Boolean, List<Integer>>> combiner() {
return (Map<Boolean, List<Integer>> map1, Map<Boolean, List<Integer>> map2) -> {
map1.get(true).addAll(map2.get(true));
map1.get(false).addAll(map2.get(false));
return map1;
};
}
accumulator
의 형식은 컬렉터 결과 형식과 같으므로 변환 과정이 필요 없음
finisher
메서드는 항등 함수 identity
를 반환하도록 구현
public Function<Map<Boolean, List<Integer>>,
Map<Boolean, List<Integer>> finisher() {
return Function.identity();
}
Function.identity()
: returns a Function
that always returns its input argumentFunction
: functional interface커스텀 컬렉터는 IDENTITY_FINISH
이므로 다음과 같이 characteristics
메서드 구현
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH));
}
+) Characteristics
의 ENUM CONSTANTS
IDENTITY_FINISH
UNORDERD
: 컬렉션 연산이 요소 입력 순서를 유지하고자 하지 않음CONCURRENT
: 본 컬렉터는 병렬이다accumulator
메서드가 병렬적으로 호출되도 ok참고: