2015-03-12 16 views
56

Tôi muốn làm như sau:Làm cách nào tôi có thể thu thập luồng Java 8 vào một bộ sưu tập không thể đoán được của Guava?

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

nhưng theo một cách mà danh sách kết quả là một thực hiện ổi của ImmutableList.

Tôi biết tôi có thể làm

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

nhưng tôi muốn thu thập để nó trực tiếp. Tôi đã thử

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

nhưng nó ném một ngoại lệ:

java.lang.UnsupportedOperationException tại com.google.common.collect.ImmutableCollection.add (ImmutableCollection.java:96)

Trả lời

50

Đây là nơi mà các nhà sưu tập collectingAndThen rất hữu ích:

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

Nó áp dụng việc chuyển đổi thành List bạn vừa xây dựng; dẫn đến một số ImmutableList.


Hoặc bạn có thể trực tiếp thu thập vào Builder và gọi build() ở cuối:

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

Nếu tùy chọn này là một chút-verbose cho bạn và bạn muốn sử dụng nó ở nhiều nơi, bạn có thể tạo ra thu của riêng bạn:

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(); 
    } 
} 

và sau đó:

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

Chỉ trong trường hợp liên kết biến mất trong các nhận xét; cách tiếp cận thứ hai của tôi có thể được định nghĩa trong một phương thức tiện ích tĩnh chỉ đơn giản là sử dụng Collector.of. Nó đơn giản hơn việc tạo lớp Collector của riêng bạn.

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); 
} 

và cách sử dụng:

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

này vẫn tạo ra một danh sách trung gian, phải không? Tôi muốn tránh điều đó. Có thể 'ImmutableList.Builder' được giúp đỡ không? –

+3

@ Zoltán Bạn có thể tích lũy các giá trị trong trình tạo trực tiếp (xem phần chỉnh sửa) và sau đó gọi 'build()'. –

+2

Cảm ơn bạn đã trả lời chi tiết này. Dường như điều này hiện đang được giải quyết: https://github.com/google/guava/issues/1582, cũng có một ví dụ điển hình ở đây (rất giống với những gì bạn đề xuất): https://gist.github.com/ JakeWharton/9734167 –

13

Trong khi không phải là một câu trả lời trực tiếp câu hỏi của tôi (nó không sử dụng nhà sưu tập), đây là một cách tiếp cận khá thanh lịch mà không sử dụng bộ sưu tập trung:

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

Source.

3

FYI, có một cách hợp lý để làm điều này trong ổi mà không cần Java 8:

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

Nếu bạn không thực sự cần những List ngữ nghĩa và chỉ có thể sử dụng một NavigableSet, mà thậm chí còn tốt hơn kể từ khi một ContiguousSet doesn không phải thực sự lưu trữ tất cả các phần tử trong đó (chỉ là RangeDiscreteDomain).

51

Phương pháp toImmutableList() trong câu trả lời chấp nhận của Alexis hiện được đưa vào Guava 21 và có thể được sử dụng như:

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

Tôi thích phương pháp này) – ycomp

+0

... ngoại trừ việc tôi không thể sử dụng ổi 22 hoặc 21 vì tôi bị kẹt ở tuổi 19 vì tôi có một số thư viện khác trong poms sử dụng một phiên bản cũ của ổi ... bất cứ ai biết làm thế nào tôi có thể theo dõi nó xuống? – ycomp

Các vấn đề liên quan