Java 8 스트림을 Guava ImmutableCollection으로 수집하려면 어떻게해야합니까?


82

다음을 수행하고 싶습니다.

List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());

그러나 결과 목록은 Guava의 ImmutableList.

내가 할 수 있다는 걸 알아

List<Integer> list = IntStream.range(0, 7).collect(Collectors.toList());
List<Integer> immutableList = ImmutableList.copyOf(list);

하지만 직접 수집하고 싶습니다. 난 노력 했어

List<Integer> list = IntStream.range(0, 7)
    .collect(Collectors.toCollection(ImmutableList::of));

하지만 예외가 발생했습니다.

com.google.common.collect.ImmutableCollection.add (ImmutableCollection.java:96)의 java.lang.UnsupportedOperationException

답변:


89

toImmutableList()렉시의 허용 대답에있어서 현재 포함되어 구아바 (21) 와 같이 사용할 수있다 :

ImmutableList<Integer> list = IntStream.range(0, 7)
    .boxed()
    .collect(ImmutableList.toImmutableList());

편집 : 릴리스 27.1 ( 6242bdd ) 에서 자주 사용되는 다른 API와 함께 제거 @Beta되었습니다 .ImmutableList.toImmutableList


1
@Beta로 표시된 메서드입니다. 그래서 그것은 문서에 의해 권장되지 않습니까?
user2602807

여전히 @BetaGuava 26.0부터.
Per Lundberg

관점을 위해 Google은 2004 년과 2009 년 사이에 Gmail을 베타 태그로 유지했습니다. 2004 년 출시 당시에는 이미 상당히 안정적이고 성숙한 제품이었습니다. Google은 일반적으로 베타 상태의 제품을 홍보하는 것을 매우 꺼립니다. 코미디의 요점에 가깝습니다.
anataliocs

68

collectingAndThen수집기가 유용한 곳은 다음과 같습니다.

List<Integer> list = IntStream.range(0, 7).boxed()
                .collect(collectingAndThen(toList(), ImmutableList::copyOf));

List방금 구축 한 변형을 적용합니다 . 결과는 ImmutableList.


또는에 직접 모아서 마지막에 Builder전화 할 수 있습니다 build().

List<Integer> list = IntStream.range(0, 7)
                .collect(Builder<Integer>::new, Builder<Integer>::add, (builder1, builder2) -> builder1.addAll(builder2.build()))
                .build();

이 옵션이 다소 장황하고 여러 곳에서 사용하려는 경우 고유 한 수집기를 만들 수 있습니다.

class ImmutableListCollector<T> implements Collector<T, Builder<T>, ImmutableList<T>> {
    @Override
    public Supplier<Builder<T>> supplier() {
        return Builder::new;
    }

    @Override
    public BiConsumer<Builder<T>, T> accumulator() {
        return (b, e) -> b.add(e);
    }

    @Override
    public BinaryOperator<Builder<T>> combiner() {
        return (b1, b2) -> b1.addAll(b2.build());
    }

    @Override
    public Function<Builder<T>, ImmutableList<T>> finisher() {
        return Builder::build;
    }

    @Override
    public Set<Characteristics> characteristics() {
        return ImmutableSet.of();
    }
}

그리고:

List<Integer> list = IntStream.range(0, 7)
                              .boxed()
                              .collect(new ImmutableListCollector<>());

댓글에서 링크가 사라지는 경우를 대비하여 내 두 번째 접근 방식은 단순히 Collector.of. 자신 만의 Collector수업을 만드는 것보다 간단합니다 .

public static <T> Collector<T, Builder<T>, ImmutableList<T>> toImmutableList() {
    return Collector.of(Builder<T>::new, Builder<T>::add, (l, r) -> l.addAll(r.build()), Builder<T>::build);
}

및 사용법 :

 List<Integer> list = IntStream.range(0, 7)
                               .boxed()
                               .collect(toImmutableList());

3
이것은 여전히 ​​중간 목록을 생성하지 않습니까? 나는 그것을 피하고 싶다. ImmutableList.Builder도움 이 될 수 있습니까?
Zoltán 2015 년

4
@ Zoltán 빌더에서 직접 값을 축적 한 다음 (편집 참조) build().
Alexis C.

4
이 자세한 답변에 감사드립니다. 이것은 현재 해결되고있는 것 같습니다 : github.com/google/guava/issues/1582 , 여기에 좋은 예도 있습니다 (당신이 제안한 것과 매우 유사합니다) : gist.github.com/JakeWharton/9734167
Zoltán

4
@ Zoltán 아 예; 좋은 발견; 두 번째 대안을 유틸리티 메소드로 간단히 감 쌉니다. A는 자신의 정의보다 더 비트 Collector:-) 클래스
알렉시스 C.에게

참조 유형은 ImmutableList<Integer>(대신 List<Integer>) 일 수 있습니다 .
palacsint

17

내 질문에 대한 직접적인 대답은 아니지만 (컬렉터를 사용하지 않음) 중간 컬렉션을 사용하지 않는 상당히 우아한 접근 방식입니다.

Stream<Integer> stream = IntStream.range(0, 7).boxed();
List<Integer> list = ImmutableList.copyOf(stream.iterator());

소스 .


6

BTW : JDK 10 이후 순수 Java로 수행 할 수 있습니다.

List<Integer> list = IntStream.range(0, 7)
    .collect(Collectors.toUnmodifiableList());

또한 toUnmodifiableSettoUnmodifiableMap가능합니다.

내부 수집기는 다음을 통해 수행되었습니다. List.of(list.toArray())


1
이것은 아닙니다 정확히 때문에, 사실 ImmutableCollections.List12ImmutableCollections.ListN! = 구아바의 ImmutableList. 실용적인 관점에서 당신은 대부분 정확하지만 대답 에이 뉘앙스를 언급하는 것이 여전히 타당합니다.
Per Lundberg

4

참고로 Java 8없이 Guava에서이 작업을 수행하는 합리적인 방법이 있습니다.

ImmutableSortedSet<Integer> set = ContiguousSet.create(
    Range.closedOpen(0, 7), DiscreteDomain.integers());
ImmutableList<Integer> list = set.asList();

List의미론이 실제로 필요하지 않고를 사용할 수 있다면 NavigableSeta ContiguousSet가 실제로 모든 요소를 ​​저장할 필요가 없기 때문에 훨씬 좋습니다 ( RangeDiscreteDomain).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.