日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Effective Java~45. 谨慎使用Stream

發(fā)布時間:2024/7/23 java 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Effective Java~45. 谨慎使用Stream 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在 Java 8 中添加了 Stream API,以簡化順序或并行執(zhí)行批量操作的任務(wù)。 該 API 提供了兩個關(guān)鍵的抽象:流(Stream),表示有限或無限的數(shù)據(jù)元素序列,以及流管道 (stream pipeline),表示對這些元素的多級計算。 Stream 中的元素可以來自任何地方。 常見的源包括集合,數(shù)組,文件,正則表達(dá)式模式匹配器,偽隨機數(shù)生成器和其他流。流中的數(shù)據(jù)元素可以是對象引用或基本類型。 支持三種基本類型:int,long 和 double。

流管道由源流(source stream)的零或多個中間操作和一個終結(jié)操作組成。每個中間操作都以某種方式轉(zhuǎn)換流,例如將每個元素映射到該元素的函數(shù)或過濾掉所有不滿足某些條件的元素。中間操作都將一個流轉(zhuǎn)換為另一個流,其元素類型可能與輸入流相同或不同。終結(jié)操作對流執(zhí)行最后一次中間操作產(chǎn)生的最終計算,例如將其元素存儲到集合中、返回某個元素或打印其所有元素。

管道延遲(lazily)計算求值:計算直到終結(jié)操作被調(diào)用后才開始,而為了完成終結(jié)操作而不需要的數(shù)據(jù)元素永遠(yuǎn)不會被計算出來。 這種延遲計算求值的方式使得可以使用無限流。 請注意,沒有終結(jié)操作的流管道是靜默無操作的,所以不要忘記包含一個。

????????Stream API 流式的(fluent)::它設(shè)計允許所有組成管道的調(diào)用被鏈接到一個表達(dá)式中。事實上,多個管道可以鏈接在一起形成一個表達(dá)式。

????????默認(rèn)情況下,流管道按順序 (sequentially) 運行。 使管道并行執(zhí)行就像在管道中的任何流上調(diào)用并行方法一樣簡單,但很少這樣做(第 48 個條目)。

????????Stream API 具有足夠的通用性,實際上任何計算都可以使用 Stream 執(zhí)行,但僅僅因為可以,并不意味著應(yīng)該這樣做。如果使用得當(dāng),流可以使程序更短更清晰;如果使用不當(dāng),它們會使程序難以閱讀和維護(hù)。對于何時使用流沒有硬性的規(guī)則,但是有一些啟發(fā)。

????????考慮以下程序,該程序從字典文件中讀取單詞并打印其大小符合用戶指定的最小值的所有變位詞(anagram)組。如果兩個單詞由長度相通,不同順序的相同字母組成,則它們是變位詞。程序從用戶指定的字典文件中讀取每個單詞并將單詞放入 map 對象中。map 對象的鍵是按照字母排序的單詞,因此『staple』的鍵是『aelpst』,『petals』的鍵也是『aelpst』:這兩個單詞就是同位詞,所有的同位詞共享相同的依字母順序排列的形式(或稱之為alphagram)。map 對象的值是包含共享字母順序形式的所有單詞的列表。 處理完字典文件后,每個列表都是一個完整的同位詞組。然后程序遍歷 map 對象的 values() 的視圖并打印每個大小符合閾值的列表:

// Prints all large anagram groups in a dictionary iteratively public class Anagrams {public static void main(String[] args) throws IOException {File dictionary = new File(args[0]);int minGroupSize = Integer.parseInt(args[1]);Map<String, Set<String>> groups = new HashMap<>();try (Scanner s = new Scanner(dictionary)) {while (s.hasNext()) {String word = s.next();groups.computeIfAbsent(alphabetize(word), (unused) -> new TreeSet<>()).add(word);}}for (Set<String> group : groups.values())if (group.size() >= minGroupSize)System.out.println(group.size() + ": " + group);}private static String alphabetize(String s) {char[] a = s.toCharArray();Arrays.sort(a);return new String(a);} }

????????現(xiàn)在考慮以下程序,它解決了同樣的問題,但大量過度使用了流。 請注意,整個程序(打開字典文件的代碼除外)包含在單個表達(dá)式中。 在單獨的表達(dá)式中打開字典文件的唯一原因是允許使用 try-with-resources 語句,該語句確保關(guān)閉字典文件:

// Overuse of streams - don't do this! public class Anagrams {public static void main(String[] args) throws IOException {Path dictionary = Paths.get(args[0]);int minGroupSize = Integer.parseInt(args[1]);try (Stream<String> words = Files.lines(dictionary)) {words.collect(groupingBy(word -> word.chars().sorted().collect(StringBuilder::new,(sb, c) -> sb.append((char) c),StringBuilder::append).toString())).values().stream().filter(group -> group.size() >= minGroupSize).map(group -> group.size() + ": " + group).forEach(System.out::println);}} }

????????如果你發(fā)現(xiàn)這段代碼難以閱讀,不要擔(dān)心;你不是一個人。它更短,但是可讀性也更差,尤其是對于那些不擅長使用流的程序員來說。過度使用流使程序難于閱讀和維護(hù)

????????幸運的是,有一個折中的辦法。下面的程序解決了同樣的問題,使用流而不過度使用它們。其結(jié)果是一個比原來更短更清晰的程序:

// Tasteful use of streams enhances clarity and conciseness public class Anagrams {public static void main(String[] args) throws IOException {Path dictionary = Paths.get(args[0]);int minGroupSize = Integer.parseInt(args[1]);try (Stream<String> words = Files.lines(dictionary)) {words.collect(groupingBy(word -> alphabetize(word))).values().stream().filter(group -> group.size() >= minGroupSize).forEach(g -> System.out.println(g.size() + ": " + g));}}// alphabetize method is the same as in original version }

????????請注意,仔細(xì)選擇 lambda 參數(shù)名稱。 上面程序中參數(shù) g 應(yīng)該真正命名為 group,但是生成的代碼行對于本書來說太寬了。 在沒有顯式類型的情況下,仔細(xì)命名 lambda 參數(shù)對于流管道的可讀性至關(guān)重要。

另請注意,單詞字母化是在單獨的 alphabetize 方法中完成的。 這通過提供操作名稱并將實現(xiàn)細(xì)節(jié)保留在主程序之外來增強可讀性。 使用輔助方法對于流管道中的可讀性比在迭代代碼中更為重要,因為管道缺少顯式類型信息和命名臨時變量

流可以很容易地做一些事情:

· 統(tǒng)一轉(zhuǎn)換元素序列
· 過濾元素序列
· 使用單個操作組合元素序列 (例如添加、連接或計算最小值)
· 將元素序列累積到一個集合中,可能通過一些公共屬性將它們分組
· 在元素序列中搜索滿足某些條件的元素

????????總之,有些任務(wù)最好使用流來完成,有些任務(wù)最好使用迭代來完成。將這兩種方法結(jié)合起來,可以最好地完成許多任務(wù)。對于選擇使用哪種方法進(jìn)行任務(wù),沒有硬性規(guī)定,但是有一些有用的啟發(fā)式方法。在許多情況下,使用哪種方法將是清楚的;在某些情況下,則不會很清楚。如果不確定一個任務(wù)是通過流還是迭代更好地完成,那么嘗試這兩種方法,看看哪一種效果更好

總結(jié)

以上是生活随笔為你收集整理的Effective Java~45. 谨慎使用Stream的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。