Java?Stream流以及常用方法操作實(shí)例
一、Stream流是什么?
Stream流是Java 8中的一個(gè)新特性,它提供了一種處理集合和數(shù)組的方式。Stream流可以讓我們以一種更加簡(jiǎn)潔、高效、可讀性更強(qiáng)的方式來(lái)處理數(shù)據(jù)。,這個(gè)版本新增的Stream,配合同版本出現(xiàn)的 Lambda ,給我們操作集合(Collection)提供了極大的便利。Stream流可以用于過(guò)濾、映射、排序、聚合等操作,它可以讓我們避免使用循環(huán)和條件語(yǔ)句來(lái)處理數(shù)據(jù),從而讓代碼更加簡(jiǎn)潔易懂。
那么什么是Stream?
Stream將要處理的元素集合看作一種流,在流的過(guò)程中,借助Stream API對(duì)流中的元素進(jìn)行操作,比如:篩選、排序、聚合等。是一種基于支持一次性處理數(shù)據(jù)的數(shù)據(jù)源的元素序列,流只能使用一次。
關(guān)于對(duì)Stream流的理解,你可以把他當(dāng)成工廠中的流水線(xiàn),每個(gè)stream流的操作過(guò)程遵循著創(chuàng)建 -->操作 -->獲取結(jié)果的過(guò)程,就像流水線(xiàn)上的節(jié)點(diǎn)一樣組成一個(gè)個(gè)鏈條。除此之外你還可以把他理解成sql的視圖,集合就相當(dāng)于數(shù)據(jù)表中的數(shù)據(jù),獲取stream流的過(guò)程就是確定數(shù)據(jù)表的屬性和元數(shù)據(jù)的過(guò)程,元數(shù)據(jù)的每一個(gè)元素就是表中的數(shù)據(jù),對(duì)stream流進(jìn)行操作的過(guò)程就是通過(guò)sql對(duì)這些數(shù)據(jù)進(jìn)行查找、過(guò)濾、組合、計(jì)算、操作、分組等過(guò)程,獲取結(jié)果就是sql執(zhí)行完畢之后獲取的結(jié)果視圖一樣,深入理解stream流可以讓我們使用更加簡(jiǎn)潔的代碼獲取自己想要的數(shù)據(jù)。

流的設(shè)計(jì)初衷是為了支持函數(shù)式編程,它的目的是將數(shù)據(jù)處理和數(shù)據(jù)存儲(chǔ)分離開(kāi)來(lái),使得數(shù)據(jù)處理更加靈活和高效。因此,流的元素只是在流中傳遞的臨時(shí)數(shù)據(jù),它們并不是永久存儲(chǔ)在內(nèi)存中的數(shù)據(jù)。當(dāng)流的元素被消費(fèi)后,它們就會(huì)被釋放,不能再次使用.
如果需要對(duì)同一個(gè)數(shù)據(jù)集進(jìn)行多次不同的操作,可以使用流的中間操作方法來(lái)構(gòu)建多個(gè)流管道,每個(gè)流管道都可以對(duì)流進(jìn)行不同的操作,并返回一個(gè)新的流。這樣就可以對(duì)同一個(gè)數(shù)據(jù)集進(jìn)行多次操作,而不需要重新獲取數(shù)據(jù)集。
所以說(shuō)Stream可以由數(shù)組或集合創(chuàng)建,對(duì)流的操作分為兩種:
- 中間操作,每次返回一個(gè)新的流,可以有多個(gè)。
- 終端操作,每個(gè)流只能進(jìn)行一次終端操作,終端操作結(jié)束后流無(wú)法再次使用。終端操作會(huì)產(chǎn)生一個(gè)新的集合或值。
另外,Stream有幾個(gè)特性:
- stream不存儲(chǔ)數(shù)據(jù),而是按照特定的規(guī)則對(duì)數(shù)據(jù)進(jìn)行計(jì)算,一般會(huì)輸出結(jié)果。
- stream不會(huì)改變數(shù)據(jù)源,通常情況下會(huì)產(chǎn)生一個(gè)新的集合或一個(gè)值。
- stream具有延遲執(zhí)行特性,只有調(diào)用終端操作時(shí),中間操作才會(huì)執(zhí)行。也就是說(shuō)只有等到用戶(hù)真正需要結(jié)果的時(shí)候才會(huì)執(zhí)行
二、stream的操作
2.1、stream流創(chuàng)建
獲取stream流的方式有許多種,最常用的有以下幾種:
- Collection接口的stream()或parallelStream()方法;
ArrayList<String> list=new ArrayList(); Collections.addAll(list,"a,b,c,d"); //ArrayList是Collection的實(shí)現(xiàn)類(lèi)所以可以使用Collection的stream方法 list.stream().forEach(s -> System.out.println(s)); //Stream流方法獲取數(shù)據(jù)
//map
HashMap<String,Integer> map=new HashMap<>();
map.put("aaa",111);
map.put("bbb",222);
map.put("ccc",333);
map.put("ddd",444);
//獲取Stream流
map.keySet().stream().forEach(s -> System.out.println(s));
//第二種方式
map.entrySet().stream().forEach(stringIntegerEntry -> System.out.println(stringIntegerEntry));stream和parallelStream的簡(jiǎn)單區(qū)分: stream是順序流,由主線(xiàn)程按順序?qū)α鲌?zhí)行操作,而parallelStream是并行流,內(nèi)部以多線(xiàn)程并行執(zhí)行的方式對(duì)流進(jìn)行操作,但前提是流中的數(shù)據(jù)處理沒(méi)有順序要求。例如篩選集合中的奇數(shù),兩者的處理不同之處:

- Arrays工具類(lèi)的stream()方法:Arrays.stream(arr);
//數(shù)組
int [] arr ={1,2,3,4,5};
String [] stringArr={"哈哈","哈哈哈","哈哈哈"};
//獲取stream流
Arrays.stream(arr).forEach(s-> System.out.println(s));
Arrays.stream(stringArr).forEach(s -> System.out.println(s));- 靜態(tài)的Stream.of()、Stream.empty()方法;
//零散數(shù)據(jù)stream流
Stream.of(1,2,3,4).forEach(s-> System.out.println(s));
Stream.of("6","7","8","9").forEach(s-> System.out.println(s));注:
有關(guān)of方法的使用還有List.of()、Set.of()、Map.of()的方式創(chuàng)建各種集合,其表示的含義都是不可變集合,表示不允許修改集合內(nèi)任何內(nèi)容。
Stream.of(arr)中還可以傳遞數(shù)組但必須是引用類(lèi)型的,而不是基本類(lèi)型的,比如數(shù)組類(lèi)中的stringArr,如果傳遞的是arr基本類(lèi)型數(shù)組,那么會(huì)打印一個(gè)對(duì)象地址,不符合我們想要的效果.
2.2、stream的使用
Stream流接口中定義了許多對(duì)于集合的操作方法,總的來(lái)說(shuō)可以分為兩大類(lèi):中間操作和終端操作:
- 中間操作:會(huì)返回一個(gè)流,通過(guò)這種方式可以將多個(gè)中間操作連接起來(lái),形成一個(gè)調(diào)用鏈,從而轉(zhuǎn)換為另外 一個(gè)流。除非調(diào)用鏈后存在一個(gè)終端操作,否則中間操作對(duì)流不會(huì)進(jìn)行任何結(jié)果處理。
- 終端操作:會(huì)返回一個(gè)具體的結(jié)果,如boolean、list、integer等。

2.2.1、中間操作-filter(篩選)
篩選,是按照一定的規(guī)則校驗(yàn)流中的元素,將符合條件的元素提取到新的流中的操作。

ArrayList<String> list=new ArrayList();
Collections.addAll(list,"張三豐","張二封","喬峰","傅紅雪","張三豐","喬峰");
//filter 過(guò)濾/篩選
list.stream().filter(s -> s.startsWith("張")).forEach(s -> System.out.println(s));
//運(yùn)行結(jié)果
張三豐
張二封ArrayList<Integer> arrayList=new ArrayList<>(); Collections.addAll(arrayList,1,2,3,4,6,7,8); arrayList.stream().filter(x-> x>6).forEach(x-> System.out.println(x)); //篩選出大于6的 //運(yùn)行結(jié)果 7 8
2.2.2、中間操作-limit
獲取前幾個(gè)元素,不是索引,就是單純個(gè)數(shù)。
//limit 獲取前幾個(gè)元素 與索引無(wú)關(guān) 就是單純前幾個(gè) arrayList.stream().limit(3).forEach(s-> System.out.print(s)); //運(yùn)行結(jié)果 123
2.2.3、中間操作-skip
跳過(guò)前幾個(gè)元素
//skip 跳過(guò)前幾個(gè)元素 arrayList.stream().skip(3).forEach(s-> System.out.print(s)); //運(yùn)行結(jié)果 4678
2.2.4、中間操作-distinct
元素去重,依賴(lài)于hashcode和equals方法(底層利用hashSet()方法去重)
//distinct 去重 依賴(lài)hashcode和equals方法 list.stream().distinct().forEach(s -> System.out.println(s)); //運(yùn)行結(jié)果 張三豐 張二封 喬峰 傅紅雪
2.2.5、中間操作-concat
合并兩個(gè)流:Stream.concat(stream1,stream2)
//concat 合并兩個(gè)流 Stream.concat(list.stream(),arrayList.stream()).forEach(s -> System.out.println(s)); //運(yùn)行結(jié)果 張三豐 張二封 喬峰 傅紅雪 張三豐 喬峰 1 2 3 4 6 7 8
2.2.6、中間操作-map
轉(zhuǎn)換流中數(shù)據(jù)類(lèi)型,返回一個(gè)新的流
//map 轉(zhuǎn)換流中的數(shù)據(jù)結(jié)構(gòu) arrayList.stream().map(s->String.valueOf(s)).forEach(s -> System.out.println(s)); //運(yùn)行結(jié)果 數(shù)組中整數(shù)全部轉(zhuǎn)換為了string類(lèi)型

2.2.7、終端操作-foreach
遍歷方法,終端操作表示調(diào)用該方法后不能再使用該流。
list.stream().distinct().forEach(s -> System.out.println(s));
2.2.7、終端操作-count
統(tǒng)計(jì)計(jì)數(shù)
//終端方法 foreach count() long count = list.stream().count(); System.out.println(count); //運(yùn)行結(jié)果 6
2.2.8、終端操作-toArray()
收集流中的數(shù)據(jù),放到數(shù)組中。
String[] strings = list.stream().toArray(value -> new String[value]); System.out.println(Arrays.toString(strings)); //運(yùn)行結(jié)果 [張三豐, 張二封, 喬峰, 傅紅雪, 張三豐, 喬峰]
2.2.9、終端操作-collect()
collect,收集,可以說(shuō)是內(nèi)容最繁多、功能最豐富的部分了。從字面上去理解,就是把一個(gè)流收集起來(lái),最終可以是收集成一個(gè)值也可以收集成一個(gè)新的集合。
collect主要依賴(lài)java.util.stream.Collectors類(lèi)內(nèi)置的靜態(tài)方法。
歸集(toList/toSet/toMap)
因?yàn)榱鞑淮鎯?chǔ)數(shù)據(jù),那么在流中的數(shù)據(jù)完成處理后,需要將流中的數(shù)據(jù)重新歸集到新的集合里。toList、toSet和toMap比較常用,另外還有toCollection、toConcurrentMap等復(fù)雜一些的用法。
// toList 將流中的數(shù)據(jù)轉(zhuǎn)換為一個(gè)新的集合
List<String> newList = list.stream()
.filter(s -> s.startsWith("張"))
.collect(Collectors.toList());
//運(yùn)行結(jié)果
[張三豐, 張二封, 張三豐]//toSet集合
Set<String> newSet = list.stream()
.filter(s -> s.startsWith("張"))
.collect(Collectors.toSet());
System.out.println("newSet = " + newSet);
//運(yùn)行結(jié)果
newSet = [張三豐, 張二封]統(tǒng)計(jì)(count/averaging)
Collectors提供了一系列用于數(shù)據(jù)統(tǒng)計(jì)的靜態(tài)方法:
- 計(jì)數(shù):count
- 平均值:averagingInt、averagingLong、averagingDouble
- 最值:maxBy、minBy
- 求和:summingInt、summingLong、summingDouble
- 統(tǒng)計(jì)以上所有:summarizingInt、summarizingLong、summarizingDouble
public class StreamTest {
public static void main(String[] args) {
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 23, "male", "New York"));
personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
// 求總數(shù)
Long count = personList.stream().collect(Collectors.counting());
// 求平均工資
Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
// 求最高工資
Optional<Integer> max = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare));
// 求工資之和
Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary));
// 一次性統(tǒng)計(jì)所有信息
DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
System.out.println("員工總數(shù):" + count);
System.out.println("員工平均工資:" + average);
System.out.println("員工工資總和:" + sum);
System.out.println("員工工資所有統(tǒng)計(jì):" + collect);
}
}
運(yùn)行結(jié)果:
員工總數(shù):3
員工平均工資:7900.0
員工工資總和:23700
員工工資所有統(tǒng)計(jì):DoubleSummaryStatistics{count=3, sum=23700.000000,min=7000.000000, average=7900.000000, max=8900.000000}總結(jié):

到此這篇關(guān)于Java Stream流以及常用方法的文章就介紹到這了,更多相關(guān)Java Stream流常用方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot 如何實(shí)現(xiàn)filter攔截token驗(yàn)證和跨域
這篇文章主要介紹了Springboot 如何實(shí)現(xiàn)filter攔截token驗(yàn)證和跨域操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
Java實(shí)現(xiàn)Kafka生產(chǎn)者消費(fèi)者代碼實(shí)例
這篇文章主要介紹了Java實(shí)現(xiàn)Kafka生產(chǎn)者消費(fèi)者代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
SpringBoot+RustFS 實(shí)現(xiàn)文件切片極速上傳的實(shí)例代碼
本文介紹利用SpringBoot和RustFS構(gòu)建高性能文件切片上傳系統(tǒng),實(shí)現(xiàn)大文件秒傳、斷點(diǎn)續(xù)傳和分片上傳等功能,具有一定的參考價(jià)值,感興趣的可以了解一下2025-09-09
cookie、session和java過(guò)濾器結(jié)合實(shí)現(xiàn)登陸程序
這篇文章主要為大家詳細(xì)介紹了cookie、session和java過(guò)濾器結(jié)合實(shí)現(xiàn)登陸程序的具體代碼,感興趣的朋友可以參考一下2016-05-05
java如何實(shí)現(xiàn)嵌套對(duì)象轉(zhuǎn)大map(扁平化)
這篇文章主要介紹了java如何實(shí)現(xiàn)嵌套對(duì)象轉(zhuǎn)大map(扁平化),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
springboot shardingjdbc與druid數(shù)據(jù)源沖突問(wèn)題及解決
這篇文章主要介紹了springboot shardingjdbc與druid數(shù)據(jù)源沖突問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
java數(shù)據(jù)結(jié)構(gòu)基礎(chǔ):循環(huán)鏈表和棧
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之循環(huán)鏈表、棧的實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了Java數(shù)據(jù)結(jié)構(gòu)中循環(huán)鏈表、棧、的功能、定義及使用方法,需要的朋友可以參考下2021-08-08

