사용자 도구

사이트 도구


java:8:stream

Java 8 Stream

Stream for Iterable

List<List<Object>> 같은 컬렉션의 컬렉션 Flatten

List<List<Object>> list = ...
List<Object> flat = 
    list.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());

Null safe stream

public static <T> Stream<T> asStream(Collection<T> collection) {
    return Optional.ofNullable(collection)
        .map(Collection::stream)
        .orElse(Stream.empty());
}
 
public static <T> Stream<T> asStream(T[] array) {
    return Optional.ofNullable(array)
        .map(Arrays::stream)
        .orElse(Stream.empty());
}
 
public static <K, V> Stream<Map.Entry<K, V>> asStream(Map<K, V> map) {
    return Optional.ofNullable(map)
        .map(kvMap -> kvMap.entrySet().stream())
        .orElse(Stream.empty());
}

Collectors.toMap

  • Collectors.toMap(key function, value function[, mergeFunction])
  • 보통은 Key 하나에 값이 하나 일 때 사용.
  • Key 하나에 값이 여러개가 나오는 충돌에 대해 merge 전략을 제공해줘야 할수도 있다.
  • 원래 HashMapnull value를 허용하지만, Collectors.toMap에서는 이게 허용이 안된다.
  • 이유는 해당 구현 내부적으로 호출하는 HashMap.merge() 메소드에서 이를 허용하지 않기 때문.

Collectors.groupingBy

  • Map 을 만들면서 다시 Collectors 의 결과를 값으로 넣는다. 보통은 키 하나에 값이 여러개가 나올 때 사용.

distinct by key

  • 객체의 특정 field / property 를 통해 distinct를 하려면,
  • 별도 Predicate 선언방식
    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object,Boolean> seen = new ConcurrentHashMap<>(); // parallel stream에서 호출할까봐 이렇게 한듯.
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }
     
    persons.stream().filter(distinctByKey(p -> p.getName());
  • toMap이용
    // 특정 Key 필드로 Map을 만들되 중복 값은 모두 무시
    persons.stream()
      .collect(toMap(Person::getName, Function.identity(), (p1, p2) -> p1))
      .values();

parallelStream

  • parallelStream은 작업 분배 오버헤드가 발생하기 때문에 CPU 연산작업만 병렬화 할경우에는 오히려 느려지는 경향이 있다.
  • DB 조회/API 호출 처럼 순차보다는 병렬이 확실히 더 확실할 때 빼고는 parallelStream은 사용하지 않는게 낫다.
  • 그리고 Thread 안정성도 보장해줘야한다.
  • 따라서 성능테스트로 완벽하게 더 좋은 성능이 보장되지 않는다면, 그냥 기본적으로 일반 스트림을 사용해야 한다.

unmodifiable, immutable collection

List<Shape> immutableBlues = shapes.stream()
                         .filter(s -> s.getColor() == BLUE)
                         .collect(collectingAndThen(toList(),
                                  Collections::unmodifiableList))
    List<Integer> list = IntStream.range(0, 9)
      .boxed()
      .collect(ImmutableList.toImmutableList());
// Generic Immutable Collection collector 만들기. 컬렉션 구현체를 원하는대로 선택
public static <T, A extends List<T>> Collector<T, A, List<T>> toImmutableList(
  Supplier<A> supplier) {
 
    return Collector.of(
      supplier,
      List::add, (left, right) -> {
        left.addAll(right);
        return left;
      }, Collections::unmodifiableList);
}
 
// 사용예 - LinkedList 구현을 unmodifiable로 감싸기
List<String> givenList = Arrays.asList("a", "b", "c", "d");
List<String> result = givenList.stream()
  .collect(MyImmutableListCollector.toImmutableList(LinkedList::new));
  • ImmutableMap.toImmutableMap() 도 사용가능. Collectors.toMap 과 유사

참고

java/8/stream.txt · 마지막으로 수정됨: 2022/04/09 00:10 저자 kwon37xi