將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 ,然後創建ImmutableList 。 ImmutableList是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上查看本文的完整源代碼。