java中Stream和Collection相互轉換
- java
- Stream
1.概述
Java 8 Stream API提供了Java Collections之外的有效替代方案,以呈現或處理結果集。但是,決定何時使用哪個是一個普遍的難題。
在本文中,我們將探索Stream
和Collection
並討論適合其各自用途的各種方案。
2. Collection
與Stream
Java Collection
List
, Set
和Map
類的數據結構,提供了有效的機制來存儲和處理數據。
但是,Stream API可用於對數據執行各種操作,而無需中間存儲。因此, Stream
工作方式類似於直接從底層存儲(如集合和I / O資源)訪問數據。
此外,這些集合主要與提供對數據的訪問以及修改數據的方式有關。另一方面,流與有效地傳輸數據有關。
儘管Java允許輕鬆地從Collection
轉換為Stream
,反之亦然,但要知道哪種是呈現/處理結果集的最佳機制是很方便的。
例如,我們可以使用stream
和parallelStream
方法Collection
轉換為Stream
public Stream<String> userNames() {
ArrayList<String> userNameSource = new ArrayList<>();
userNameSource.add("john");
userNameSource.add("smith");
userNameSource.add("tom");
return userNames.stream();
}
同樣,我們可以使用Stream API collect
Stream
轉換為Collection
public List<String> userNameList() {
return userNames().collect(Collectors.toList());
}
在這裡,我們使用Collectors.toList()
方法Stream
轉換為List
同樣,我們可以將Stream
轉換為Set
或Map
:
public static Set<String> userNameSet() {
return userNames().collect(Collectors.toSet());
}
public static Map<String, String> userNameMap() {
return userNames().collect(Collectors.toMap(u1 -> u1.toString(), u1 -> u1.toString()));
}
3.何時返回Stream
?
3.1 相關的成本高
Stream API可以隨時隨地懶惰地執行和過濾結果,這是降低實現成本的最有效方法。
例如,Java NIO readAllLines
Files
所有行,JVM必須為此文件的所有行將其內容保存在內存中。因此,此方法在返回行列表時涉及較高的實現成本。
但是, Files
類還提供了lines
方法,該方法返回一個Stream
,我們可以使用它來渲染所有行,甚至可以使用limit
方法更好地限制結果集的大小-兩者都可以延遲執行:
Files.lines(path).limit(10).collect(toList());
另外,在forEach
類的終端操作之前Stream
不會執行中間操作:
userNames().filter(i -> i.length() >= 4).forEach(System.out::println);
因此, Stream
避免了與過早實現相關的成本。
3.2 大結果或無限結果
Stream
的設計目的是為了獲得更好的性能,無論結果是大還是無限。 Stream
用於此類用例始終是一個好主意。
同樣,在結果無限的情況下,我們通常不處理整個結果集。因此,Stream API的內置功能(例如filter
和limit
證明在處理所需結果集時非常方便,使Stream
成為首選。
3.3 靈活性
Stream
允許在以任何形式或順序處理結果時非常靈活。
當我們不想對使用者強制執行一致的結果集時, Stream
此外,當我們想為消費者提供急需的靈活性時Stream
例如,我們可以使用Stream API上可用的各種操作來過濾/排序/限制結果:
public static Stream<String> filterUserNames() {
return userNames().filter(i -> i.length() >= 4);
}
public static Stream<String> sortUserNames() {
return userNames().sorted();
}
public static Stream<String> limitUserNames() {
return userNames().limit(3);
}
3.4 功能行為
Stream
功能正常。當以不同方式處理時,不允許對源進行任何修改。因此,呈現不可變結果集是首選。
例如,讓我們filter
並limit
Stream
收到的一組結果:
userNames().filter(i -> i.length() >= 4).limit(3).forEach(System.out::println);
在此,每次對Stream
filter
和limit
類的操作都會返回一個新的Stream
並且不會修改userNames
方法提供Stream
4.何時返回一個Collection
?
4.1 物化成本低
在渲染或處理涉及物化成本較低的結果時,我們可以選擇流中的集合。
換句話說,Java從一開始就通過計算所有元素來急切地Collection
因此, Collection
在實現時會對堆內存造成很大壓力。
因此,我們應該考慮使用Collection
來呈現一個結果集,該結果集不會對實現它的堆內存造成太大的壓力。
4.2 固定格式
我們可以使用Collection
來為用戶強制執行一致的結果集。例如, Collection
如TreeSet
和TreeMap
返回自然排序的結果。
換句話說,使用Collection
,我們可以確保每個使用者以相同的順序接收和處理相同的結果集。
4.3 可重複使用的結果
Collection
的形式返回時,可以輕鬆地遍歷多次。但是, Stream
就認為它已消耗掉,並在重用時IllegalStateException
public static void tryStreamTraversal() {
Stream<String> userNameStream = userNames();
userNameStream.forEach(System.out::println);
try {
userNameStream.forEach(System.out::println);
} catch(IllegalStateException e) {
System.out.println("stream has already been operated upon or closed");
}
}
因此,當很明顯消費者將遍歷結果多次時Collection
4.4 修改
與Stream
Collection
允許修改元素,例如在結果源中添加或刪除元素。因此,我們可以考慮使用集合來返回結果集,以允許使用者進行修改。
例如,我們可以使用add
/ remove
方法ArrayList
userNameList().add("bob");
userNameList().add("pepper");
userNameList().remove(2);
類似地,諸如put
和remove
類的方法允許在地圖上進行修改:
Map<String, String> userNameMap = userNameMap();
userNameMap.put("bob", "bob");
userNameMap.remove("alfred");
4.5 內存中結果
另外,當以集合形式出現的物化結果已經存在於內存中時, Collection
是一個顯而易見的選擇。
5.結論
在本文中,我們比較了Stream
和Collection
並研究了適合他們的各種方案。
我們可以得出結論, Stream
是呈現大型或無限結果集的理想選擇,它具有諸如延遲初始化,急需的靈活性和功能行為之類的優點。
但是,當我們要求結果的形式一致時,或者當涉及到較低的成本實現時,我們應該選擇Stream
Collection
。