정규 축소는 int, double 등과 같은 두 개의 불변 값 을 결합 하여 새로운 값을 생성하는 것을 의미합니다 . 그것은이다 불변의 감소. 반대로 collect 메소드는 컨테이너 를 변경 하여 생성해야하는 결과를 축적 하도록 설계되었습니다 .
문제를 설명하기 위해 다음 Collectors.toList()
과 같은 간단한 축소를 사용하여 달성한다고 가정 해 봅시다.
List<Integer> numbers = stream.reduce(
new ArrayList<Integer>(),
(List<Integer> l, Integer e) -> {
l.add(e);
return l;
},
(List<Integer> l1, List<Integer> l2) -> {
l1.addAll(l2);
return l1;
});
이는에 해당합니다 Collectors.toList()
. 그러나이 경우 List<Integer>
. 우리 ArrayList
는 스레드 안전하지 않으며 반복하는 동안 값을 추가 / 제거해도 안전하지 않으므로 ArrayIndexOutOfBoundsException
목록이나 결합기를 업데이트 할 때 동시 예외 또는 모든 종류의 예외 (특히 병렬로 실행될 때) 를 얻습니다. 정수를 누적 (추가)하여 목록을 변경하기 때문에 목록을 병합하려고합니다. 이 스레드를 안전하게하려면 성능을 저하시킬 때마다 새 목록을 전달해야합니다.
대조적으로, Collectors.toList()
비슷한 방식으로 작동합니다. 그러나 값을 목록에 누적 할 때 스레드 안전성을 보장합니다. 방법에 대한 설명서에서collect
:
수집기를 사용하여이 스트림의 요소에 대해 변경 가능한 축소 작업을 수행합니다. 스트림이 병렬이고 수집기가 동시이고 스트림이 정렬되지 않았거나 수집기가 정렬되지 않은 경우 동시 축소가 수행됩니다. 병렬로 실행될 때, 가변 데이터 구조의 격리를 유지하기 위해 다수의 중간 결과가 인스턴스화되고, 채워지고, 병합 될 수있다. 따라서 스레드로부터 안전하지 않은 데이터 구조 (예 : ArrayList)와 병렬로 실행될 때에도 병렬 감소를 위해 추가 동기화가 필요하지 않습니다.
따라서 귀하의 질문에 대답하십시오 :
언제 collect()
vs 를 사용 reduce()
하시겠습니까?
당신과 같은 불변 값이있는 경우 ints
, doubles
, Strings
다음 정상 감소는 잘 작동합니다. 그러나 reduce
값에 List
(변경 가능한 데이터 구조) 를 말해야하는 경우 collect
메소드 와 함께 변경 가능한 축소를 사용해야합니다 .