一、什么是Stream流

Stream是java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤、映射数据等操作,使用Stream API对集合数据进行操作就类似使用SQL执行数据库查询。也可以使用Stream API来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

集合讲的是数据,流讲的是计算

注意:

  • Stream自己不会存储元素
  • Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream
  • Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才会去执行

二、Stream操作的三个步骤

1、创建Stream

一个数据源,获取一个流

package com.xuzhi.stream;/*** Author: 徐志* Date: 2020/8/1 15:20*/import com.xuzhi.entity.Employee;
import org.junit.Test;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;/*** Stream操作的三个步骤* 1.创建Stream* 2.中间操作* 3.终止操作*/
public class TestStreamAPI1 {//1.创建Stream的几种方式@Testpublic void test1(){//1.可以通过Collection系列集合提供的stream()或者parallelStream()List<String> list=new ArrayList<>();Stream<String> stream1=list.stream();//2.通过Arrays中的静态方法获取数组流Employee[] emps=new Employee[10];Stream<Employee> stream2= Arrays.stream(emps);//3.通过Stream中的静态方法of()创建Stream<String> stream3 = Stream.of("aa", "dd", "dd", "ddddd");//4.创建无限流Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);stream4.limit(10).forEach(System.out::println);Stream.generate(()->Math.random()).limit(5).forEach(System.out::println);}
}

2、中间操作

一个中间操作链,对数据源的数据进行处理
注意:多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”

package com.xuzhi.stream;/*** Author: 徐志* Date: 2020/8/1 15:33*/import com.xuzhi.entity.Employee;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;/*** 中间操作* 筛选和切片* filter--接收Lambda,从流中排出某些元素* limit--截断流,使其元素不超过给定 的数量* skip(n)--跳过元素,返回一个扔掉了前n个元素的流,若流中的元素不足n个,则返回一个空流* distinct---筛选,通过流所产生的hashCode和equals()去除重复元素*/
public class TestStreamAPI2 {List<Employee> employees= Arrays.asList(new Employee("张三",18,9999.99),new Employee("李四",38,5555.99),new Employee("王五",50,6666.99),new Employee("赵六",16,3333.99),new Employee("田七",8,7777.99));//内部迭代@Testpublic void test1(){employees.stream().filter((e)->e.getAge()>35).forEach(System.out::println);}//外部迭代@Testpublic void test2(){Iterator<Employee> it=employees.iterator();while (it.hasNext()){System.out.println(it.next());}}@Testpublic void test3(){employees.stream().filter((e)->e.getSalary()>5000).limit(2).forEach(System.out::println);}@Testpublic void test4(){employees.stream().filter((e)->e.getSalary()>5000).skip(2).forEach(System.out::println);}/*** 映射* map--接收lambda,将元素转换成其他形式获取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素* flatMap--接收一个函数作为参数,将流中的每一个值换成另一个流,然后把所有的流连成一个流**/@Testpublic void test5(){List<String> list=Arrays.asList("aaa","bbb","ccccc","ddd","ee");list.stream().map((str)->str.toUpperCase()).forEach(System.out::println);employees.stream().map(Employee::getName).forEach(System.out::println);/**--------------------------------------------**/Stream<Stream<Character>> stream=list.stream().map(TestStreamAPI2::filterCharacter);stream.forEach((sm)->{sm.forEach(System.out::println);});/**--------------------------------------------**/list.stream().flatMap(TestStreamAPI2::filterCharacter).forEach(System.out::println);}public static Stream<Character> filterCharacter(String str){List<Character> list=new ArrayList<>();for (Character c:str.toCharArray()) {list.add(c);}return list.stream();}/*** 排序* sorted()--自然排序* sorted(Comparator com)**/@Testpublic void test7(){List<String> list=Arrays.asList("aa","ddd","dddf","rfgg");list.stream().sorted().forEach(System.out::println);employees.stream().sorted((e1,e2)->{if(e1.getAge()==e2.getAge()){return e1.getName().compareTo(e2.getName());}else{return Integer.compare(e1.getAge(),e2.getAge());}}).forEach(System.out::println);}
}

map和flatMap的区别
在讲解mapflatMap的区别之前,先来看看集合中add()和addALL()方法的区别

@Testpublic void test(){List list1=new ArrayList();List list2=new ArrayList();List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);list1.add(1);list1.add(2);list1.add(list);System.out.println(list1.toString());list2.add(1);list2.add(2);list2.addAll(list);System.out.println(list2.toString());}

运行结果

使用add()方法,他会将集合当做元素插入进集合当中,而addAll()而是将此集合中的元素插入。

map和flatMap与之类似,遇到同样的情况,map会返回一个Stream的集合,集合里面又有一个Stream的集合,二flatMap不会

3、终止操作

一个终止的操作,执行中间操作链,并产生结果

package com.xuzhi.stream;/*** Author: 徐志* Date: 2020/8/2 8:11*/import com.xuzhi.entity.Employee;
import org.junit.Test;import java.util.*;
import java.util.stream.Collectors;/*** 终止操作*/
public class TestStreamAPI3 {List<Employee> employees= Arrays.asList(new Employee("张三",18,9999.99),new Employee("李四",38,5555.99),new Employee("王五",50,6666.99),new Employee("赵六",16,3333.99),new Employee("田七",18,7777.99));/*查找与匹配allMatch--检查是否匹配所有的元素anyMatch--检查是否至少匹配一个元素noneMatch--检查是否没有匹配所有元素findFirst--返回第一个元素findAny--返回当前流中的任意元素count--返回流中元素的总个数max--返回流中的最大值min--返回流中的最小值*/@Testpublic void  test1(){boolean b1 = employees.stream().allMatch((e) -> e.getAge() == 18);System.out.println(b1);boolean b2 = employees.stream().anyMatch((e) -> e.getAge() == 18);System.out.println(b2);boolean b3 = employees.stream().noneMatch((e) -> e.getAge() == 18);System.out.println(b3);Optional<Employee> first = employees.stream().sorted((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary())).findFirst();System.out.println(first.get());Optional<Employee> any = employees.stream().sorted().findAny();System.out.println(any.get());}@Testpublic void test2(){long count = employees.stream().count();System.out.println(count);Optional<Employee> max = employees.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));System.out.println(max.get());Optional<Double> min = employees.stream().map(Employee::getSalary).min(Double::compare);System.out.println(min.get());}/*** 规约* reduce--可以将流中的元素反复结合起来,得到一个值*/@Testpublic void test3(){List<Integer> list=Arrays.asList(1,2,3,4,5,6,7,8,9,0);Integer reduce = list.stream().reduce(0, (x, y) -> x + y);System.out.println(reduce);Optional<Double> reduce1 = employees.stream().map(Employee::getSalary).reduce(Double::sum);}/*** 收集** collect--将流转换成其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法*/@Testpublic void test4(){List<String> collect = employees.stream().map(Employee::getName).collect(Collectors.toList());collect.forEach(System.out::println);Set<Double> collect1 = employees.stream().map(Employee::getSalary).collect(Collectors.toSet());collect1.forEach(System.out::println);HashSet<String> collect2 = employees.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));collect2.forEach(System.out::println);}@Testpublic void test5(){Long collect = employees.stream().collect(Collectors.counting());System.out.println(collect);Double collect1 = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary));System.out.println(collect1);Double collect2 = employees.stream().collect(Collectors.summingDouble(Employee::getSalary));System.out.println(collect2);Optional<Employee> collect3 = employees.stream().collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));System.out.println(collect3.get());}//分组@Testpublic void test6(){Map<Integer, List<Employee>> collect = employees.stream().collect(Collectors.groupingBy(Employee::getAge));System.out.println(collect);}//分区@Testpublic void test8(){Map<Boolean, List<Employee>> collect = employees.stream().collect(Collectors.partitioningBy((e) -> e.getSalary() > 6000));System.out.println(collect);}@Testpublic void test9(){DoubleSummaryStatistics collect = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary));System.out.println(collect.getMax());}//连接@Testpublic void test10(){String collect = employees.stream().map(Employee::getName).collect(Collectors.joining(","));System.out.println(collect);}
}

三、小练习

package com.xuzhi.stream;import com.xuzhi.entity.Employee;
import org.junit.Test;import java.util.Arrays;
import java.util.List;
import java.util.Optional;/*** Author: 徐志* Date: 2020/8/2 10:33*/
public class Zuoye {/*** 给定一个数字列表,如何返回一个由每个数的平方组成的列表* 给定【1,2,3,4,5】,应该返回【1,4,9,16,25】*/@Testpublic void test1(){Integer[] nums=new Integer[]{1,2,3,4,5};Arrays.stream(nums).map((x)->x*x).forEach(System.out::println);}/*** 怎样用map+reduce数出有多少个Employee*/List<Employee> employees= Arrays.asList(new Employee("张三",18,9999.99),new Employee("李四",38,5555.99),new Employee("王五",50,6666.99),new Employee("赵六",16,3333.99),new Employee("田七",8,7777.99));public void test2(){Optional<Integer> reduce = employees.stream().map((e) -> 1).reduce(Integer::sum);System.out.println(reduce.get());}}

四、并行流和顺序流

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流

java8中将并行进行了优化,我们可以很容易的对数据进行并行操作,StreamAPI可以声明性地通过parallel()与sequential()在并行流与顺序流之间进行切换

  • ForkJoinCalculate.java
package com.xuzhi.forkJoin;import java.util.concurrent.RecursiveTask;/*** Author: 徐志* Date: 2020/8/2 11:20*//**使用ForkJoin框架必须继承RecursiveAction或者RecursiveTask。两者的区别是RecursiveTask有返回值,RecursiveAction没有返回值*/
public class ForkJoinCalculate extends RecursiveTask<Long> {private static final long serialVersionUID=233224555L;private long start;private long end;private static final long THREADHOLD=10000;public ForkJoinCalculate(long start,long end){this.start=start;this.end=end;}@Overrideprotected Long compute() {long length=end-start;if(length<=THREADHOLD){long sum=0;for (long i=start;i<=end;i++){sum+=i;}return sum;}else{long mid=(start+end)/2;ForkJoinCalculate left=new ForkJoinCalculate(start,mid);left.fork();ForkJoinCalculate right=new ForkJoinCalculate(mid+1,end);right.fork();return left.join()+right.join();}}
}
  • TestForkJoin.java
package com.xuzhi.forkJoin;import org.junit.Test;import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;/*** Author: 徐志* Date: 2020/8/2 11:29*/
public class TestForkJoin {/*
使用ForkJoin
*/@Testpublic void test1(){Instant startTime = Instant.now();ForkJoinPool pool=new ForkJoinPool();ForkJoinTask<Long> task=new ForkJoinCalculate(0,100000000L);Long sum=pool.invoke(task);System.out.println(sum);Instant endTime = Instant.now();System.out.println(Duration.between(startTime, endTime).toMillis());}/*
传统的for循环
*/@Testpublic void test2(){Instant startTime = Instant.now();long sum=0L;for (long i = 0; i <=100000000L; i++) {sum+=i;}System.out.println(sum);Instant endTime = Instant.now();System.out.println(Duration.between(startTime, endTime).toMillis());}//java8并行流public void test3(){Instant startTime = Instant.now();LongStream.rangeClosed(0,100000000L).parallel().reduce(0,Long::sum);Instant endTime = Instant.now();System.out.println(Duration.between(startTime, endTime).toMillis());}
}

使用forkJoin框架或者并行流都是为了充分利用CPU的资源,当数据量过小的时候,for循环会比其他两种方式块,当数据量较大时,并行流的优势就提现出来了

五、Optional

Optional<T>类是一个容器类,代表一个值存在或者不存在,原来使用Null表示一个值不存在,现在Optional可以更好的表达这个概念,并且可以避免空指针异常

常用方法:

  • Optional.of(T t):创建一个Optional实例
  • Optional.empty():创建一个空的Optional实例
  • Optional.ofNullable(T t):若t不为null,创建Optional实例,否则则创建空实例
  • isPresent():判断是否包含值
  • orElse(T t):如果调用 的对象包含值,返回该值,否则返回t
  • orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回s获取的值
  • map(Function f):如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
  • flatMap(Function mapper):与map类似,要求返回值必须是Optional
package com.xuzhi.optional;import com.xuzhi.entity.Employee;
import org.junit.Test;import java.util.Optional;/*** Author: 徐志* Date: 2020/8/2 14:53*/
public class TestOptional {@Testpublic void test1(){//不能为nullOptional<Employee> op=Optional.of(new Employee());Employee employee = op.get();System.out.println(employee);}@Testpublic void test2(){Optional<Employee> op = Optional.empty();System.out.println(op.get());}@Testpublic void test3(){//有值就获取,没值就什么都不做Optional<Employee> op = Optional.ofNullable(null);/* if (op.isPresent()){System.out.println(op.get());}*/Employee employee = op.orElse(new Employee("李四", 66, 99999));System.out.println(employee);Employee employee1 = op.orElseGet(() -> new Employee());System.out.println(employee1);}@Testpublic void test4(){Optional<Employee> dd = Optional.ofNullable(new Employee("dd", 33, 4343));/*  Optional<String> s = dd.map((e) -> e.getName());System.out.println(s.get());*/Optional<String> s = dd.flatMap((e) -> Optional.of(e.getName()));System.out.println(s);}
}

六、总结

本人观看的学习资料为B站尚硅谷教学视频。简单的学习了解了Stream流操作集合的强大,过去对集合中的元素进行操作可能需要写比较复杂的代码,现在通过Stream流配合lambda表达式,实现一些功能实在是太轻松了。附上本人微信公众号二维码,欢迎一起交流学习

java8新特性之Stream流相关推荐

  1. 使用Java8新特性(stream流、Lambda表达式)实现多个List 的笛卡尔乘积 返回需要的List<JavaBean>

    需求分析: 有两个Long类型的集合 : List<Long> tagsIds; List<Long> attributesIds; 现在需要将这两个Long类型的集合进行组合 ...

  2. java stream byte_乐字节-Java8新特性之Stream流(上)

    上一篇文章,小乐给大家介绍了<Java8新特性之方法引用>,下面接下来小乐将会给大家介绍Java8新特性之Stream,称之为流,本篇文章为上半部分. 1.什么是流? Java Se中对于 ...

  3. Java8新特性-使用Stream流来实现递归遍历树形结构(案例)

    Java8新特性-Stream流 可能平常会遇到一些需求,比如构建菜单,构建树形结构,数据库一般就使用父id来表示,为了降低数据库的查询压力,我们可以使用Java8中的Stream流一次性把数据查出来 ...

  4. Java8新特性之Stream流式编程

    特地感谢鲁班大叔的分享,原学习地址:Java8 Stream流式编程爱 撸码就是快,流式编程好 代码传家宝 以下是学习过程整理的笔记 1.简介 Stream 流处理,首先要澄清的是 java8 中的 ...

  5. Java8新特性之Stream流的使用

    Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找.过滤.筛选等操作,在新版的JPA中,也已经加入了Stream. 1.Stream的操作步骤 Stream有如下三个操 ...

  6. JAVA8新特性之Stream流分组

    Apple apple01 = new Apple(1, "red", 100, "成都");Apple apple02 = new Apple(2, &quo ...

  7. 跟我学 Java 8 新特性之 Stream 流(七)流与迭代器,流系列大结局

    转载自   跟我学 Java 8 新特性之 Stream 流(七)流与迭代器,流系列大结局 恭喜你们,马上就要学完Java8 Stream流的一整系列了,其实我相信Stream流对很多使用Java的同 ...

  8. 跟我学 Java 8 新特性之 Stream 流基础体验

    转载自   跟我学 Java 8 新特性之 Stream 流基础体验 Java8新增的功能中,要数lambda表达式和流API最为重要了.这篇文章主要介绍流API的基础,也是流API系列的第一篇文章, ...

  9. 【java8新特性】——Stream API详解(二)

    一.简介 java8新添加了一个特性:流Stream.Stream让开发者能够以一种声明的方式处理数据源(集合.数组等),它专注于对数据源进行各种高效的聚合操作(aggregate operation ...

最新文章

  1. java中数组的含义_数组
  2. CVPR NTIRE 2022|双目超分辨率挑战赛开赛
  3. iOS 自定义 View
  4. 【Android 应用开发】BluetoothServerSocket详解
  5. 全球最大保险公司之一Ace推出一亿美元网络安全险
  6. pandas fillna_【Python基础】快速提升效率的6个pandas使用小技巧
  7. 《MS SQL Server 2000管理员手册》系列——8. 管理 Microsoft SQL Server 服务
  8. 牛客14386 水仙花数
  9. java 原子量Atomic举例(AtomicReference)
  10. android 显示canvas,【报Bug】部分情况下,安卓canvas不显示
  11. php arsort函数,php-常用函数
  12. 取色器ColorPix
  13. 大数据项目实战——基于某招聘网站进行数据采集及数据分析(五)
  14. WIN7各种系统大全
  15. QLV转MP4格式转换器在线免费的方法有哪些
  16. windows7 telnet服务开启和登录授权
  17. delphi里面奇奇怪怪的函数真多。。
  18. python爬虫练习高清壁纸【王者荣耀高清壁纸】python爬虫
  19. c++ 迭代公式:使用用迭代公式X(n+1)=(Xn+a/Xn) /2 (n=0,2···;x0=a/2)编程求某一正数a的平方根
  20. 医疗dcm格式图像解析成bmp格式图片

热门文章

  1. 小红伞AntiVir专区
  2. 《开源之迷》有哪些迷?怎么解?
  3. 《口算大作战 概念版》功能规格说明书
  4. 宠物购物领养社区app(IDEA,SpringBoot,SSM,MySQL)+全套视频教程
  5. 惠普电脑如何重装Linux系统,如何把惠普下的Linux操作系统换为windows 7
  6. SAP 可配置BOM创建
  7. 蓝牙核心技术概述: 蓝牙协议规范(射频、基带链路控制、链路管理)
  8. iPhone12基带确认,果粉放心
  9. 使用百度API获取地名坐标信息
  10. GO 基础语法50问