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)成工廠中的流水線,每個(gè)stream流的操作過(guò)程遵循著創(chuàng)建 -->操作 -->獲取結(jié)果的過(guò)程,就像流水線上的節(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ǔ)分離開來(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ō)只有等到用戶真正需要結(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)類所以可以使用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是順序流,由主線程按順序?qū)α鲌?zhí)行操作,而parallelStream是并行流,內(nèi)部以多線程并行執(zhí)行的方式對(duì)流進(jìn)行操作,但前提是流中的數(shù)據(jù)處理沒(méi)有順序要求。例如篩選集合中的奇數(shù),兩者的處理不同之處:

- Arrays工具類的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ù)組但必須是引用類型的,而不是基本類型的,比如數(shù)組類中的stringArr,如果傳遞的是arr基本類型數(shù)組,那么會(huì)打印一個(gè)對(duì)象地址,不符合我們想要的效果.
2.2、stream的使用
Stream流接口中定義了許多對(duì)于集合的操作方法,總的來(lái)說(shuō)可以分為兩大類:中間操作和終端操作:
- 中間操作:會(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
元素去重,依賴于hashcode和equals方法(底層利用hashSet()方法去重)
//distinct 去重 依賴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ù)類型,返回一個(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類型

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主要依賴java.util.stream.Collectors類內(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)文章
Spring Security中的Servlet過(guò)濾器體系代碼分析
這篇文章主要介紹了Spring Security中的Servlet過(guò)濾器體系,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07
java實(shí)現(xiàn)最短路徑算法之Dijkstra算法
這篇文章主要介紹了java實(shí)現(xiàn)最短路徑算法之Dijkstra算法, Dijkstra算法是最短路徑算法中為人熟知的一種,是單起點(diǎn)全路徑算法,有興趣的可以了解一下2017-10-10
關(guān)于重寫equals()方法和hashCode()方法及其簡(jiǎn)單的應(yīng)用
這篇文章主要介紹了關(guān)于重寫equals()方法和hashCode()方法及其簡(jiǎn)單的應(yīng)用,網(wǎng)上的知識(shí)有些可能是錯(cuò)誤的,關(guān)于?equals()?方法的理解,大家討論不一樣,需要的朋友可以參考下2023-04-04
java動(dòng)態(tài)口令登錄實(shí)現(xiàn)過(guò)程詳解
這篇文章主要介紹了java動(dòng)態(tài)口令登錄實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
Java實(shí)現(xiàn)餅圖旋轉(zhuǎn)角度的代碼詳解
在現(xiàn)代數(shù)據(jù)可視化領(lǐng)域,餅圖因其直觀展示各部分占整體比例而被廣泛采用,為了增強(qiáng)互動(dòng)性和吸引力,常會(huì)賦予餅圖 旋轉(zhuǎn) 動(dòng)畫:自動(dòng)、平滑地旋轉(zhuǎn),讓用戶從不同角度重點(diǎn)查看扇區(qū),本文將從零開始,手把手實(shí)現(xiàn)一個(gè) Java2D Swing 版 的 可旋轉(zhuǎn)餅圖組件,需要的朋友可以參考下2025-05-05

