1. Stream 关注的是对数据的运算,与CPU打交道
集合关注的是数据存储,与内存打交道
2.特点
(1) 自己不会存储元素
(2) 不会改变源对象。相反,他们会返回一个持有结果的新的Stream
(3) 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
3. Stream执行流程
(1) Stream实例化
(2) 一系列的中间操作(过滤、映射...)
(3) 终止操作
4. 说明
(1) 一个中间操作链,对数据源的数据进行处理
(2) 一旦执行终止操作,就执行中间操作链,共产生结果。之后,不会再被使用
数据准备
Employee类
- public class Employee {
-
- private int id;
- private String name;
- private int age;
- private double salary;
-
- public Employee(int id, String name, int age, double salary) {
-
- this.id = id;
- this.name = name;
- this.age = age;
- this.salary = salary;
- }
-
- public Employee() {
-
- }
-
- public int getId() {
- return id;
- }
-
- public void setId(int id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getAge() {
- return age;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- public double getSalary() {
- return salary;
- }
-
- public void setSalary(double salary) {
- this.salary = salary;
- }
-
- @Override
- public String toString() {
- return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + "]";
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + age;
- result = prime * result + id;
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- long temp;
- temp = Double.doubleToLongBits(salary);
- result = prime * result + (int) (temp ^ (temp >>> 32));
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Employee other = (Employee) obj;
- if (age != other.age)
- return false;
- if (id != other.id)
- return false;
- if (name == null) {
- if (other.name != null)
- return false;
- } else if (!name.equals(other.name))
- return false;
- if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
- return false;
- return true;
- }
-
-
-
- }
EmployeeData
- import java.util.ArrayList;
- import java.util.List;
-
- public class EmployeeData {
-
- public static List<Employee> getEmployee(){
- List<Employee> list=new ArrayList<>();
-
- list.add(new Employee(1001,"马化腾",34,6000.38));
- list.add(new Employee(1002,"马云",12,9876.12));
- list.add(new Employee(1003,"刘强东",34,3000.82));
- list.add(new Employee(1004,"雷军",26,7657.37));
- list.add(new Employee(1005,"李彦宏",65,5555.32));
- list.add(new Employee(1006,"比尔盖茨",42,9500.43));
- list.add(new Employee(1007,"任正非",26,4333.32));
- list.add(new Employee(1008,"扎克伯格",35,2500.32));
-
- return list;
- }
- }
Stream的实例化方法
- public class StreamAPITest {
-
- /**
- * 测试Stream的实例化
- */
- // 创建Stream 方式一: 通过集合
- public void test1() {
- List<Employee> employees= EmployeeData.getEmployee();
-
- // default Stream<E> stream() : 返回一个顺序流
- Stream<Employee> stream = employees.stream();
-
- // default Stream<E> parallelStream(): 返回一个并行流
- Stream<Employee> parallelStream = employees.parallelStream();
- }
-
- //创建 Stream 方式二: 通过数组
- @Test
- public void test2() {
- int [] arr = {1,2,3,4,5,6};
- //调用Arrays类的static<T> Stream<T> stream (T [] array) :返回一个流
- IntStream stream = Arrays.stream(arr);
-
- Employee e1 = new Employee(100,"Tom", 0, 0);
- Employee e2 = new Employee(100,"Tom", 0, 0);
-
- Employee [] arr2 = {e1,e2};
- Stream<Employee> stream2= Arrays.stream(arr2);
- }
-
- //创建Stream方式三:通过Stream的of()
- @Test
- public void test3() {
- Stream<Integer> stream=Stream.of(1,2,3,4,5,6);
- }
-
- //创建Stream方式四: 创建无限流
- @Test
- public void test4() {
- //遍历前10个偶数
- Stream.iterate(0, t->t+2).limit(10).forEach(System.out::println);
- System.out.println("------------------");
-
- //打印10个随机小数
- Stream.generate(Math::random).limit(10).forEach(i->System.out.println(i));
- }
- }
Stream的中间操作
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.List;
- import java.util.stream.Stream;
-
- import org.junit.jupiter.api.Test;
-
- public class StreamAPITest2 {
-
- /**
- * 测试Stream的中间操作
- */
- // 1. 筛选和切片
- @Test
- public void test1() {
- List<Employee> list=EmployeeData.getEmployee();
-
- System.out.println("---------filter------");
- // filter(Predicate p) ----接收 Lambda,从流中排除某些元素
- Stream<Employee> stream=list.stream();
- // 练习:查询员工表中,员工工资大于7000的员工信息
- stream.filter(e -> e.getSalary()>7000).forEach(i->System.out.println(i));
-
- System.out.println("------limit(n)--------");
-
- //limit(n) 截断流 ,使其元素不超过给定数量
- list.stream().limit(3).forEach(System.out::println);
-
- System.out.println("----skip(n)------");
-
- // skip(n) --跳过元素,返回一个扔掉了前n个元素的流
- list.stream().skip(3).forEach(i->System.out.println(i));
-
- //distinct() --筛选,通过流所生成元素的hasnCode()和equals() 去除重复元素
- System.out.println("-------------------distinct-------------");
- list.add(new Employee(1010,"刘强东",40,8000));
- list.add(new Employee(1010,"刘强东",40,8000));
- list.add(new Employee(1010,"刘强东",40,8000));
- list.add(new Employee(1010,"刘强东",40,8000));
- list.add(new Employee(1010,"刘强东",40,8000));
- list.add(new Employee(1010,"刘强东",40,8000));
-
- list.stream().distinct().forEach(i->System.out.println(i));
- }
-
- //映射
- @Test
- public void test2() {
- //map (function f) --接收一个函数作为参数,将元素转换为其他形式或提取信息
- List<String> list = Arrays.asList("aa","bb","cc","dd");
- list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
-
- //练习:获取员工姓名长度大于3的员工姓名
- System.out.println("---------nameStreamFilter----------");
- List<Employee> employees = EmployeeData.getEmployee();
- Stream<String> nameStream = employees.stream().map(e -> e.getName());
- nameStream.filter(name -> name.length()>3).forEach(System.out::println);;
-
- System.out.println("------------");
- //flatMap(Function f) -- 接收一个函数作为参数,将流中的每个值换位另一个流,然后把所有的流连成一个流
- Stream<Character> charStream = list.stream().flatMap(StreamAPITest2::fromStringToStream);
- charStream.forEach(System.out::println);
- }
-
- //将字符串中的多个字符串构成的集合转换为对应的Stream实例
- public static Stream<Character> fromStringToStream(String str){
- ArrayList<Character> list= new ArrayList<>();
- for(Character c:str.toCharArray()) {
- list.add(c);
- }
- return list.stream();
- }
-
- //3--排序
- @Test
- public void test4() {
- //sorted--自然排序
- System.out.println("----sorted--------");
- List<Integer> list = Arrays.asList(12,43,65,34,87,0,-98,7);
- list.stream().sorted().forEach(System.out::println);
-
- //sorted(Compare com) -- 定制排序
- System.out.println("------sorted(com)-----");
- List<Employee> employees = EmployeeData.getEmployee();
- employees.stream().sorted( (e1,e2)->{
- return (e1.getAge()-e2.getAge());
- } ).forEach(System.out::println);
- }
-
- }
测试终止植操作
- import java.util.List;
- import java.util.Optional;
- import java.util.stream.Stream;
-
- import org.junit.jupiter.api.Test;
-
- /**
- * 测试终止操作
- * @author CharlieLiang
- *
- */
- public class StreamAPITest3 {
-
- //1-- 匹配与查找
- @Test
- public void test1() {
- List<Employee> employees = EmployeeData.getEmployee();
- //allMath(Predicate p) -- 检查是否匹配所有元素
- // 练习:是否所有员工的年龄都大于18
- System.out.println("-------allMath----------");
- boolean allMath= employees.stream().allMatch( e -> e.getAge()>10);
- System.out.println(allMath);
-
- System.out.println("--------anyMatch----------");
- //anyMatch(Predicate p) -- 检查是否至少匹配一个袁术
- //练习:是否存在员工工资大于10000
- boolean anyMatch = employees.stream().anyMatch( e -> e.getSalary()>1000);
- System.out.println(anyMatch);
-
- System.out.println("----noneMath-------");
- //练习: 是否不存在员工姓雷
- boolean noneMath = employees.stream().noneMatch( e -> e.getName().startsWith("雷"));
- System.out.println(noneMath);
-
- System.out.println("------findFirst------");
- Optional<Employee> firstEmployee = employees.stream().findFirst();
- System.out.println(firstEmployee);
-
- System.out.println("--------findAny-----------");
- Optional<Employee> findAny = employees.parallelStream().findAny();
- System.out.println(findAny);
- }
-
-
- @Test
- public void test2() {
- List<Employee> employees = EmployeeData.getEmployee();
- // count -- 返回流中元素的总个数
- System.out.println("---------count-----------");
- long count = employees.stream().filter( e -> e.getSalary()>5000).count();
- System.out.println(count);
-
- // 练习返回最高工资
- System.out.println("--------max--------");
- Stream<Double> salaryStream = employees.stream().map( e -> e.getSalary());
- Optional<Double> maxSalary = salaryStream.max(
- (s1,s2) -> {
- return (int) (s1-s2);
- }
- );
- System.out.println(maxSalary);
-
- System.out.println("--------max2------");
- Stream<Double> salaryStream2 = employees.stream().map( e -> e.getSalary());
- Optional<Double> maxSalary2 = salaryStream2.max(Double::compare);
- System.out.println(maxSalary2);
-
- // 返回最低工资的员工
- System.out.println("---min---");
- Optional<Employee> minSalaryEmployee =
- employees.stream().min( (e1,e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
- System.out.println(minSalaryEmployee);
-
- //forEach (Consumer c) --- 内部迭代
- employees.stream().forEach(i -> System.out.println(i));
-
- // 或者
- // employees.forEach(System.out::println);
- }
- }
- import java.util.Arrays;
- import java.util.List;
- import java.util.Optional;
- import java.util.stream.Stream;
-
- import org.junit.jupiter.api.Test;
- /**
- * 归约测试
- * @author CharlieLiang
- *
- */
- public class StreamAPITest4 {
-
-
- @Test
- public void test1() {
- //reduce (T identity, BinaryOperator) -- 可以将流中的元素反复结合起来,得到一个值。返回T
- // 练习计算1-10的自然数的和
- System.out.println("----reduce-----");
- List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
- // 0: 表示初始值是0
- Integer sum = list.stream().reduce(0 , Integer::sum);
- System.out.println(sum);
-
- System.out.println("---reduce2----");
-
- List<Integer> list2 = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
- // 0: 表示初始值是0
- Integer sum2 = list2.stream().reduce(0 , (a,b) -> (a+b));
- System.out.println(sum2);
-
-
- System.out.println("-----reduce(Optional T)---");
- // reduce(BinaryOperator b)--可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
- List<Employee> employees = EmployeeData.getEmployee();
- Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
- Optional<Double> salarySum = salaryStream.reduce(Double::sum);
- System.out.println(salarySum);
-
- System.out.println("-----reduce(Optional T)2---");
- Stream<Double> salaryStream2 = employees.stream().map(Employee::getSalary);
- Optional<Double> salarySum2 = salaryStream2.reduce((a,b) -> (a+b) );
- System.out.println(salarySum2);
- }
- }
- import java.util.List;
- import java.util.Set;
- import java.util.stream.Collectors;
-
- import org.junit.jupiter.api.Test;
-
- /**
- * 收集测试
- * @author CharlieLiang
- *
- */
- public class StreamAPITest5 {
-
- @Test
- public void test1() {
- // collect(Collector c) -- 将流转化为其他形式。接收一个Collector接口的实现,
- // 用于给Stream中元素做汇总的方法
- //练习:查找工资大于6000的员工,结果返回一个List或Set
- System.out.println("---toList----");
- List<Employee> employees = EmployeeData.getEmployee();
- List<Employee> empList = employees.stream().filter( e -> e.getSalary()>6000).collect(Collectors.toList());
- empList.forEach(System.out::println);
-
- System.out.println("---toSet----");
- Set<Employee> empSet = employees.stream().filter( e -> e.getSalary()>6000).collect(Collectors.toSet());
- empSet.forEach( i -> System.out.println(i));
- }
- }
Optional类的使用
Optional类: 为了在程序中避免出现空指针异常而创建的
常用的方法 : ofNullable(T t)
ofElse(T t)
girl类
- public class Girl {
-
- private String name;
-
- public Girl(String name) {
-
- this.name = name;
- }
-
- public Girl() {
-
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- @Override
- public String toString() {
- return "Girl [name=" + name + "]";
- }
-
- }
Boy类
- public class Boy {
-
- private Girl girl;
-
- public Boy(Girl girl) {
- this.girl = girl;
- }
-
- public Boy() {
-
- }
-
- public Girl getGirl() {
- return girl;
- }
-
- public void setGirl(Girl girl) {
- this.girl = girl;
- }
-
- @Override
- public String toString() {
- return "Boy [girl=" + girl + "]";
- }
-
- }
测试类
- import java.util.Optional;
-
- import org.junit.jupiter.api.Test;
-
- /**
- * Optional类: 为了在程序中避免出现空指针异常而创建的
- * 常用的方法 : ofNullable(T t)
- * ofElse(T t)
- * @author CharlieLiang
- *
- */
- public class OptionTest {
-
- /**
- * Option.of(T t): 创建一个Optional实例,t必须非空
- * Optional.empty(): 创建一个空的Optional实例
- * Optional.ofNullable(T t): t可以为null
- */
-
- @Test
- public void test1() {
- Girl girl = new Girl();
- Optional<Girl> optionalGirl = Optional.of(girl);
- System.out.println(optionalGirl);
- }
- // ----------------------------
- @Test
- public void test2() {
- Girl girl = new Girl();
- Optional<Girl> optionalGirl = Optional.ofNullable(girl);
- System.out.println(optionalGirl);
-
- System.out.println("---------");
-
- Girl girl2 = null;
- Optional<Girl> optionalGirl2 = Optional.ofNullable(girl2);
- System.out.println(optionalGirl2);
-
- System.out.println("--------");
-
- //orElse(T t1) : 如果当前的Optional内部封装的t是非空的,则返回内部的t
- // 如果内部的t是空的,则返回orElse() 方法中的参数t1
- Girl girl3 = optionalGirl2.orElse( new Girl("小梅"));
- System.out.println(girl3);
- }
- // -----------------------------------
- public String getGirlName(Boy boy) {
- return boy.getGirl().getName();
- }
-
- @Test
- public void test3() {
- Boy boy = new Boy();
- String girlName = getGirlName(boy);
- System.out.println(girlName);
- }
- // ----------------------------------
-
-
- // 优化以后的版本
- public String getGirlName2(Boy boy) {
- if(boy != null ) {
- Girl girl=boy.getGirl();
- if(girl != null) return girl.getName();
- }
- return null;
- }
-
- @Test
- public void test4() {
- Boy boy = new Boy();
- String girlName = getGirlName2(boy);
- System.out.println(girlName);
- }
- // ------------------------------------
-
- // 使用Optinal类getGirlName():
- public String getGirlName3(Boy boy) {
- Optional<Boy> boyOptional = Optional.ofNullable(boy);
- // 此时boy2一定非空
- Boy boy2 = boyOptional.orElse(new Boy(new Girl("大梅")));
-
- Girl girl=boy2.getGirl();
- Optional<Girl> girlOptional = Optional.ofNullable(girl);
- // girl2 一定非空
- Girl girl2 = girlOptional.orElse(new Girl("小娟"));
-
- return girl2.getName();
- }
-
- @Test
- public void test5() {
- Boy boy = null;
- String girlName = getGirlName3(boy);
- System.out.println(girlName);
-
- System.out.println("---------");
-
- Boy boy2 = new Boy();
- String str= getGirlName3(boy2);
- System.out.println(str);
-
- System.out.println("----------");
-
- Boy boy3 = new Boy( new Girl("陈老师") );
- String strChen= getGirlName3(boy3);
- System.out.println(strChen);
- }
-
- }
NullPointerException