java中Stream和Collection相互轉換

1.概述

Java 8 Stream API提供了Java Collections之外的有效替代方案,以呈現或處理結果集。但是,決定何時使用哪個是一個普遍的難題。

在本文中,我們將探索StreamCollection並討論適合其各自用途的各種方案。

2. CollectionStream

Java Collection ListSetMap類的數據結構,提供了有效的機制來存儲和處理數據。

但是,Stream API可用於對數據執行各種操作,而無需中間存儲。因此, Stream工作方式類似於直接從底層存儲(如集合和I / O資源)訪問數據。

此外,這些集合主要與提供對數據的訪問以及修改數據的方式有關。另一方面,流與有效地傳輸數據有關。

儘管Java允許輕鬆地從Collection轉換為Stream ,反之亦然,但要知道哪種是呈現/處理結果集的最佳機制是很方便的。

例如,我們可以使用streamparallelStream方法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轉換為SetMap

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的內置功能(例如filterlimit證明在處理所需結果集時非常方便,使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功能正常。當以不同方式處理時,不允許對源進行任何修改。因此,呈現不可變結果集是首選。

例如,讓我們filterlimit Stream收到的一組結果:

userNames().filter(i -> i.length() >= 4).limit(3).forEach(System.out::println);

在此,每次對Stream filterlimit類的操作都會返回一個新的Stream並且不會修改userNames方法提供Stream

4.何時返回一個Collection

4.1 物化成本低

在渲染或處理涉及物化成本較低的結果時,我們可以選擇流中的集合。

換句話說,Java從一開始就通過計算所有元素來急切地Collection因此, Collection在實現時會對堆內存造成很大壓力。

因此,我們應該考慮使用Collection來呈現一個結果集,該結果集不會對實現它的堆內存造成太大的壓力。

4.2 固定格式

我們可以使用Collection來為用戶強制執行一致的結果集。例如, CollectionTreeSetTreeMap返回自然排序的結果。

換句話說,使用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);

類似地,諸如putremove類的方法允許在地圖上進行修改:

Map<String, String> userNameMap = userNameMap();

 userNameMap.put("bob", "bob");

 userNameMap.remove("alfred");

4.5 內存中結果

另外,當以集合形式出現的物化結果已經存在於內存中時, Collection是一個顯而易見的選擇。

5.結論

在本文中,我們比較了StreamCollection並研究了適合他們的各種方案。

我們可以得出結論, Stream是呈現大型或無限結果集的理想選擇,它具有諸如延遲初始化,急需的靈活性和功能行為之類的優點。

但是,當我們要求結果的形式一致時,或者當涉及到較低的成本實現時,我們應該選擇Stream Collection