[Java]Stream.collect

Jerry·2021년 9월 14일
0

language & framework study

목록 보기
28/28

Stream.collect 분석

1. <R> R collect(Supplier supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)

Stream의 collect 매소드는 위와 같이 정의되어 있습니다.

  • Supplier supplier : Stream의 요소들을 이용하여 생성할 누적 연산결과 객체
  • BiConsumer<R, ? super T> accumulator : 누적 연산결과를 도출할 함수 정의
  • BiConsumer<R, R> combiner : 각 스레드에서 생성된 누적연산 결과 객체 R을 결합하는 역할. 병렬 처리시에만 사용.

파라미터 참고

Supplier<T> : 함수형 인터페이스
package java.util.function;

@FunctionalInterface
public interface Supplier<T> {
    T get();
}
  • 입력 파라미터는 없고 리턴값은 있음
BiConsumer<T,U> : 함수형 인터페이스
@FunctionalInterface
public interface BiConsumer<T, U> {
  void accept(T t, U u);
  ...
}
  • 입력 파라미터를 두개 받고(객체 T와 객체 U), 리턴값은 없음

예제

StringBuilder sbResult= Stream.<String>builder()
                        .add("je")
                        .add("r")
                        .add("ry")
                        .add("st")
                        .add("udy")
                        .build()
                        .collect(StringBuilder::new,
                                 // [Supplier<R> supplier]. ()-> new StringBuilder()로 StringBuilder 객체 생성
                                 (sb, word)->sb.append(word),
                                 // [BiConsumer<R, ? super T> accumulator]. Supplier로 생성한 StringBuilder 객체에 Stream 요소들을 append 하는 함수 정의

                                 (sb1,sb2)-> sb1.append(sb2));
																 // [BiConsumer<R, R> combiner]. 병렬처리시 각 스레드에서 생성된 StringBuilder 객체를 결합
System.out.println(sbResult.toString());

[output]

jerrystudy

2. <R,A> R collect(Collector<? super T,A,R> collector)

파라미터 참고

Collector<T, A, R>
  • T: Stream의 요소
  • A : 누적기. 누적 연산을 수행할 함수
  • R : 누적 연산의 결과가 저장되는 객체

Collectors

Collectors에 정의된 정적 매소드들을 활용하면 collect 함수를 쉽게 구현할 수 있습니다.

  • static <T> Collector<T,?,Double> averagingDouble(ToDoubleFunction<? super T> mapper)
    : Stream의 요소에 mapper 연산을 하고 생성한 Double 객체로 평균값을 구한 후 Double 객체로 반환
    • [유사매소드]
      • static <T> Collector<T,?,Double> averagingInt(ToIntFunction<? super T> mapper)
      • static <T> Collector<T,?,Double> averagingLong(ToLongFunction<? super T> mapper)
Stream<String> stream= Arrays.asList("0.342","1.234","12.23","0.23").stream();
        Double avgDouble=stream.collect(Collectors.averagingDouble(val-> Double.valueOf(val)));
System.out.println("avg Double : "+avgDouble);
  • static <T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher)

    : Collector를 이용해 변환한 후 추가적인 변환작업을 한번 더 하는 경우 사용

Map<String, String> immutableMap = Stream.of(new String[][] {})
                .collect(Collectors.collectingAndThen(
                                Collectors.toMap(p -> p[0], p -> p[1]),
                                Collections::<String, String>unmodifiableMap
                ));
  • static <T> Collector<T,?,Long> counting()
    : Stream 요소의 갯수를 카운트하여 Long 타입으로 리턴

  • static <T,K> Collector<T,?,Map<K,List>> groupingBy(Function<? super T,? extends K> classifier)

    : Stream 요소를 특정 기준으로 분류하여, 분류 기준을 key로 해당되는 요소를 List형태 value로 Map객체 생성

    • [유사매소드]
      • static <T,K,A,D> Collector<T,?,Map<K,D>> groupingBy(Function<? super T,? extends K> classifier, Collector<? super T,A,D> downstream)
      • static <T,K,D,A,M extends Map<K,D>>
        Collector<T,?,M> groupingBy(Function<? super T,? extends K> classifier, Supplier mapFactory, Collector<? super T,A,D> downstream)
      • static <T,K> Collector<T,?,ConcurrentMap<K,List>> groupingByConcurrent(Function<? super T,? extends K> classifier)
      • static <T,K,A,D> Collector<T,?,ConcurrentMap<K,D>> groupingByConcurrent(Function<? super T,? extends K> classifier, Collector<? super T,A,D> downstream)
      • static <T,K,A,D,M extends ConcurrentMap<K,D>>
        Collector<T,?,M> groupingByConcurrent(Function<? super T,? extends K> classifier, Supplier mapFactory, Collector<? super T,A,D> downstream)
// Car.java
public class Car {
    private int price;
    private String carName;
  ...
}

// Person.java
public class Person {
    String name;
    int age;
    Car car;
  ...
}

//test 코드
Person person1=new Person("jerry",10,new Car(1000,"avante"));
Person person2=new Person("tom",20,new Car(2000,"audi"));
Person person3=new Person("ford",30,new Car(3000,"toycar"));
Person person4=new Person("leli",15,new Car(1000,"avante"));
Person person5=new Person("amy",40,new Car(5000,"toycar"));
List<Person> lists=new ArrayList<>();
lists.add(person1);
lists.add(person2);
lists.add(person3);
lists.add(person4);
lists.add(person5);

Map<String,List<Person>> groups = lists.stream().collect(Collectors.groupingBy(person -> person.getCar().getCarName()));
for(Map.Entry<String,List<Person>> entry : groups.entrySet()){
  System.out.println("key : "+ entry.getKey());
  System.out.println("value : "+ entry.getValue());
}

[output]

key : toycar
value : [Person{name='ford', age=30, car=Car{price=3000, carName='toycar'}}, Person{name='amy', age=40, car=Car{price=5000, carName='toycar'}}]
key : avante
value : [Person{name='jerry', age=10, car=Car{price=1000, carName='avante'}}, Person{name='leli', age=15, car=Car{price=1000, carName='avante'}}]
key : audi
value : [Person{name='tom', age=20, car=Car{price=2000, carName='audi'}}]

  • static Collector<CharSequence,?,String> joining()
    : String Stream인 경우 String들을 연결해서 하나의 String으로 반환

    • [유사매소드]

      • static Collector<CharSequence,?,String> joining(CharSequence delimiter)
        : Stream 요소를 연결할때 구분자를 중간에 삽입 delimiter

      • static Collector<CharSequence,?,String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)

        : Stream 요소 연결할때 앞(prefix), 뒤(suffix)로 문자열을 붙인 후 delimiter 구분자로 연결

  • static <T,U,A,R> Collector<T,?,R> mapping(Function<? super T,? extends U> mapper, Collector<? super U,A,R> downstream)
    : Stream 요소를 mapper 함수로 변환한 후 downstream 함수를 이용해 다른 형태로 변환후 리턴

  • static <T> Collector<T,?,Optional> maxBy(Comparator<? super T> comparator)

    : 주어진 comparator 함수를 이용해 Stream 요소 중 max 요소를 Optional로 랩핑 하여 리턴

  • static <T> Collector<T,?,Optional> minBy(Comparator<? super T> comparator)
    : 주어진 comparator 함수를 이용해 Stream 요소 중 min 요소를 Optional로 랩핑 하여 리턴

  • static <T> Collector<T,?,Map<Boolean,List>> partitioningBy(Predicate<? super T> predicate)
    : predicate 함수식으로 stream 요소에 대한 논리연산 결과값을 리턴하여, 결과값 true/false를 key로 Map 객체 생성

    • [유사매소드]
      • static <T,D,A> Collector<T,?,Map<Boolean,D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T,A,D> downstream)
Stream<Integer> stream3=Arrays.asList(1,2,3,4,5,6,7,8,9,10).stream();
Map<Boolean, List<Integer>> collect = stream3.collect(Collectors.partitioningBy(val -> val % 2 == 0));

for(Map.Entry<Boolean,List<Integer>> entry : collect.entrySet()){
  System.out.println("key : "+ entry.getKey());
  System.out.println("value : "+ entry.getValue());
}

[output]

key : false
value : [1, 3, 5, 7, 9]
key : true
value : [2, 4, 6, 8, 10]

  • static Collector<T,?,Optional> reducing(BinaryOperator op)
    : Stream의 요소를 순회하며 누적 연산한 결과를 리턴
    • [유사매소드]
      - static Collector<T,?,T> reducing(T identity, BinaryOperator op)
      : 초기값(identity) 설정
      - static <T,U> Collector<T,?,U> reducing(U identity, Function<? super T,? extends U> mapper, BinaryOperator<U op)
      : 초기값과(identity)과 요소를 변환할 mapper 함수 지정텍스트
Stream<Integer> stream=Arrays.asList(1,2,3,4,5,6,7,8,9,10).stream();
Integer accumulateSum=stream.collect(Collectors.reducing
                                      (0, // 초기값
                                       Integer::intValue // mapper. Stream의 요소를 mapper를 통해 변환
                                       ,(total, num)->total+num)); // total은 축적되는 값, num은 mapper로 변환된 Stream의 요소
System.out.println("reducing result: "+ accumulateSum);

[output]

reducing result: 55

  • static <T> Collector<T,?,Double> summingDouble(ToDoubleFunction<? super T> mapper)
    : mapper함수로 Stream 요소를 Double 타입으로 변환 후 합계를 구하여 Double 타입으로 리턴

    • [유사매소드]
      • static <T> Collector<T,?,Integer> summingInt(ToIntFunction<? super T> mapper)
      • static <T> Collector<T,?,Long> summingLong(ToLongFunction<? super T> mapper)
  • static <T> Collector<T,?,DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper)
    : Stream 요소를 mapper함수로 Double로 변환후 요소들의 DoubleSummaryStatistics 객체를 생성

    • DoubleSummaryStatistics : 복수개의 double 데이터로 여러가지 연산 결과를 저장할 수 있는 객체
  package java.util;
  
  public class DoubleSummaryStatistics implements DoubleConsumer {
      private long count;
      private double sum;
      private double sumCompensation; // Low order bits of sum
      private double simpleSum; // Used to compute right sum for non-finite inputs
      private double min = Double.POSITIVE_INFINITY;
      private double max = Double.NEGATIVE_INFINITY;
    ...
      public final long getCount() {
          return count;
      }
      public final double getSum() {
      ...
      }
      public final double getMin() {
          return min;
      }
      public final double getMax() {
          return max;
      }
  	  public final double getAverage() {
          return getCount() > 0 ? getSum() / getCount() : 0.0d;
      }
  • [유사매소드]

    • static <T> Collector<T,?,IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper)
    • static <T> Collector<T,?,LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper)
  • static <T,C extends Collection>
    Collector<T,?,C> toCollection(Supplier collectionFactory)
    : Collection 인터페이스를 구현한 특정 객체로 변환하여 리턴 [toSet(), toList()의 경우에는 특정한 구현 객체 지정 불가]

  • static <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)
    : Stream의 요소와 key를 추출하는 함수, value를 추출하는 함수를 정의하여 Map객체를 반환

    • [유사매소드]
      • static <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction)
      • static <T,K,U,M extends Map<K,U>>
        Collector<T,?,M> toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier)
      • static <T,K,U> Collector<T,?,ConcurrentMap<K,U>> toConcurrentMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper)
        : Thread-safe 한 ConcurrentMap으로 변환
      • static <T,K,U> Collector<T,?,ConcurrentMap<K,U>> toConcurrentMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction)
      • static <T,K,U,M extends ConcurrentMap<K,U>>
        Collector<T,?,M> toConcurrentMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier mapSupplier)
  • static Collector<T,?,List> toList()
    : Stream 요소를 List 형태로 리턴

  • static <T> Collector<T,?,Set> toSet()
    : Stream의 요소를 Set 데이터 타입으로 변환

[참고]

oracle docs jdk 11

Java Stream 사용자 정의 컨테이너에 수집하기(collect())

techie delight - Collectors collectingAndThen() method in Java

profile
제리하이웨이

0개의 댓글