Java 8 스트림 - 수집과 감소
제사 when when? when when를 사용하시겠습니까?collect()
»reduce()
어느 쪽으로 가는 것이 확실히 좋은지, 구체적인 예를 든 사람이 있습니까?
Javadoc에서는 collect()는 가변적인 축소라고 합니다.
이것은 가변적인 삭감이기 때문에, (내부) 동기화가 필요하게 되어, 결과적으로 퍼포먼스에 악영향을 미칠 가능성이 있다고 생각합니다. ★★★★★★★★★★★★★★★★★.reduce()
비용 절감의 모든 단계를 거친 후 반환을 위한 새로운 데이터 구조를 생성해야 하므로 병렬화가 더욱 용이합니다.
그러나 위의 진술들은 추측일 뿐이며, 나는 여기에 전문가가 참여하기를 바란다.
reduce
는 "폴드" 연산자이며 스트림 내의 각 요소에 바이너리 연산자를 적용합니다.오퍼레이터에 대한 첫 번째 인수는 이전 응용 프로그램의 반환값이고 두 번째 인수는 현재 스트림 요소입니다.
collect
는, 「수집」이 작성되어 각 요소가 그 수집에 「추가」되는 집약 조작입니다.그런 다음 스트림의 다른 부분에 있는 컬렉션이 함께 추가됩니다.
링크한 문서에는 두 가지 접근 방식이 있는 이유가 나와 있습니다.
스트링 스트림을 1개의 긴 스트링으로 연결하려면 , 통상의 삭감으로 이것을 실현할 수 있습니다.
String concatenated = strings.reduce("", String::concat)
우리는 원하는 결과를 얻을 수 있고, 심지어 병행해서 작동할 수도 있습니다.하지만, 우리는 그 공연이 행복하지 않을 수도 있어요!이러한 실장에서는 대량의 문자열 복사가 이루어지며, 실행 시간은 문자 수에서 O(n^2)가 됩니다.보다 퍼포먼스 높은 접근방식은 결과를 String Builder에 축적하는 것입니다.String Builder는 문자열 축적을 위한 가변 컨테이너입니다.일반적인 감소와 같은 기술을 사용하여 가변 감소를 병렬화할 수 있습니다.
, 는 두 동일하지만 이 병렬화는 동일하다는 입니다.reduce
스트림 요소 자체에 기능을 적용하는 경우.그 에서에서collect
우리는 변할 수 있는 보관 용기로 기능을 적용한 사례.변이 가능한 용기에 기능을 적용할 경우.
이유는 간단합니다.
collect()
는 변경 가능한 결과 개체에서만 사용할 수 있습니다.reduce()
는 불변의 결과 객체와 연동하도록 설계되어 있습니다.
reduce()
로immutable" example불변의 예를 들어
public class Employee {
private Integer salary;
public Employee(String aSalary){
this.salary = new Integer(aSalary);
}
public Integer getSalary(){
return this.salary;
}
}
@Test
public void testReduceWithImmutable(){
List<Employee> list = new LinkedList<>();
list.add(new Employee("1"));
list.add(new Employee("2"));
list.add(new Employee("3"));
Integer sum = list
.stream()
.map(Employee::getSalary)
.reduce(0, (Integer a, Integer b) -> Integer.sum(a, b));
assertEquals(Integer.valueOf(6), sum);
}
collect()
mutable"example변이 가능한"예제를 사용하여와
예:만약 수동으로 합 예를 들어를 사용하여 계산하고 싶다음을 사용하여 합계를 수동으로 계산하려는 경우.collect()
그것은와는 통하지 않는다를 못한다.BigDecimal
하지만 단만이 있어야만MutableInt
부터에서org.apache.commons.lang.mutable
예를들면.예를들면.:참조:
public class Employee {
private MutableInt salary;
public Employee(String aSalary){
this.salary = new MutableInt(aSalary);
}
public MutableInt getSalary(){
return this.salary;
}
}
@Test
public void testCollectWithMutable(){
List<Employee> list = new LinkedList<>();
list.add(new Employee("1"));
list.add(new Employee("2"));
MutableInt sum = list.stream().collect(
MutableInt::new,
(MutableInt container, Employee employee) ->
container.add(employee.getSalary().intValue())
,
MutableInt::add);
assertEquals(new MutableInt(3), sum);
}
이는 축전지가 container.add(employee.getSalary().intValue());
그 결과에 있지만 이변 결과를 포함한의 상태를 변화시키려 새로운 개체가 반환 새 개체를 반환하는 것이 아니라 변수 상태를 변경하도록 되어 있습니다로 되어 있지 않은가.container
입입 of MutableInt
.
「 」를 는, 「 」를 해 주세요.BigDecimal
신 the를 container
하실 수 .collect()
method method method methodcontainer.add(employee.getSalary());
에는 변화가 .container
BigDecimal
이와는 별도로)BigDecimal::new
would would BigDecimal
컨스트럭터가 ).
통상적인 감소는 int, double 등 2개의 불변의 값을 조합하여 새로운 값을 생성하는 것을 의미합니다.불변의 감소입니다.이와는 대조적으로, 수집 방법은 용기를 변이시켜 생산해야 할 결과를 축적하도록 설계되어 있습니다.
문제를하기 위해서 이 성취하고 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;
});
은 것은은 this this this this this this this this this에 해당합니다.Collectors.toList()
이 는, 「」, 「」를 List<Integer>
있는 것처럼ArrayList
, 그렇게 자신 또는 는 스레드 세이프가 아니며 반복 중에 값을 추가/삭제하는 것도 안전하지 않으므로 동시에 예외가 발생합니다 동시 예외 가는 반면 반복하는 데 사용하는 것에서 값 add/remove기에 안전한 스레드로부터 안전하지 않은가.ArrayIndexOutOfBoundsException
왜냐하면(추가)에 정수하기도 하여 1위 변종이 된 아니면 예외(특히 병렬로 실행)의 목록 또는 콤바이너 업데이트 어떤 종류 목록이 합병하려고 한다.또는목록을 갱신할 때, 또는 목록에 정수를 누적하여 목록을 변환하기 때문에 결합기가 목록을 병합하려고 할 때(특히 병렬로 실행되는 경우)모든 종류의 예외도 마찬가지입니다.만약 당신이 이 스레드로부터 안전하게 하고 싶다면 성능에 짐이 될 것 매번 새 목록을 통과시켜야 한다.이 스레드를 안전하게 만들려면 성능을 저하시킬 때마다 새 목록을 전달해야 합니다.
에 반해, 「 」는Collectors.toList()
비슷한 방식으로 작동합니다.그러나 값을 목록에 누적하면 스레드의 안전성이 보장됩니다.메서드의 매뉴얼에서 다음 내용을 참조해 주십시오.
Collector를 사용하여 이 스트림의 요소에 대해 가변 축소 작업을 수행합니다.스트림이 병렬이고 Collector가 동시이고 스트림이 비순서이거나 수집기가 비순서일 경우 동시 감소가 수행됩니다.병렬로 실행되면 여러 중간 결과를 인스턴스화, 입력 및 병합하여 가변 데이터 구조의 분리를 유지할 수 있습니다.따라서 스레드 세이프 이외의 데이터 구조(ArrayList 등)와 병렬로 실행해도 병렬 감소를 위해 추가 동기화가 필요하지 않습니다.
질문에 답하려면:
제사 when when? when when를 사용하시겠습니까?
collect()
»reduce()
의 ints
,doubles
,Strings
정상적인 감소는 잘 작동합니다. 꼭 하는 는, 「」를 참조해 주세요.reduce
을 A라고 .List
( 구조) (변동 데이터 구조)와 ( 구조)를 함께 collect
★★★★★★ 。
스트림을 <- b <- c <- d 로 합니다.
그 결과,
(a # b) # c) # d 가 됩니다.
여기서 #는 당신이 하고 싶은 흥미로운 작업입니다.
컬렉션에서는
수집가에게 일종의 수집 구조 K가 있을 겁니다
K는 a를 소비한다.K는 b를 소비한다.K는 c를 소비한다.K는 d를 소비한다.
마지막으로 K에게 최종 결과가 무엇인지 물어보세요.
그리고 K는 당신에게 그것을 줍니다.
실행 시 메모리 사용 가능 공간이 크게 다릅니다.하는 동안에collect()
모든 데이터를 수집하여 수집에 넣습니다.reduce()
그럼 스트림을 통과한 데이터를 줄이는 방법을 지정하도록 명시적으로 요구됩니다.
예를 들어 파일에서 일부 데이터를 읽고 처리한 후 데이터베이스에 저장하려는 경우 다음과 같은 Java 스트림 코드가 표시될 수 있습니다.
streamDataFromFile(file)
.map(data -> processData(data))
.map(result -> database.save(result))
.collect(Collectors.toList());
는 이를 사용합니다.collect()
Java가 데이터를 강제로 스트리밍하고 결과를 데이터베이스에 저장하도록 합니다.collect()
데이터는 읽거나 저장되지 않습니다.
을 생성합니다.java.lang.OutOfMemoryError: Java heap space
파일 크기가 충분히 크거나 힙 크기가 충분히 낮으면 런타임 오류입니다.분명한 이유는 스트림을 통과한 모든 데이터(실제로 이미 데이터베이스에 저장되어 있는 데이터)를 결과 컬렉션에 스택하려고 하고 이로 인해 힙이 폭발하기 때문입니다.
를 하면, 「」가 됩니다.collect()
reduce()
에 더 가 되지 -- 자자그그그그 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 。
이 예에서는 그냥 치환합니다.collect()
을 가지고reduce
:
.reduce(0L, (aLong, result) -> aLong, (aLong1, aLong2) -> aLong1);
은 굳이 쓸 .result
Java는 순수 FP(기능 프로그래밍) 언어가 아니기 때문에 잠재적인 부작용으로 인해 스트림 하단에서 사용되지 않는 데이터를 최적화할 수 없습니다.
다음은 코드 예시입니다.
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
int sum = list.stream().reduce((x,y) -> {
System.out.println(String.format("x=%d,y=%d",x,y));
return (x + y);
}).get();
System.out.println(sum);
실행 결과는 다음과 같습니다.
x=1,y=2
x=3,y=3
x=6,y=4
x=10,y=5
x=15,y=6
x=21,y=7
28
함수 핸들 2개의 파라미터를 줄입니다.첫 번째 파라미터는 스트림 내의 이전 반환값, 두 번째 파라미터는 스트림 내의 현재 계산값, 첫 번째 값과 현재 값을 다음 caculation의 첫 번째 값으로 합산합니다.
reducing() 컬렉터는 groupingBy 또는 partitioningBy 다운스트림의 멀티레벨 리덕션에서 사용하는 경우에 가장 편리합니다.스트림에서 단순 축소를 수행하려면 대신 Stream.reduce(Binary Operator)를 사용하십시오.
으로는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.reducing()
컬렉션 내에서 강제될 때만.다음은 또 다른 예입니다.
For example, given a stream of Person, to calculate the longest last name
of residents in each city:
Comparator<String> byLength = Comparator.comparing(String::length);
Map<String, String> longestLastNameByCity
= personList.stream().collect(groupingBy(Person::getCity,
reducing("", Person::getLastName, BinaryOperator.maxBy(byLength))));
이 튜토리얼에 따르면 절감 효과가 낮은 경우가 있습니다.
축소 작업은 항상 새 값을 반환합니다.그러나 어큐뮬레이터 함수는 스트림의 요소를 처리할 때마다 새 값도 반환합니다.스트림의 요소를 집합과 같은 더 복잡한 개체로 축소한다고 가정합니다.이로 인해 응용 프로그램의 성능이 저하될 수 있습니다.축소 작업이 컬렉션에 요소를 추가하는 경우 누적기 함수가 요소를 처리할 때마다 요소를 포함하는 새 컬렉션이 생성되므로 비효율적입니다.대신 기존 컬렉션을 업데이트하는 것이 더 효율적입니다.이 작업은 Stream.collect 메서드를 사용하여 수행할 수 있습니다.이 메서드는 다음 섹션에서 설명합니다.
에 'ID'로 가는 이 조금 더 입니다..reduce
가능하면.
항상 reduce() 메서드보다 collect() 메서드를 선호하는 이유가 있습니다.collect()를 사용하면 다음과 같이 퍼포먼스가 향상됩니다.
* Stream.collect()와 같은 가변 축소 조작은 스트림 요소를 처리할 때 가변 결과 컨테이너(컬렉션)에 수집합니다.가변 리덕션 오퍼레이션은 불변의 리덕션 오퍼레이션(Stream.reduce() 등)에 비해 퍼포먼스가 크게 향상됩니다.
이는 각 감소 단계에서 결과를 유지하는 컬렉터가 Collector에 대해 가변적이며 다음 단계에서 다시 사용할 수 있기 때문입니다.
반면 Stream.reduce() 작업은 불변의 결과 컨테이너를 사용하기 때문에 중간 단계마다 컨테이너의 새로운 인스턴스를 인스턴스화해야 하므로 성능이 저하됩니다.*
언급URL : https://stackoverflow.com/questions/22577197/java-8-streams-collect-vs-reduce
'programing' 카테고리의 다른 글
Vuex에서 POST 요청을 통해 상태 데이터를 전송하는 방법 (0) | 2022.08.01 |
---|---|
우체국에서 일했는데도 400 오류, 생각할 수 있는 이유? (0) | 2022.08.01 |
인라인 함수를 호출할 때 정의되지 않은 참조 (0) | 2022.08.01 |
일부 경로에서 글로벌컴포넌트(예를 들어 navbar)를 숨기려면 어떻게 해야 합니까? (0) | 2022.08.01 |
VueJ 2 - $emit을 사용한 파라미터 전달 방법 (0) | 2022.08.01 |