將Java流收集到不可變集合

1.簡介

在這篇快速的文章中,我們將研究將Java Streams收集到不可變的Collections的各種方法-這需要一種特殊的方法,因為標準的Collector僅適用於可變數據結構。

2. Maven依賴

我們將利用Google的Guava庫來驅動一些示例:

<dependency>

 <groupId>com.google.guava</groupId>

 <artifactId>guava</artifactId>

 <version>22.0</version>

 </dependency>

我們可以從這裡獲取此依賴項的最新版本。

3.使用Java的collectionAndThen()

Java的Collectors類中的collectionAndThen()方法接受一個Collector和一個finisher**函數,該函數應用於從Collector返回的結果

@Test

 public void whenUsingCollectingToImmutableList_thenSuccess() {

 List<String> givenList = Arrays.asList("a", "b", "c");

 List<String> result = givenList.stream()

 .collect(collectingAndThen(toList(), ImmutableList::copyOf));



 System.out.println(result.getClass());

 }

由於我們不能直接使用toCollection ()收集器**,因此我們需要將元素收集到一個臨時列表中,然後從中構造一個不可變列表。

在此示例中,我們使用toList()收集器將Stream轉換為List ,然後創建ImmutableListImmutableList是Guava庫的一部分。如果將輸出記錄到控制台,則將獲取基礎類

如果將輸出記錄到控制台,則將獲得基礎List實現的類:

class com.google.common.collect.RegularImmutableList

4.使用番石榴的收藏家

從Guava 21開始,每個不可變的類都有一個隨附的Collector ,它與標準Collector一樣易於使用

@Test

 public void whenCollectToImmutableList_thenSuccess() {

 List<Integer> list = IntStream.range(0, 9)

 .boxed()

 .collect(ImmutableList.toImmutableList());

 }

結果實例是RegularImmutableList

class com.google.common.collect.RegularImmutableList

5.建立一個自定義收集器

現在,讓我們進一步前進,並實現我們的自定義Collector 。為了實現這個目標,我們將使用靜態的Collector.of()方法:

public static <T> Collector<T, List<T>, List<T>> toImmutableList() {

 return Collector.of(ArrayList::new, List::add,

 (left, right) -> {

 left.addAll(right);

 return left;

 }, Collections::unmodifiableList);

 }

要了解有關實現自定義收集器的更多信息,請參見本文的第4節。就是這樣。上面的方法是我們自定義類的一部分

我們現在可以像使用其他任何內置收集器一樣使用它:

@Test

 public void whenCollectToMyImmutableListCollector_thenSuccess() {

 List<String> givenList = Arrays.asList("a", "b", "c", "d");

 List<String> result = givenList.stream()

 .collect(MyImmutableListCollector.toImmutableList());

 }

最後,讓我們檢查輸出:

class java.util.Collections$UnmodifiableRandomAccessList

5.1。使MyImmutableListCollector通用

我們的實現有一個局限性–它總是返回一個由ArrayList支持的不可變實例。但是,經過一些改進,我們可以使此收集器返回用戶指定的類型:

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

 }

現在,我們不是在方法實現中確定供應商,而是向用戶請求供應商

@Test

 public void whenPassingSupplier_thenSuccess() {

 List<String> givenList = Arrays.asList("a", "b", "c", "d");

 List<String> result = givenList.stream()

 .collect(MyImmutableListCollector.toImmutableList(LinkedList::new));

 }

請注意,我們現在使用的是LinkedList而不是ArrayList 。讓我們運行它並查看結果:

class java.util.Collections$UnmodifiableList

這次,我們得到了UnmodifiableList而不是UnmodifiableRandomAccessList

六,結論

在這篇簡短的文章中,我們已經看到了將Stream收集為不可變Collection的各種方法。

確保在GitHub上查看本文的完整源代碼。