App下載

Java 8 流式編程:讓你的代碼更優(yōu)雅

美少女上梁山 2023-06-21 13:43:20 瀏覽數(shù) (2359)
反饋

Java 8 引入了一個(gè)新的抽象概念,叫做流(Stream)。流可以讓你以一種聲明式的方式處理數(shù)據(jù),類(lèi)似于 SQL 語(yǔ)句。流不僅可以操作集合,還可以操作數(shù)組、文件、生成器等數(shù)據(jù)源。流還支持并行處理,可以充分利用多核 CPU 的性能。

本文將介紹 Java 8 流式編程的基本概念和常用方法,幫助你掌握流式編程的精髓。

什么是流?

流(Stream)是一個(gè)來(lái)自數(shù)據(jù)源的元素序列,并支持聚合操作。流有以下幾個(gè)特點(diǎn):

  • 流不存儲(chǔ)元素,而是按需計(jì)算。
  • 流的操作不會(huì)改變?cè)磾?shù)據(jù),而是返回一個(gè)新的流。
  • 流的操作是延遲執(zhí)行的,只有當(dāng)需要結(jié)果時(shí)才會(huì)執(zhí)行。
  • 流支持內(nèi)部迭代,無(wú)需顯示地遍歷元素。
  • 流支持串行和并行兩種模式。

如何創(chuàng)建流?

創(chuàng)建流的方式有很多,常見(jiàn)的有以下幾種:

  • 從集合或數(shù)組創(chuàng)建流。例如,List list = Arrays.asList("a", "b", "c"); Stream stream = list.stream();
  • 從 Stream 類(lèi)的靜態(tài)方法創(chuàng)建流。例如,Stream stream = Stream.of("a", "b", "c");
  • 從文件或 I/O 通道創(chuàng)建流。例如,Stream stream = Files.lines(Paths.get("data.txt"));
  • 從 Random 或其他生成器創(chuàng)建流。例如,Stream stream = Stream.generate(() -> new Random().nextInt(100));
  • 從其他類(lèi)型的流創(chuàng)建流。例如,IntStream intStream = stream.mapToInt(String::length);

如何操作流?

流提供了很多有用的方法來(lái)對(duì)元素進(jìn)行操作,這些方法可以分為兩類(lèi):中間操作(Intermediate Operation)和終端操作(Terminal Operation)。

中間操作會(huì)返回一個(gè)新的流,可以鏈?zhǔn)秸{(diào)用多個(gè)中間操作。中間操作是惰性的,只有當(dāng)遇到終端操作時(shí)才會(huì)執(zhí)行。

終端操作會(huì)產(chǎn)生一個(gè)結(jié)果或副作用,比如計(jì)算平均值、求和、打印輸出等。終端操作會(huì)消耗掉流,執(zhí)行完終端操作后,流就不能再使用了。

下面介紹一些常用的中間操作和終端操作。

中間操作

  • filter:根據(jù)條件過(guò)濾元素。例如,stream.filter(s -> s.length() > 3)表示只保留長(zhǎng)度大于3的字符串。
  • map:對(duì)每個(gè)元素進(jìn)行映射,生成一個(gè)新的元素。例如,stream.map(String::toUpperCase)表示把每個(gè)字符串轉(zhuǎn)換成大寫(xiě)。
  • flatMap:對(duì)每個(gè)元素進(jìn)行映射,生成一個(gè)新的流,并把所有的流合并成一個(gè)流。例如,stream.flatMap(s -> Arrays.stream(s.split("")))表示把每個(gè)字符串拆分成字符,并合并成一個(gè)字符流。
  • distinct:去除重復(fù)的元素。例如,stream.distinct()表示去除重復(fù)的字符串。
  • sorted:對(duì)元素進(jìn)行排序。例如,stream.sorted()表示按照自然順序排序,stream.sorted(Comparator.comparing(String::length))表示按照長(zhǎng)度排序。
  • limit:截取前n個(gè)元素。例如,stream.limit(10)表示只保留前10個(gè)元素。
  • skip:跳過(guò)前n個(gè)元素。例如,stream.skip(10)表示跳過(guò)前10個(gè)元素。

終端操作

  • forEach:對(duì)每個(gè)元素執(zhí)行一個(gè)操作。例如,stream.forEach(System.out::println)表示打印每個(gè)元素。
  • count:返回元素的個(gè)數(shù)。例如,stream.count()表示返回流中元素的個(gè)數(shù)。
  • collect:將流轉(zhuǎn)換成其他形式。例如,stream.collect(Collectors.toList())表示將流轉(zhuǎn)換成列表,stream.collect(Collectors.joining(","))表示將流中的字符串用逗號(hào)連接起來(lái)。
  • reduce:對(duì)流中的元素進(jìn)行歸約操作,生成一個(gè)值。例如,stream.reduce((s1, s2) -> s1 + s2)表示將流中的字符串拼接起來(lái),stream.reduce(0, (n1, n2) -> n1 + n2)表示將流中的整數(shù)求和。
  • min:返回最小的元素。例如,stream.min(Comparator.comparing(String::length))表示返回長(zhǎng)度最短的字符串。
  • max:返回最大的元素。例如,stream.max(Comparator.comparing(String::length))表示返回長(zhǎng)度最長(zhǎng)的字符串。
  • anyMatch:判斷是否有任意一個(gè)元素滿足條件。例如,stream.anyMatch(s -> s.startsWith("a"))表示判斷是否有以a開(kāi)頭的字符串。
  • allMatch:判斷是否所有的元素都滿足條件。例如,stream.allMatch(s -> s.length() > 3)表示判斷是否所有的字符串長(zhǎng)度都大于3。
  • noneMatch:判斷是否沒(méi)有任何一個(gè)元素滿足條件。例如,stream.noneMatch(s -> s.contains("z"))表示判斷是否沒(méi)有包含z的字符串。

如何使用并行流?

并行流是指可以利用多核 CPU 并行處理的流。并行流可以提高性能,但也有一些注意事項(xiàng):

  • 并行流不一定比串行流快,因?yàn)椴⑿辛餍枰~外的線程切換和數(shù)據(jù)同步開(kāi)銷(xiāo)。
  • 并行流不一定能保證順序性,因?yàn)槎鄠€(gè)線程同時(shí)處理元素可能會(huì)導(dǎo)致亂序。
  • 并行流不適合有狀態(tài)的操作,因?yàn)槎鄠€(gè)線程同時(shí)操作共享狀態(tài)可能會(huì)導(dǎo)致數(shù)據(jù)不一致。

要?jiǎng)?chuàng)建一個(gè)并行流,有以下幾種方式:

  • 調(diào)用 parallelStream() 方法。例如,list.parallelStream()表示從列表創(chuàng)建一個(gè)并行流。
  • 調(diào)用 parallel() 方法。例如,stream.parallel()表示把一個(gè)串行流轉(zhuǎn)換成并行流。
  • 使用 StreamSupport 類(lèi)。例如,StreamSupport.stream(iterable.spliterator(), true)表示從可迭代對(duì)象創(chuàng)建一個(gè)并行流。

要把一個(gè)并行流轉(zhuǎn)換成串行流,可以調(diào)用 sequential() 方法。例如,stream.sequential()表示把一個(gè)并行流轉(zhuǎn)換成串行流。

總結(jié)

本文介紹了 Java 8 流式編程的基本概念和常用方法,希望能幫助你理解和使用流式編程,讓你的代碼更優(yōu)雅、更高效、更簡(jiǎn)潔。

0 人點(diǎn)贊