本文是向大家介紹:Java8特性之Stream流的原理和日常使用,可以直觀的理解Stream流操作和玩轉(zhuǎn)集合
1骨稿、什么是 Stream
1.1乖坠、 簡(jiǎn)介
? ? ? ? java8新添加了一個(gè)特性:流Stream薄榛。Stream和I/O流不同,它更像具有Iterable的集合類勒极,但行為和集合類又有所不同,它是對(duì)集合對(duì)象功能的增強(qiáng)虑鼎,讓開發(fā)者能夠以一種聲明的方式處理數(shù)據(jù)源(集合辱匿、數(shù)組等),它專注于對(duì)數(shù)據(jù)源進(jìn)行各種高效的聚合操作(aggregate operation)和大批量數(shù)據(jù)操作 (bulk data operation)炫彩。
? ? ? 舉個(gè)例子匾七,只要給出需要對(duì)其包含的元素執(zhí)行什么操作,比如 “過濾掉長(zhǎng)度大于 10 的字符串”江兢、“獲取每個(gè)字符串的首字母”等昨忆,Stream 會(huì)隱式地在內(nèi)部進(jìn)行遍歷,做出相應(yīng)的數(shù)據(jù)轉(zhuǎn)換杉允。
? ? ? ? Stream是一種對(duì) Java 集合運(yùn)算和表達(dá)的高階抽象邑贴。Stream API將處理的數(shù)據(jù)源看做一種Stream(流),Stream(流)在Pipeline(管道)中傳輸和運(yùn)算叔磷,支持的運(yùn)算包含篩選拢驾、排序、聚合等世澜,當(dāng)?shù)竭_(dá)終點(diǎn)后便得到最終的處理結(jié)果独旷。
幾個(gè)關(guān)鍵概念:
元素 Stream是一個(gè)來自數(shù)據(jù)源的元素隊(duì)列,Stream本身并不存儲(chǔ)元素。
數(shù)據(jù)源(即Stream的來源)包含集合嵌洼、數(shù)組案疲、I/O channel、generator(發(fā)生器)等麻养。
聚合操作 類似SQL中的filter褐啡、map、find鳖昌、match备畦、sorted等操作
管道運(yùn)算 Stream在Pipeline中運(yùn)算后返回Stream對(duì)象本身,這樣多個(gè)操作串聯(lián)成一個(gè)Pipeline许昨,并形成fluent風(fēng)格的代碼懂盐。這種方式可以優(yōu)化操作,如延遲執(zhí)行(laziness)和短路( short-circuiting)糕档。
內(nèi)部迭代 不同于java8以前對(duì)集合的遍歷方式(外部迭代)莉恼,Stream API采用訪問者模式(Visitor)實(shí)現(xiàn)了內(nèi)部迭代。
并行運(yùn)算 Stream API支持串行(stream() )或并行(parallelStream() )的兩種操作方式速那。
1.2俐银、 Stream API的特點(diǎn)以及類型:
? (1)Stream API的使用和同樣是java8新特性的lambda表達(dá)式密不可分,可以大大提高編碼效率和代碼可讀性端仰。
? (2)Stream API提供串行和并行兩種操作捶惜,其中并行操作能發(fā)揮多核處理器的優(yōu)勢(shì),使用fork/join的方式進(jìn)行并行操作以提高運(yùn)行速度荔烧。
? (3)Stream API進(jìn)行并行操作無需編寫多線程代碼即可寫出高效的并發(fā)程序吱七,且通常可避免多線程代碼出錯(cuò)的問題鹤竭。
和以前的Collection操作不同陪捷, Stream操作有兩個(gè)基礎(chǔ)的特征:
? ? ? Pipelining: 中間操作都會(huì)返回流對(duì)象本身。 這樣多個(gè)操作可以串聯(lián)成一個(gè)管道诺擅, 如同流式風(fēng)格(fluent style)市袖。 這樣做可以對(duì)操作進(jìn)行優(yōu)化, 比如延遲執(zhí)行(laziness)和短路( short-circuiting)烁涌。
? ? ? 內(nèi)部迭代: 以前對(duì)集合遍歷都是通過Iterator或者For-Each的方式, 顯式的在集合外部進(jìn)行迭代苍碟, 這叫做外部迭代。 Stream提供了內(nèi)部迭代的方式撮执, 通過訪問者模式(Visitor)實(shí)現(xiàn)微峰。
流的操作可以分為:
? ? 中間操作(Intermediate Operations)
無狀態(tài)(Stateless)操作:每個(gè)數(shù)據(jù)的處理是獨(dú)立的,不會(huì)影響或依賴之前的數(shù)據(jù)抒钱。如filter()蜓肆、flatMap()颜凯、flatMapToDouble()、flatMapToInt()仗扬、flatMapToLong()症概、map()、mapToDouble()早芭、mapToInt()彼城、mapToLong()、peek()退个、unordered() 等募壕;
有狀態(tài)(Stateful)操作:處理時(shí)會(huì)記錄狀態(tài),比如處理了幾個(gè)语盈。后面元素的處理會(huì)依賴前面記錄的狀態(tài)舱馅,或者拿到所有元素才能繼續(xù)下去。如distinct()刀荒、sorted()习柠、sorted(comparator)、limit()照棋、skip() 等;
? ? ? 終止操作(Terminal Operations)
非短路操作:處理完所有數(shù)據(jù)才能得到結(jié)果武翎。如collect()烈炭、count()、forEach()宝恶、forEachOrdered()符隙、max()、min()垫毙、reduce()霹疫、toArray()等;
短路(short-circuiting)操作:拿到符合預(yù)期的結(jié)果就會(huì)停下來综芥,不一定會(huì)處理完所有數(shù)據(jù)丽蝎。如anyMatch()、allMatch()膀藐、noneMatch()屠阻、findFirst()、findAny() 等额各。
2国觉、源碼分析
2.1、結(jié)構(gòu)圖如下:
2.2虾啦、源碼分析如下:
其中麻诀,Stream是一個(gè)接口痕寓,沒有操作的默認(rèn)實(shí)現(xiàn)方式。最主要的實(shí)現(xiàn)類是ReferencePipeline蝇闭,它繼承自AbstractPipline呻率,而AbstractPipline實(shí)現(xiàn)了BaseStream接口。ReferencePipeline內(nèi)部定義了三個(gè)靜態(tài)內(nèi)部類丁眼,包括:輸入流的Head筷凤、無狀態(tài)中間操作StablessOp、有狀態(tài)StatfulOp苞七,但之后Head不是抽象類藐守。
2.2.1ReferencePipeline的理解
Stream只是一個(gè)接口,并沒有操作的缺省實(shí)現(xiàn)蹂风。最主要的實(shí)現(xiàn)是ReferencePipeline和AbstractPipeline完成的卢厂。
定義:
abstract class ReferencePipeline<P_IN, P_OUT>
extends AbstractPipeline<P_IN, P_OUT, Stream<P_OUT>>
implements Stream<P_OUT>? {}
ReferencePipeline類幾乎實(shí)現(xiàn)了所有的Stream中間操作和最終操作,這里挑選一些典型的代碼進(jìn)行分析惠啄。
先看看其中的三個(gè)重要的內(nèi)部類慎恒。控制數(shù)據(jù)流入的 Head 撵渡,中間操作 StatelessOp融柬,StatefulOp。
Head是ReferencePipeline數(shù)據(jù)源趋距,其實(shí)內(nèi)部就是一個(gè)集合的并行迭代器粒氧。
? ? static class Head<E_IN, E_OUT> extends ReferencePipeline<E_IN, E_OUT> {
? ? ? ? // 構(gòu)造器,數(shù)據(jù)源類型需要進(jìn)程自Spliterator
? ? ? ? Head(Supplier<? extends Spliterator<?>> source,
? ? ? ? ? ? int sourceFlags, boolean parallel) {
? ? ? ? ? ? super(source, sourceFlags, parallel);
? ? ? ? }
? ? ? ? // 構(gòu)造器节腐,數(shù)據(jù)源類型就是Spliterator
? ? ? ? Head(Spliterator<?> source,
? ? ? ? ? ? int sourceFlags, boolean parallel) {
? ? ? ? ? ? super(source, sourceFlags, parallel);
? ? ? ? }
? ? ? ? @Override
? ? ? ? final boolean opIsStateful() {
? ? ? ? ? ? throw new UnsupportedOperationException();
? ? ? ? }
? ? ? ? @Override
? ? ? ? final Sink<E_IN> opWrapSink(int flags, Sink<E_OUT> sink) {
? ? ? ? ? ? throw new UnsupportedOperationException();
? ? ? ? }
? ? ? ? // Optimized sequential terminal operations for the head of the pipeline
? ? ? ? @Override
? ? ? ? public void forEach(Consumer<? super E_OUT> action) {
? ? ? ? ? ? if (!isParallel()) {
? ? ? ? ? ? ? ? sourceStageSpliterator().forEachRemaining(action);
? ? ? ? ? ? }
? ? ? ? ? ? else {
? ? ? ? ? ? ? ? super.forEach(action);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void forEachOrdered(Consumer<? super E_OUT> action) {
? ? ? ? ? ? if (!isParallel()) {
? ? ? ? ? ? ? ? sourceStageSpliterator().forEachRemaining(action);
? ? ? ? ? ? }
? ? ? ? ? ? else {
? ? ? ? ? ? ? ? super.forEachOrdered(action);
? ? ? ? ? ? }
? ? ? ? }
? ? }
無狀態(tài)的鏈?zhǔn)郊庸ね舛ⅲ瑫?huì)返回一個(gè)StatelessOp對(duì)象,有狀態(tài)的加工操作會(huì)返回一個(gè)StatefulOp對(duì)象翼雀。
? ? abstract static class StatelessOp<E_IN, E_OUT>
? ? ? ? ? ? extends ReferencePipeline<E_IN, E_OUT> {
? ? ? // 構(gòu)造器饱苟,就是將當(dāng)前的中間操作和舊的Stream組合成一個(gè)新的Stream,返回新的Stream狼渊,實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用
? ? ? ? StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
? ? ? ? ? ? ? ? ? ? StreamShape inputShape,
? ? ? ? ? ? ? ? ? ? int opFlags) {
? ? ? ? ? ? super(upstream, opFlags);
? ? ? ? ? ? assert upstream.getOutputShape() == inputShape;
? ? ? ? }
? ? ? ? @Override
? ? ? ? final boolean opIsStateful() {
? ? ? ? ? ? return false;
? ? ? ? }
? ? }
? ? abstract static class StatefulOp<E_IN, E_OUT>
? ? ? ? ? ? extends ReferencePipeline<E_IN, E_OUT> {
// 構(gòu)造器箱熬,和上面一樣
? ? ? ? StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
? ? ? ? ? ? ? ? ? StreamShape inputShape,
? ? ? ? ? ? ? ? ? int opFlags) {
? ? ? ? ? ? super(upstream, opFlags);
? ? ? ? ? ? assert upstream.getOutputShape() == inputShape;
? ? ? ? }
? ? ? ? @Override
? ? ? ? final boolean opIsStateful() {
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? @Override
? ? ? ? abstract <P_IN> Node<E_OUT> opEvaluateParallel(PipelineHelper<E_OUT> helper,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Spliterator<P_IN> spliterator,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IntFunction<E_OUT[]> generator);
? ? }
2.2.2.無狀態(tài)的中間操作
? ? public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
? ? ? ? Objects.requireNonNull(predicate);
? ? ? ? return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? StreamOpFlag.NOT_SIZED) {
? ? ? ? ? ? @Override
? ? ? ? ? ? Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
? ? ? ? ? ? ? ? return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? public void begin(long size) {
? ? ? ? ? ? ? ? ? ? ? ? downstream.begin(-1);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? public void accept(P_OUT u) {
? ? ? ? ? ? ? ? ? ? ? ? if (predicate.test(u))
? ? ? ? ? ? ? ? ? ? ? ? ? ? downstream.accept(u);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? };
? ? ? ? ? ? }
? ? ? ? };
? ? }
可以看到這個(gè)操作只是返回一個(gè)StatelessOp對(duì)象(此類依然繼承于ReferencePipeline),它的一個(gè)回調(diào)函數(shù)opWrapSink會(huì)返回一個(gè)Sink對(duì)象鏈表狈邑。
Sink代表管道操作的每一個(gè)階段坦弟, 比如本例的filter階段。 在調(diào)用accept之前官地,先調(diào)用begin通知數(shù)據(jù)來了酿傍,數(shù)據(jù)發(fā)送后調(diào)用end。
? ? public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
? ? ? ? Objects.requireNonNull(mapper);
? ? ? ? return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
? ? ? ? ? ? @Override
? ? ? ? ? ? Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
? ? ? ? ? ? ? ? return new Sink.ChainedReference<P_OUT, R>(sink) {
? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? public void accept(P_OUT u) {
? ? ? ? ? ? ? ? ? ? ? ? downstream.accept(mapper.apply(u));
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? };
? ? ? ? ? ? }
? ? ? ? };
? ? }
stream.filter(....).map(...)怎么形成一個(gè)鏈的驱入?
filter返回一個(gè)StatelessOp,我們記為StatelessOp1, 而map返回另外一個(gè)StatelessOp赤炒,我們記為StatelessOp2氯析。在調(diào)用StatelessOp1.map時(shí), StatelessOp2是這樣生成的:return new StatelessOp<P_OUT, R>(StatelessOp1,......);莺褒,管道中每個(gè)階段的Stream保留前一個(gè)流的引用掩缓。
2.2.3有狀態(tài)的中間操作
? ? @Override
? ? public final Stream<P_OUT> distinct() {
? ? ? ? return DistinctOps.makeRef(this);
? ? }
? ? @Override
? ? public final Stream<P_OUT> sorted() {
? ? ? ? return SortedOps.makeRef(this);
? ? }
不管無狀態(tài)還是有狀態(tài)的中間操作都為返回一個(gè)StatelessOp或者StatefulOp傳遞給下一個(gè)操作,有點(diǎn)像設(shè)計(jì)模式中的職責(zé)鏈模式遵岩。
2.2.4.最終操作
public final long count() {
? ? ? ? return mapToLong(e -> 1L).sum();
? ? }
? ? @Override
? ? public final LongStream mapToLong(ToLongFunction<? super P_OUT> mapper) {
? ? ? ? Objects.requireNonNull(mapper);
? ? ? ? return new LongPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
? ? ? ? ? ? @Override
? ? ? ? ? ? Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
? ? ? ? ? ? ? ? return new Sink.ChainedReference<P_OUT, Long>(sink) {
? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? public void accept(P_OUT u) {
? ? ? ? ? ? ? ? ? ? ? ? downstream.accept(mapper.applyAsLong(u));
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? };
? ? ? ? ? ? }
? ? ? ? };
? ? }
Stream中的最終操作都是惰性的你辣,是如何實(shí)現(xiàn)的呢。
首先找到最后一個(gè)操作尘执,也就是最終操作舍哄, 執(zhí)行它的opWrapSink,事實(shí)上得到一個(gè)鏈表誊锭,最終返回第一個(gè)Sink, 執(zhí)行第一個(gè)Sink的accept將觸發(fā)鏈?zhǔn)讲僮鳎?將管道中的操作在一個(gè)迭代中執(zhí)行一次表悬。
事實(shí)上Java是將所有的操作形成一個(gè)類似鏈接的結(jié)構(gòu)(通過Sink的downstream,upstream),在遇到最終操作時(shí)觸發(fā)鏈?zhǔn)椒磻?yīng), 通過各種數(shù)據(jù)類型特定的spliterator的一次迭代最終得到結(jié)果丧靡。
并行操作是通過ForkJoinTask框架實(shí)現(xiàn)蟆沫。
2.3、源碼總結(jié)
其實(shí)還是可以把Stream的源碼過程當(dāng)成流水線來理解温治。
? ? ? ? (1)流水線的入口饭庞,也就是數(shù)據(jù)源,每個(gè)Stream具有一個(gè)Head內(nèi)部對(duì)象熬荆,而Head中就是一個(gè)集合spliterator舟山,通過迭代依次輸出一個(gè)個(gè)數(shù)據(jù)。常用的集合都實(shí)現(xiàn)了 Spliterator 接口以支持 Stream惶看。可以這樣理解六孵,Spliterator 定義了數(shù)據(jù)集合流入流水線的方式纬黎。
? ? ? (2) 流水線的中間操作組裝,不管是有狀態(tài)的還是無狀態(tài)的劫窒,都會(huì)返回一個(gè)包含了上一個(gè)節(jié)點(diǎn)引用的中間節(jié)點(diǎn)本今,就這樣把一個(gè)個(gè)中間操作拼接到了控制數(shù)據(jù)流入口的Head后面,但是并沒有開始所任何數(shù)據(jù)處理主巍。
? ? ? (3) 啟動(dòng)流水線冠息,在最后一個(gè)操作的時(shí)候回溯鏈表, 并調(diào)用Spliterator的forEachRemaining方法進(jìn)行一次遍歷孕索, 每訪問一個(gè)數(shù)組的元素就會(huì)從頭開始調(diào)用鏈表的每個(gè)節(jié)點(diǎn)逛艰。
3、Stream流結(jié)合Lambda表達(dá)式的使用
3.1搞旭、Stream創(chuàng)建流
(1)散怖、調(diào)用.stream()方法直接返回流:
? public static void test() {
? ? ? ? List<Student> students = StudentData.getStudents();
? ? ? ? Stream<Student> stream = students.stream();//第一種:返回一個(gè)順序流
? ? ? ? Stream<Student> stream1 = students.parallelStream();//第二種:返回一個(gè)并行流
? ? }
(2)Arrays.stream() 方法創(chuàng)建
//通過一個(gè)數(shù)組創(chuàng)建stream
public static void test(){
? ? //獲取一個(gè)整型stream
? ? int []arr={1,34,2,54,56,34};
? ? IntStream stream = Arrays.stream(arr );
}
(3)stream.of方式創(chuàng)建
? public static void test(){
? ? ? ? Stream<String> stringStream =Stream .of("1","4","34","23");
? ? ? ? Stream<Student>studentStream =Stream .of(new Student(1,"book",23,89.5),
? ? ? ? ? ? ? ? new Student(2,"cack",22,90.9));
? ? }
3.2菇绵、Stream流使用之中間操作
? (1)、filter:接收 Lambda 镇眷, 從流中排除某些元素咬最。
Arrays.asList(1, 2, 3, 4, 5).stream().filter(x->x%2==0).collect(Collectors.toList());
(2)、distinct:篩選欠动,通過流所生成元素的 hashCode() 和 equals() 去除重復(fù)元素永乌。
Arrays.asList(1,2,3,4,5,6,7,7,7,7).stream().distinct().collect(Collectors.toList());
(3)、sorted:集合中的元素排序并且是倒序
Arrays.asList(1,2,3,4,5,6).stream().sorted((a,b)->b-a).collect(Collectors.toList());
(4)具伍、limit:截?cái)嗔鞒岢蛊湓夭怀^給定數(shù)量。3
Arrays.asList(1,2,3,4,5,6,7).stream().limit().collect(Collectors.toList());
(5)沿猜、skip:跳過元素枚荣,返回一個(gè)扔掉了前 n 個(gè)元素的流。若流中元素不足 n 個(gè)啼肩,則返回一個(gè)空流橄妆。與 limit(n) 互補(bǔ)
Arrays.asList(1,2,3,3,4,5).stream().skip(1).collect(Collectors.toList());
(6)、map:接收Lambda祈坠,將元素轉(zhuǎn)換成其他形式或提取信息害碾。接收一個(gè)函數(shù)作為參數(shù),該函數(shù)會(huì)被應(yīng)用到每個(gè)元素上赦拘,并將其映射成一個(gè)新的元素慌随。
Arrays.asList("1","2","3","5").stream().map(x->Integer.valueOf(x)).collect(Collectors.toList());
(7)、peek:類似于打印日志的功能在進(jìn)行操作時(shí)查看當(dāng)前值
Arrays.asList("1","2","3","5").stream().peek(System.out::println).collect(Collectors.toList());
3.3躺同、Stream流使用之終止操作
(1)阁猜、allMatch–檢查是否匹配所有元素
List<Student> list=StudentData.getStudents() ;
//判斷所有的學(xué)生年齡是否都大于20歲
boolean allMatch=list.stream() .allMatch(student ->student .getAge() >20);
(2)、anyMatch–檢查是否至少匹配一個(gè)元素
List<Student> list=StudentData.getStudents() ;
//判斷是否存在學(xué)生的年齡大于20歲
boolean anyMatch=list .stream() .anyMatch(student ->student .getAge() >20);
(3)蹋艺、noneMatch–檢查是否沒有匹配所有元素
List<Student> list=StudentData.getStudents() ;
//判斷是否不存在學(xué)生叫小白
boolean noneMatch=list .stream() .noneMatch(student ->student .getName() .equals("小白") );
(4)剃袍、findFirst–返回第一個(gè)元素
List<Student> list=StudentData.getStudents() ;
//查找第一個(gè)學(xué)生
Optional<Student>first=list .stream().findFirst() ;
(5)、findAny–返回當(dāng)前流中的任意元素
List<Student> list=StudentData.getStudents() ;
//查找當(dāng)前流中的元素
Optional <Student>any=list .stream().findAny() ;
(6)捎谨、count–返回流中元素的總個(gè)數(shù)
List<Student> list=StudentData.getStudents() ;
//查找所有的學(xué)生數(shù)量
long count=list .stream() .filter(student->student .getAge() >20).count() ;
(7)民效、max–返回流中最大值
//查找學(xué)生的最高分?jǐn)?shù)
Stream <Double >doubleStream =list .stream() .map(student ->student .getScore() );
Optional <Double > max=doubleStream .max(Double::compareTo );
? ? ? ? System.out.println(max );
(8)、min–返回流中最小值
List<Student> list=StudentData.getStudents() ;
Stream <Double >doubleStream =list .stream() .map(student ->student .getScore() );
Optional <Double > max=doubleStream .min(Double::compareTo );
(9)涛救、歸約
reduce–歸約操作可以將流中元素反復(fù)結(jié)合起來畏邢,得到一個(gè)值
public static void test(){
? ? ? //計(jì)算數(shù)的總和
? ? ? List<Integer >list =Arrays .asList(4,5,6,1,8,9,2,3,7) ;
? ? ? Integer reduce=list .stream() .reduce(0,Integer::sum );
? ? ? System.out.println(reduce );
? ? ? //計(jì)算學(xué)生總分
? ? ? ? List <Student >students =StudentData .getStudents() ;
? ? ? ? Stream <Double >doubleStream =students .stream() .map(Student::getScore );
? ? ? ? Optional <Double >reduce1=doubleStream .reduce(Double ::sum );
? ? ? ? System.out.println(reduce1 .get() );
? ? }
(10)、收集
collect:將流轉(zhuǎn)換為其他形式检吆,接收一個(gè)Collector接口實(shí)現(xiàn)舒萎,用于給Stream中匯總的方法
? public static void test(){
? ? ? ? //返回一個(gè)list
? ? ? ? List <Student >students =StudentData .getStudents() ;
? ? ? ? List <Student >list =students .stream() .filter(student ->student .getScore() >88).collect(Collectors.toList()) ;
? ? ? ? //返回一個(gè)set
? ? ? ? Set <Student >set =students .stream() .filter(s->s.getAge() >23).collect(Collectors.toSet()) ;
? ? }