屋頂平臺設(shè)計(jì)效果圖大全淘寶優(yōu)化
文章目錄
- 什么是 Stream Api?
- 快速入門
- 流的操作
- 創(chuàng)建流
- 中間操作
- filter 過濾
- map 數(shù)據(jù)轉(zhuǎn)換
- flatMap 合并流
- distinct 去重
- sorted 排序
- limit 限流
- skip 跳過
- peek 操作
- 終結(jié)操作
- forEach 遍歷
- forEachOrdered 有序遍歷
- count 統(tǒng)計(jì)數(shù)量
- min 最小值
- max 最大值
- reduce 聚合
- collect 收集
- anyMatch 任意匹配
- allMatch 全匹配
- noneMatch 全不匹配
- findFirst 查找第一個
- findAny
什么是 Stream Api?
Stream流的由來可以追溯到函數(shù)式編程語言,特別是Haskell語言的概念。函數(shù)式編程強(qiáng)調(diào)以函數(shù)為基本構(gòu)建塊,并通過組合和轉(zhuǎn)換函數(shù)來操作數(shù)據(jù)。
Java 8引入了Lambda表達(dá)式,使得函數(shù)式編程在Java中更加方便和實(shí)用。為了能夠更好地支持函數(shù)式編程的思想,Java 8也引入了Stream流這個概念。
Stream流的設(shè)計(jì)目標(biāo)是提供一種高效且易于使用的方式來對集合數(shù)據(jù)進(jìn)行處理。它的設(shè)計(jì)靈感來源于Unix Shell和函數(shù)式編程語言中的管道操作符(|)。Stream流可以看作是對集合數(shù)據(jù)進(jìn)行流式操作的抽象,它將數(shù)據(jù)的處理過程抽象成一系列的操作步驟,可以鏈?zhǔn)降剡M(jìn)行操作。
通過使用Stream流,我們可以以一種聲明式的方式來描述對數(shù)據(jù)的操作,而無需關(guān)心底層的實(shí)現(xiàn)細(xì)節(jié)。這樣的好處是我們可以編寫更簡潔、可讀性更高的代碼,并且Stream API還可以自動優(yōu)化并行執(zhí)行,提高運(yùn)行效率。
因此,Stream流的引入使得Java語言更加接近函數(shù)式編程的理念,提供了一種更現(xiàn)代化、高效的數(shù)據(jù)處理方式。它的出現(xiàn)大大簡化了對集合數(shù)據(jù)的處理,使得代碼更加簡潔、易讀,并且提供了更好的性能。
Stream 流可以讓我們以一種聲明式的方式對集合數(shù)據(jù)進(jìn)行操作,從而簡化代碼并提高代碼可讀性和可維護(hù)性。同時,在使用流時還可以結(jié)合Lambda表達(dá)式,進(jìn)一步簡化代碼。
Stream流的優(yōu)點(diǎn):
-
代碼簡潔:使用Stream API可以用更少的代碼實(shí)現(xiàn)相同的功能,使代碼更加簡潔、易讀。
-
并行支持:Stream可以自動優(yōu)化并行執(zhí)行,可以利用多核CPU提高運(yùn)行效率。
-
延遲執(zhí)行:Stream支持延遲執(zhí)行,只有在需要輸出結(jié)果的時候才會進(jìn)行計(jì)算,可以減少一部分不必要的計(jì)算。
Lambda表達(dá)式的優(yōu)點(diǎn):
-
簡潔高效:Lambda表達(dá)式可以讓我們寫出更加簡潔高效的代碼。
-
可讀性好:Lambda表達(dá)式可以讓代碼變得更加易讀,減少了冗余代碼。
-
面向函數(shù)編程:Lambda表達(dá)式可以讓Java開發(fā)者更加容易地采用函數(shù)式編程的思想。
例如,假設(shè)我們有一個整數(shù)列表,要求將其中所有大于10的數(shù)加倍,然后將結(jié)果存儲在另一個列表中。
使用傳統(tǒng)的方法,可能需要寫出以下代碼:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);List<Integer> newList = new ArrayList<>();for (Integer i : list) {if (i > 10) {newList.add(i * 2);}
}
使用Stream和Lambda表達(dá)式則可以寫出更為簡潔的代碼:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);List<Integer> newList = list.stream().filter(i -> i > 10).map(i -> i * 2).collect(Collectors.toList());
這段代碼使用了Stream的filter和map方法,以及Lambda表達(dá)式,可以一行代碼實(shí)現(xiàn)要求。
快速入門
我們先通過一個簡單的快速入門案例,體驗(yàn)以下Stream流的強(qiáng)大功能。
題目: 假設(shè)我們有一個整數(shù)列表,需要篩選出其中所有大于5的數(shù),并將它們加倍后輸出。
-
使用 for 循環(huán)的方式實(shí)現(xiàn):
public class StreamExample {public static void main(String[] args) {// 創(chuàng)建一個整數(shù)集合List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 創(chuàng)建一個結(jié)果集合List<Integer> result = new ArrayList<>();//循環(huán)遍歷for (Integer n : numbers) {if (n > 5) {result.add(n * 2);}}// 輸出結(jié)果System.out.println(result);} }
-
使用 Stream 流的方式實(shí)現(xiàn):
public class StreamExample {public static void main(String[] args) {// 創(chuàng)建一個整數(shù)集合List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 使用Stream流對列表進(jìn)行篩選和轉(zhuǎn)換操作List<Integer> result = numbers.stream().filter(n -> n > 5) // 篩選出大于5的數(shù).map(n -> n * 2) // 將選中的數(shù)加倍.collect(Collectors.toList()); // 將結(jié)果轉(zhuǎn)換為新的列表// 輸出結(jié)果System.out.println(result);} }
在代碼中,我們首先創(chuàng)建了一個整數(shù)列表
numbers
,包含了1到10的整數(shù)。接下來,我們使用
stream()
方法將列表轉(zhuǎn)換為一個流對象。然后,通過調(diào)用filter()
方法來篩選出大于5的數(shù),使用map()
方法將選中的數(shù)加倍。最后使用collect()
方法將結(jié)果轉(zhuǎn)換為一個新的列表。最終,通過
System.out.println()
將結(jié)果輸出到控制臺。
流的操作
創(chuàng)建流
在Java 8中提供了多種方式去完成Stream流的創(chuàng)建,常用方式如下:
-
通過單列集合創(chuàng)建:對于實(shí)現(xiàn)了
java.util.Collection
接口的集合,比如List
、Set
等,可以直接調(diào)用stream()
方法來創(chuàng)建流對象。List<String> list = Arrays.asList("apple", "banana", "orange"); Stream<String> stream = list.stream();
-
通過數(shù)組創(chuàng)建:可以通過調(diào)用
Arrays.stream()
方法來創(chuàng)建一個數(shù)組的流對象。Integer[] array = {1, 2, 3, 4, 5}; Stream<Integer> stream = Arrays.stream(array);
-
通過雙列集合創(chuàng)建:
-
使用
entrySet().stream()
方法:對于Map
類型的雙列集合,可以先通過entrySet()
方法獲取鍵值對的Set
集合,然后再調(diào)用stream()
方法創(chuàng)建流對象。Map<String, Integer> map = new HashMap<>(); // map.put() 添加元素 Set<Map.Entry<String, Integer>> entrySet = map.entrySet(); Stream<Map.Entry<String, Integer>> stream = entrySet.stream();
-
使用
values().stream()
方法:對于Map
類型的雙列集合,也可以只獲取值的集合,然后再調(diào)用stream()
方法創(chuàng)建流對象。Map<String, Integer> map = new HashMap<>(); // map.put() 添加元素 Stream<Integer> stream = map.values().stream();
-
-
通過靜態(tài)方法創(chuàng)建:可以通過調(diào)用
Stream.of()
或Stream.iterate()
來創(chuàng)建一個包含指定元素或無限元素的流對象。-
Stream.of()
方法:Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
-
Stream.iterate()
方法:Stream<Integer> stream2 = Stream.iterate(0, n -> n + 2).limit(5);
使用
Stream.iterate()
方法創(chuàng)建了一個包含無限元素的流對象,每個元素都是由前一個元素應(yīng)用函數(shù)生成的。在這個例子中,流對象的第一個元素為0,然后每次通過應(yīng)用lambda表達(dá)式(n -> n + 2)
來生成下一個元素,即將前一個元素加上2。接著,使用
limit()
方法來限制流對象的元素?cái)?shù)量,使其只包含前5個元素。最終返回一個含有5個整數(shù)的Stream流對象。注:由于
Stream.iterate()
方法創(chuàng)建的是一個無限流對象,如果不調(diào)用limit()
方法或者其他的限制操作,那么該流對象將一直產(chǎn)生新的元素,直到程序耗盡內(nèi)存空間并拋出異常。因此,在使用Stream.iterate()
方法創(chuàng)建流對象時,一定要注意對其進(jìn)行限制,以避免程序崩潰。
-
-
通過文件創(chuàng)建:可以通過調(diào)用
Files.lines()
方法來創(chuàng)建一個文件的流對象。Path path = Paths.get("file.txt"); Stream<String> stream = Files.lines(path);
中間操作
Stream 流的中間操作是指那些對流進(jìn)行轉(zhuǎn)換、篩選、映射等操作,并返回一個新的流的操作。Stream 對象是惰性求值的,也就是說,在我們對 Stream 對象應(yīng)用終端操作之前,中間操作并不會立即執(zhí)行,只有等到終端操作觸發(fā)時才會執(zhí)行。這樣可以提高性能,避免不必要的計(jì)算。
filter 過濾
通過使用 filter()
方法,我們可以根據(jù)自定義的條件對流進(jìn)行過濾操作,只保留符合條件的元素,從而得到一個新的流。
Stream<T> filter(Predicate<? super T> predicate);
filter()
方法接受一個 Predicate(謂詞:對主語動作狀態(tài)或特征的陳述或說明)作為參數(shù),并返回一個包含滿足條件的元素的新流。
具體來說,filter()
方法會對流中的每個元素應(yīng)用給定的謂詞,如果謂詞返回 true,則該元素被包含在新流中;如果謂詞返回 false,則該元素被過濾掉:
@FunctionalInterface
public interface Predicate<T> {boolean test(T t);
}
Predicate
接口被聲明為@FunctionalInterface
,這意味著它可以用作 Lambda 表達(dá)式或方法引用的目標(biāo)。
Predicate
接口代表一個斷言,用于對給定的輸入進(jìn)行判斷。它只有一個抽象方法 test
,接受一個參數(shù)并返回一個boolean值,表示輸入是否滿足謂詞條件。
同時也意味著任何實(shí)現(xiàn)了Predicate
接口的類或 Lambda 表達(dá)式都必須實(shí)現(xiàn) test 方法,并且該方法可以在任何地方被調(diào)用或覆蓋。
以下是一個示例,演示如何使用 filter()
進(jìn)行過濾操作:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
numbers.stream().filter(n->n%2==0).forEach(System.out::println);
在上述示例中,我們首先創(chuàng)建了一個包含整數(shù)元素的列表 numbers
。然后,使用 stream()
方法將其轉(zhuǎn)換為流對象。接下來,我們調(diào)用 filter()
方法,并傳入一個謂詞 n -> n % 2 == 0
用于篩選出偶數(shù)。最后,使用 forEach()
終端操作遍歷過濾后的流,并打印每個元素。
執(zhí)行 filter 過濾操作后,流內(nèi)的元素變化如下:
map 數(shù)據(jù)轉(zhuǎn)換
Stream 接口定義的map
方法的聲明如下:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
map()
方法接受一個Function
(函數(shù))類型的參數(shù),并將流中的每個元素按照指定的映射規(guī)則進(jìn)行轉(zhuǎn)換,返回一個新的Stream
流。
@FunctionalInterface
public interface Function<T, R> {R apply(T t);
}
Function
接口中只有一個抽象方法apply(T t)
,它將一個類型為T
的參數(shù)作為輸入,并返回一個類型為R
的結(jié)果。
具體來說,map
方法將對流中的每個元素應(yīng)用提供的映射函數(shù),并將其轉(zhuǎn)換為另一種類型。最后將新類型的結(jié)果組合成一個新的流對象并返回。
注:
map
方法只會對流中的每個元素應(yīng)用映射操作,不會改變流的大小或順序。它返回的是一個新的流,因此可以鏈?zhǔn)秸{(diào)用其他的流操作方法。
以下是一個示例,演示如何使用 map()
進(jìn)行轉(zhuǎn)換操作:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
numbers.stream().map(n->"Number:"+n).forEach(System.out::println);
在上述示例中,我們創(chuàng)建了一個包含整數(shù)元素的列表 numbers
。然后,使用 stream()
方法將其轉(zhuǎn)換為流對象。接下來,我們調(diào)用 map()
方法,并傳入一個函數(shù) n -> "Number: " + n
,該函數(shù)用于將每個整數(shù)元素轉(zhuǎn)換為以 "Number: " 開頭的字符串。最后,使用 forEach()
終端操作遍歷轉(zhuǎn)換后的流,并打印每個元素。
執(zhí)行 map 轉(zhuǎn)換操作后,流的元素變化如下:
flatMap 合并流
flatMap
可以將一個流中的每個元素映射為另一個流,并將這些流合并成一個單獨(dú)的流。
具體來說,flatMap
方法接受一個將每個元素轉(zhuǎn)換為流的函數(shù),然后將所有轉(zhuǎn)換后的流合并成一個單獨(dú)的流。因此,它可以用于將嵌套的流平鋪開來。
方法簽名如下:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
示例用法如下:
List<List<Integer>> nestedList = Arrays.asList(Arrays.asList(1, 2, 3),Arrays.asList(4, 5, 6),Arrays.asList(7, 8, 9)
);nestedList.stream().flatMap(Collection::stream).forEach(System.out::println);
在上述示例中,我們有一個嵌套列表nestedList
,其中包含三個子列表。我們首先將其轉(zhuǎn)換為流,然后調(diào)用flatMap
方法,傳遞一個方法引用Collection::stream
作為映射函數(shù)。該方法引用將每個子列表轉(zhuǎn)換為一個流,并將所有的流合并成一個單獨(dú)的流。最終,我們得到了一個包含所有元素的扁平化流flattenedStream
。
執(zhí)行flatMap
轉(zhuǎn)換操作后,流的元素變化如下:
同時flatMap
方法支持?jǐn)?shù)據(jù)轉(zhuǎn)換:
List<List<Integer>> nestedList = Arrays.asList(Arrays.asList(1, 2, 3),Arrays.asList(4, 5, 6),Arrays.asList(7, 8, 9)
);nestedList.stream().flatMap(ns-> ns.stream().map(n->"Number:"+n)).forEach(System.out::println);
distinct 去重
distinct()
返回一個包含流中不重復(fù)元素的新流。新流中的元素順序與原始流中的元素順序相同。
具體來說,distinct()
方法會基于元素的 equals()
方法判斷元素是否重復(fù)。如果流中有多個元素與當(dāng)前元素相等,則只保留其中的一個元素。其他重復(fù)元素將被過濾掉。在去重過程中,保留的是第一次出現(xiàn)的元素,后續(xù)重復(fù)出現(xiàn)的元素將被忽略。
方法簽名如下:
Stream<T> distinct();
以下是一個示例,演示如何使用 distinct()
方法進(jìn)行去重操作:
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 4, 5);numbers.stream().distinct().forEach(System.out::println);
在上述示例中,我們創(chuàng)建了一個包含整數(shù)元素的列表 numbers
,其中存在重復(fù)的元素。然后,使用 stream()
方法將其轉(zhuǎn)換為流對象。接下來,我們調(diào)用 distinct()
方法,該方法會返回一個新的流,其中只包含不重復(fù)的元素。最后,使用 forEach()
終端操作遍歷去重后的流,并打印每個元素。
使用 distinct()
方法后,流的元素變化如下:
注:
distinct()
方法會基于元素的equals()
方法判斷元素是否重復(fù),因此必須保證元素的equals()
方法正確實(shí)現(xiàn),才能準(zhǔn)確判斷元素是否重復(fù)。
sorted 排序
通過調(diào)用 sorted()
方法,我們可以對流中的元素進(jìn)行排序操作。并返回一個包含按自然順序或指定比較器排序的元素的新流。
sorted()
方法有兩種重載形式:
//默認(rèn)排序規(guī)則
Stream<T> sorted();
//指定排序規(guī)則
Stream<T> sorted(Comparator<? super T> comparator);
- 若調(diào)用時不傳入任何參數(shù),則會根據(jù)元素的自然順序(即調(diào)用元素的
compareTo()
方法進(jìn)行比較)完成排序。如果流中的元素不支持自然排序(即元素類型未實(shí)現(xiàn)Comparable
接口或者實(shí)現(xiàn)了該接口但未正確實(shí)現(xiàn)compareTo()
方法),則會拋出ClassCastException
異常。 - 若調(diào)用時傳入一個比較器(Comparator)作為參數(shù),則會使用指定的比較器對元素進(jìn)行排序。
以下是兩個示例,分別演示了使用自然順序和比較器進(jìn)行排序的情況:
-
使用自然順序進(jìn)行排序:
List<Integer> numbers = Arrays.asList(5, 3, 2, 4, 1);numbers.stream().sorted().forEach(System.out::println);
在上述示例中,我們創(chuàng)建了一個包含整數(shù)元素的列表
numbers
。然后,使用stream()
方法將其轉(zhuǎn)換為流對象。接下來,我們調(diào)用sorted()
方法,該方法會返回一個新的流,其中的元素按照自然順序進(jìn)行排序。最后,使用
forEach()
終端操作遍歷排序后的流,并打印每個元素。經(jīng)過
sorted()
方法后,流的元素變化如下: -
使用比較器進(jìn)行排序:
List<Integer> numbers = Arrays.asList(5, 3, 2, 4, 1);numbers.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
在上述示例中,我們創(chuàng)建了一個包含整數(shù)元素的列表
numbers
。然后,使用stream()
方法將其轉(zhuǎn)換為流對象。接下來,我們創(chuàng)建了一個比較器reverseOrder
,該比較器會按逆序?qū)υ剡M(jìn)行排序。最后,我們調(diào)用
sorted()
方法,并傳入比較器作為參數(shù),返回一個新的流,其中的元素按照指定的比較器進(jìn)行排序。經(jīng)過
sorted()
方法后,流的元素變化如下:
注:使用
sorted()
方法對流中的元素進(jìn)行排序時,元素類型必須實(shí)現(xiàn)Comparable
接口,或者提供比較器來指定排序規(guī)則。
limit 限流
limit()
方法用于截取流中的前 n
個元素,并返回一個新的流。該方法的語法如下:
Stream<T> limit(long maxSize)
其中,maxSize
參數(shù)指定了要截取的元素個數(shù)。
注:如果輸入的流中元素的數(shù)量不足
maxSize
,則返回的新流中只包含所有元素。此外,如果maxSize
小于等于 0,或者輸入的流為空,則返回的新流也將為空。
以下是一個示例,演示了如何使用 limit()
方法對流進(jìn)行截取:
List<Integer> numbers = Arrays.asList(5, 3, 2, 4, 1);numbers.stream().limit(3).forEach(System.out::println);
在上述示例中,我們創(chuàng)建了一個包含整數(shù)元素的列表 numbers
。然后,使用 stream()
方法將其轉(zhuǎn)換為流對象。接下來,我們調(diào)用 limit(3)
方法,截取流中的前三個元素。
最后,使用 forEach()
終端操作遍歷截取后的流,并打印每個元素。
使用 limit()
方法后,流的元素變化如下:
skip 跳過
skip()
方法用于跳過流中的前 n
個元素,并返回一個新的流。該方法的語法如下:
Stream<T> skip(long n)
其中,n
參數(shù)指定了要跳過的元素個數(shù)。
注:如果輸入的流中元素的數(shù)量不足
n
,則返回的新流將為空。此外,如果n
小于等于 0,或者輸入的流為空,則返回的新流將包含原始流中的所有元素。
以下是一個示例,演示了如何使用 skip()
方法跳過流中的元素:
List<Integer> numbers = Arrays.asList(5, 3, 2, 4, 1);numbers.stream().skip(3).forEach(System.out::println);
根據(jù)你提供的代碼,創(chuàng)建了一個包含整數(shù)元素的列表 numbers
。然后,使用 stream()
方法將其轉(zhuǎn)換為流對象。接下來,我們調(diào)用 skip(3)
方法,跳過流中的前三個元素。
最后,使用 forEach()
終端操作遍歷跳過后的流,并打印每個元素。
使用 skip()
方法后,流的元素變化如下:
peek 操作
peek()
方法提供了一種在流元素處理過程中插入非終端操作的機(jī)制,即在每個元素的處理過程中執(zhí)行某些操作,例如調(diào)試、日志記錄、統(tǒng)計(jì)等。
該方法的語法如下:
Stream<T> peek(Consumer<? super T> action)
其中,action
參數(shù)是一個 Consumer 函數(shù)式接口,用于定義要在流元素處理過程中執(zhí)行的操作。對于每個元素,peek()
方法都會調(diào)用 action
函數(shù),并傳遞該元素作為參數(shù)。
以下是一個示例,演示了如何使用 peek()
方法:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);numbers.stream().filter(n -> n % 2 == 0).peek(n -> System.out.println("Found even number: " + n)).map(n -> n * 2).forEach(System.out::println);
在上述示例中,我們創(chuàng)建了一個包含整數(shù)元素的列表 numbers
。然后,我們使用 stream()
方法將其轉(zhuǎn)換為流對象。接下來,我們使用 filter()
方法過濾出所有偶數(shù),并使用 peek()
方法插入一條打印語句,以便在每個偶數(shù)被消耗時顯示一條消息。
然后,我們使用 map()
方法對每個偶數(shù)進(jìn)行乘法運(yùn)算,并最終使用 forEach()
終端操作打印每個結(jié)果。
控制臺打印結(jié)果:
Found even number: 2
4
Found even number: 4
8
使用 peek()
方法時,流的元素變化如下:
終結(jié)操作
終結(jié)操作(Terminal Operation)是 Stream 流的最后一個操作,用于觸發(fā)流的處理并產(chǎn)生最終的結(jié)果或副作用。執(zhí)行終結(jié)操作后,流將會被關(guān)閉,因此在調(diào)用終結(jié)操作之后,流將不再可用。
forEach 遍歷
forEach()
是 Stream 流的一個終端操作方法,用于對流中的每個元素執(zhí)行指定的操作。它接受一個 Consumer 函數(shù)式接口作為參數(shù),并將該操作應(yīng)用于流中的每個元素。
forEach()
方法沒有返回值,因此它只用于執(zhí)行一些針對每個元素的操作,并不能產(chǎn)生新的流或結(jié)果。
以下是 forEach()
方法的語法:
void forEach(Consumer<? super T> action)
其中,action
表示要對每個元素執(zhí)行的操作,它是一個接受一個參數(shù)并且沒有返回值的函數(shù)式接口。在Lambda表達(dá)式中,可以使用該參數(shù)執(zhí)行自定義的操作。
以下是一個示例,演示了如何使用 forEach()
方法對流中的每個元素執(zhí)行操作:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);numbers.stream().forEach(System.out::println);
首先,我們創(chuàng)建了一個包含整數(shù)元素的列表 numbers
。接下來,我們通過調(diào)用 stream()
方法將該列表轉(zhuǎn)換為一個流對象。然后,我們使用 forEach()
方法對每個元素執(zhí)行一條打印語句。
在打印語句中,我們使用了方法引用(Method Reference)的方式,即 System.out::println
,它代表了一個輸出流操作,將流中的每個元素輸出到控制臺上。也可以使用 lambda 表達(dá)式的方式,即 (x) -> System.out.println(x)
。
運(yùn)行上述代碼,控制臺輸出結(jié)果如下:
1
2
3
4
5
forEachOrdered 有序遍歷
forEachOrdered()
方法與 forEach()
方法相似,用于對流中的每個元素執(zhí)行指定的操作。但與 forEach()
不同的是,forEachOrdered()
方法能夠保證操作按照流中元素的順序依次執(zhí)行。
以下是 forEachOrdered()
方法的語法:
void forEachOrdered(Consumer<? super T> action)
其中,action
參數(shù)是一個 Consumer 函數(shù)式接口,用于定義要在每個元素上執(zhí)行的操作。對于流中的每個元素,forEachOrdered()
方法都會調(diào)用 action
函數(shù),并將該元素作為參數(shù)傳遞給它。這些操作將按照流中元素的順序依次執(zhí)行,而不是在并行流中產(chǎn)生競爭條件。
以下是一個示例,演示了如何使用 forEachOrdered()
方法對流中的每個元素執(zhí)行操作:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);numbers.parallelStream().forEachOrdered(System.out::println);
在上述示例中,我們創(chuàng)建了一個包含整數(shù)元素的列表 numbers
。然后,我們使用 parallelStream()
方法將該列表轉(zhuǎn)換為一個并行流對象。并行流允許并行處理流中的元素,以提高處理速度。
接下來,我們使用 forEachOrdered()
方法將并行流中的每個元素輸出到控制臺。
控制臺輸出結(jié)果如下:
1
2
3
4
5
由于我們在這里使用了并行流,而并行流的處理順序可能會受到多線程的調(diào)度和執(zhí)行時間的影響,因此如果使用 forEach()
方法,則打印順序可能是隨機(jī)的。但是,由于我們使用了 forEachOrdered()
方法,所以不會受到并行處理的影響,最終的輸出順序?qū)⑴c原始列表中的順序一致。
parallelStream()
并行流中的元素變化如下:
count 統(tǒng)計(jì)數(shù)量
count 用于統(tǒng)計(jì) Stream 流中元素的個數(shù)。該方法返回一個 long
類型的值,表示流中元素的數(shù)量。
count的語法如下:
long count()
它返回一個long類型的值,表示流中元素的個數(shù)。
以下是一個示例,演示了如何使用 count()
方法計(jì)算一個整數(shù)流中的元素?cái)?shù)量:
List<String> fruits = Arrays.asList("apple", "banana", "orange");// 統(tǒng)計(jì)水果的個數(shù)
long count = fruits.stream().count();System.out.println("水果的個數(shù)為:" + count);
首先我們創(chuàng)建了一個 Integer 類型的列表 numbers
。然后,通過調(diào)用 stream()
方法將列表轉(zhuǎn)換為順序流。接著,使用 count()
方法來計(jì)算順序流中的元素?cái)?shù)量,并將結(jié)果賦值給變量 count
。
最后,使用 System.out.println()
方法將計(jì)算出的元素?cái)?shù)量輸出到控制臺。
控制臺輸出結(jié)果如下:
5
注:
count()
方法只能用于非并行流或無限流。如果在并行流或無限流中調(diào)用該方法,則可能會導(dǎo)致程序掛起或陷入死循環(huán)等不良情況。
min 最小值
min()
用于獲取流中的最小值。它可以用于處理基本類型和對象類型的流。以下是 min()
方法的語法:
Optional<T> min(Comparator<? super T> comparator)
它接收一個 Comparator 對象作為參數(shù),用于確定最小值的比較方式。返回一個 Optional 對象,表示流中的最小值(如果存在)。
下面是一個示例代碼,演示了如何使用 min()
方法找到整數(shù)流中的最小值:
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9);// 找到最小值
Optional<Integer> min = numbers.stream().min(Integer::compareTo);System.out.println("最小值為:" + min.get());
上述代碼中,我們將一個包含五個整數(shù)的 List 轉(zhuǎn)換成了 Stream 流,并使用 min 方法找到流中的最小值。通過傳入 Integer 類的 compareTo 方法作為比較器,可以實(shí)現(xiàn)對整數(shù)的比較。最后,我們將結(jié)果輸出到控制臺。
經(jīng)過 min()
方法后流中的元素變化如下:
max 最大值
在 Java 中,max()
是一個流的終端操作,用于獲取流中的最大值。它可以用于處理基本類型和對象類型的流。
以下是 max()
方法的語法:
Optional<T> max(Comparator<? super T> comparator)
它接收一個 Comparator 對象作為參數(shù),用于確定最大值的比較方式。返回一個 Optional 對象,表示流中的最大值(如果存在)。
下面是一個示例代碼,演示了如何使用 max()
方法找到整數(shù)流中的最大值:
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9);// 找到最大值
Optional<Integer> max = numbers.stream().max(Integer::compareTo);System.out.println("最大值為:" + max.get());
上述代碼中,我們將一個包含五個整數(shù)的 List 轉(zhuǎn)換成了 Stream 流,并使用 max 方法找到流中的最大值。通過傳入 Integer 類的 compareTo 方法作為比較器,可以實(shí)現(xiàn)對整數(shù)的比較。最后,我們將結(jié)果輸出到控制臺。
經(jīng)過 min()
方法后流中的元素變化如下:
reduce 聚合
reduce()
用于將流中的元素進(jìn)行聚合操作,生成一個最終的結(jié)果。它可以用于處理基本類型和對象類型的流。
以下是 reduce()
方法的三種語法:
-
單個參數(shù):
Optional<T> reduce(BinaryOperator<T> accumulator)
參數(shù)含義如下:
accumulator
是一個函數(shù)接口BinaryOperator<T>
的實(shí)例,定義了一個二元操作符,用于將流中的元素逐個進(jìn)行操作。
使用這種形式的
reduce()
方法時,它會將流中的元素依次與累加器進(jìn)行操作,最終將所有元素聚合成一個結(jié)果。返回值類型是
Optional<T>
,因?yàn)槿绻鳛榭?#xff0c;沒有元素可以進(jìn)行聚合操作,此時返回的是一個空的Optional
對象。下面是一個示例代碼,演示了如何使用帶有一個參數(shù)的
reduce()
方法對整數(shù)流進(jìn)行求和操作:List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9);Optional<Integer> reduce = numbers.stream().reduce((a, b) -> a + b);System.out.println("Sum:" + reduce.get());
在上述示例中,我們首先創(chuàng)建了一個整數(shù)流
numbers
。然后,我們調(diào)用reduce()
方法來對流中的元素進(jìn)行求和操作。二元操作符使用 lambda 表達(dá)式(a, b) -> a + b
進(jìn)行相加操作。最后,打印求和結(jié)果:
Sum:25
注:
reduce()
方法默認(rèn)將流中的第一個元素作為初始化值,依次與后面的元素進(jìn)行累加器操作。 -
兩個參數(shù):
T reduce(T identity, BinaryOperator<T> accumulator)
參數(shù)含義如下:
identity
是初始值,用于處理空流的情況。accumulator
是一個函數(shù)接口BinaryOperator<T>
的實(shí)例,定義了一個二元操作符,用于將流中的元素逐個與累加器進(jìn)行操作。
使用這種形式的
reduce()
方法時,如果流中有元素,則將第一個參數(shù)作為初始值,然后依次將流中的元素與初始值進(jìn)行操作。如果流為空,則直接返回初始值。下面是一個示例代碼,演示了如何使用帶有兩個參數(shù)的
reduce()
方法對整數(shù)流進(jìn)行求和操作:List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9);Integer reduce = numbers.stream().reduce(1, Integer::sum);System.out.println("Sum:" + reduce);
在上述示例中,我們首先創(chuàng)建了一個整數(shù)流
numbers
。然后,我們調(diào)用reduce()
方法來對流中的元素進(jìn)行求和操作。初始值設(shè)置為 1,元素進(jìn)行相加操作。最后,我們將求和結(jié)果輸出到控制臺:
Sum:26
-
三個參數(shù):
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)
每個參數(shù)含義如下:
identity
是初始值,用于處理空流的情況。accumulator
是一個函數(shù)接口BiFunction<U, ? super T, U>
的實(shí)例,定義了一個二元操作符,用于將流中的元素逐個與累加器進(jìn)行操作。combiner
是一個函數(shù)接口BinaryOperator<U>
的實(shí)例,用于在并行流的情況下,將多個部分結(jié)果進(jìn)行合并。
在處理并行流時,
reduce()
方法會將流分成多個部分,并發(fā)地執(zhí)行累加操作。然后,使用combiner
函數(shù)將各個部分的結(jié)果進(jìn)行合并,最終生成一個最終的結(jié)果。下面是一個示例代碼,演示了如何使用帶有三個參數(shù)的
reduce()
方法對整數(shù)流進(jìn)行求和操作:List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9);Integer reduce = numbers.parallelStream().reduce(0, (a, b) -> a + b, Integer::sum);System.out.println("Sum:" + reduce);
在上述示例中,我們首先創(chuàng)建了一個整數(shù)流
numbers
。然后,我們調(diào)用reduce()
方法來對流中的元素進(jìn)行求和操作。初始值設(shè)置為 0,二元操作符使用 lambda 表達(dá)式(a, b) -> a + b
進(jìn)行相加操作。combiner
函數(shù)使用了方法引用Integer::sum
,用于在并行流的情況下合并部分結(jié)果。最后,我們將求和結(jié)果輸出到控制臺:
Sum:25
reduce()
方法后流中的元素變化如下:
collect 收集
collect()
方法是用于將流中的元素收集到集合或者其他數(shù)據(jù)結(jié)構(gòu)中的操作。它可以將流中的元素進(jìn)行轉(zhuǎn)換、分組、過濾等操作,并將結(jié)果存儲到指定的集合中。
collect()
方法使用 Collector
對象來定義收集操作的行為。Collector
接口提供了一系列靜態(tài)方法,可以創(chuàng)建常見的收集器實(shí)例,如 toList()
、toSet()
、toMap()
等。
以下是 collect()
方法的語法:
<R, A> R collect(Collector<? super T, A, R> collector)
這里的參數(shù)含義如下:
collector
是一個Collector
對象,用于定義收集操作的行為。
返回值類型是根據(jù)收集器的定義而確定的。
下面是一些示例代碼,展示了如何使用 collect()
方法進(jìn)行常見的收集操作:
-
將流中的元素收集到一個列表中:
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);List<Integer> numberList = numbers.collect(Collectors.toList());System.out.println("Number List: " + numberList);
-
將流中的元素收集到一個集合中:
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);Set<Integer> numberSet = numbers.collect(Collectors.toSet());System.out.println("Number Set: " + numberSet);
-
將流中的元素收集到一個映射表中:
Stream<String> names = Stream.of("Alice", "Bob", "Charlie");Map<String, Integer> nameLengthMap = names.collect(Collectors.toMap(name -> name,name -> name.length() ));System.out.println("Name Length Map: " + nameLengthMap);
anyMatch 任意匹配
anyMatch()
方法是用于檢查流中是否存在滿足指定條件的元素。它返回一個boolean
值,表示流中是否存在匹配的元素。
以下是anyMatch()
方法的語法:
boolean anyMatch(Predicate<? super T> predicate)
參數(shù)含義如下:
predicate
是一個Predicate
函數(shù)接口的實(shí)例,用于定義匹配條件。
返回值是一個boolean
值,如果流中至少有一個元素滿足predicate
定義的條件,則返回true
,否則返回false
。
下面是一個示例代碼,演示了如何使用anyMatch()
方法來檢查整數(shù)流中是否存在大于10的元素:
Stream<Integer> numbers = Stream.of(5, 8, 12, 3, 9);boolean hasNumberGreaterThanTen = numbers.anyMatch(number -> number > 10);System.out.println("Has Number Greater Than Ten: " + hasNumberGreaterThanTen);
在上述示例中,我們創(chuàng)建了一個整數(shù)流numbers
。然后調(diào)用anyMatch()
方法檢查是否存在大于10的元素。
allMatch 全匹配
allMatch()
方法用于檢查流中的所有元素是否都滿足指定的條件。它返回一個布爾值,表示流中的所有元素是否都滿足條件。
以下是 allMatch()
方法的語法:
boolean allMatch(Predicate<? super T> predicate)
參數(shù)含義如下:
predicate
是一個Predicate
函數(shù)接口的實(shí)例,用于定義匹配條件。
返回值是一個布爾值,如果流中的所有元素都滿足 predicate
定義的條件,則返回 true
,否則返回 false
。
下面是一個示例代碼,演示了如何使用 allMatch()
方法來檢查整數(shù)流中的所有元素是否都為偶數(shù):
Stream<Integer> numbers = Stream.of(2, 4, 6, 8, 10);boolean allEven = numbers.allMatch(number -> number % 2 == 0);System.out.println("All Even: " + allEven);
在上述示例中,創(chuàng)建了一個整數(shù)流 numbers
,然后調(diào)用 allMatch()
方法檢查流中的所有元素是否都為偶數(shù)。
noneMatch 全不匹配
noneMatch()
方法用于檢查流中是否沒有任何元素滿足指定的條件。它返回一個boolean值,表示流中是否不存在滿足條件的元素。
以下是noneMatch()
方法的語法:
boolean noneMatch(Predicate<? super T> predicate)
這里的參數(shù)含義如下:
predicate
是一個Predicate
函數(shù)接口的實(shí)例,用于定義匹配條件。
返回值是一個boolean值,如果流中沒有任何元素滿足predicate
定義的條件,則返回true,否則返回false。
下面是一個示例代碼,演示了如何使用noneMatch()
方法來檢查整數(shù)流中是否沒有負(fù)數(shù)元素:
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);boolean noNegativeNumbers = numbers.noneMatch(number -> number < 0);System.out.println("No Negative Numbers: " + noNegativeNumbers);
在上述示例中,創(chuàng)建了一個整數(shù)流numbers
,調(diào)用noneMatch()
方法檢查流中是否沒有負(fù)數(shù)元素。
findFirst 查找第一個
findFirst()
方法用于返回流中的第一個元素(按照流的遍歷順序)。它返回一個 Optional
對象,可以用于處理可能不存在的情況。
以下是 findFirst()
方法的語法:
Optional<T> findFirst()
返回值類型是 Optional<T>
,其中 T
是流中元素的類型。如果流為空,則返回一個空的 Optional
對象;否則,返回一個包含第一個元素的 Optional
對象。
下面是一個示例代碼,演示了如何使用 findFirst()
方法來獲取整數(shù)流中的第一個元素:
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);Optional<Integer> firstNumber = numbers.findFirst();if (firstNumber.isPresent()) {System.out.println("First Number: " + firstNumber.get());
} else {System.out.println("Stream is empty");
}
在上述示例中,創(chuàng)建了一個整數(shù)流 numbers
,調(diào)用 findFirst()
方法,返回一個 Optional
對象,表示流中的第一個元素。
findAny
findAny()
方法用于返回流中的任意一個元素。它返回一個 Optional
對象,可以用于處理可能不存在的情況。
以下是 findAny()
方法的語法:
Optional<T> findAny()
返回值類型是 Optional<T>
,其中 T
是流中元素的類型。如果流為空,則返回一個空的 Optional
對象;否則,返回一個包含任意一個元素的 Optional
對象。
findAny()
方法與 findFirst()
方法類似,但不保證返回的是流中的第一個元素,而是返回任意一個元素。這在并行流中尤為有用,因?yàn)樗梢圆⑿刑幚砹鞯牟煌糠?#xff0c;然后返回其中的任意一個元素。
下面是一個示例代碼,演示了如何使用 findAny()
方法來獲取整數(shù)流中的任意一個元素:
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);Optional<Integer> anyNumber = numbers.findAny();if (anyNumber.isPresent()) {System.out.println("Any Number: " + anyNumber.get());
} else {System.out.println("Stream is empty");
}
上述示例中,創(chuàng)建了一個整數(shù)流 numbers
,調(diào)用 findAny()
方法,返回一個 Optional
對象,表示流中的任意一個元素。