Day.36 Java 8新特性: Stream API、Optional 类

目录

强大的Stream API

一、创建流

二、中间操作

1.筛选与切片 

2.映射

3.排序 

三、终止操作

1.匹配与查找

2. 归约

3. 收集 --- Collectors类

Stream常用方法

Optional 类

使用Optional类优化


强大的Stream API

  • Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API

  • Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

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

为什么要是用 Stream API?

  • 实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数据源可以更多了,有MongDB,Radis等,而这些NoSQL的数据就需要Java层面去处理。

  • Stream 和 Collection 集合的区别:Collection 是一种静态的内存数据结构,主要面向内存,存储在内存中。Stream 是有关计算的,主要是面向 CPU,通过 CPU 实现计算

Day.36 Java 8新特性: Stream API、Optional 类_第1张图片

Day.36 Java 8新特性: Stream API、Optional 类_第2张图片

  1. Stream关注的是对数据的运算,与CPU打交道 集合关注的是数据的存储,与内存打交道

  2. ①Stream 自己不会存储元素。

    ②Stream 不会改变源对象。每次处理都会返回一个持有结果的新Stream。

    ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

  3. Stream 执行流程
    ① Stream的实例化
    ② 一系列的中间操作(过滤、映射、...)
    ③ 终止操作

  4. 说明
    ①一个中间操作链,对数据源的数据进行处理
    ②一旦执行终止操作,就执行中间操作链,并产生结果。之后,此Stream不能再被使用

一、创建流

static  Stream concat(Stream a, Stream b)

创建一个懒惰连接的流,其元素是第一个流的所有元素,后跟第二个流的所有元素。(可以合并两个集合)

static  Stream of(T... values)

通过显示值创建一个流。它可以接收任意数量的参数。返回一个顺序流

  • 代码
public class StreamAPITest {

    //创建 Stream方式一: 通过集合
    @Test
    public void test1(){
        List employees = EmployeeData.getEmployees();

//      default Stream stream() : 返回一个顺序流
        Stream stream = employees.stream();

//      default Stream parallelStream() : 返回一个并行流(多线程)
        Stream parallelStream = stream.parallel();
    }

    //创建 Stream方式二:通过数组
    @Test
    public void test2(){
        int[] arr = new int[]{1,2,3,4,5,6};
//      调用Arrays类static  Stream stream(T[] array): 返回一个流
        IntStream stream = Arrays.stream(arr);

        Employee e1 = new Employee(1001,"Tom");
        Employee e2 = new Employee(1002,"Jerry");
        Employee[] arr1 = new Employee[]{e1,e2};
        Stream stream1 = Arrays.stream(arr1);
    }

    //创建 Stream方式三:通过Stream的of(

    @Test
    public void test3(){
        Stream stream = Stream.of(1, 2, 3, 4, 5, 6);
    }

    //创建 Stream方式四:创建无限流(较少使用)
    @Test
    public void test4(){
        //迭代
        //public static Stream iterate(final T seed, final UnaryOperator f)
        //遍历前10个偶数
        Stream.iterate(0,t -> t+2).limit(10).forEach(System.out::println);

        //生成
        //public static Stream generate(Supplier s)
        Stream.generate((Math::random)).limit(10).forEach(System.out::println);;
    }
}

二、中间操作

1.筛选与切片 

 Day.36 Java 8新特性: Stream API、Optional 类_第3张图片

Stream filter(Predicate p)

接收 Lambda , 从流中排除某些元素,保留符合条件的元素

Stream distinct()

筛选,通过流所生成元素的equals() 去除重复元素

Stream limit(long maxSize)

截断流,使其元素不超过给定数量

Stream

skip(long n)

跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补

  •  代码
/*
* 测试Stream的中间操作
*
* */
public class StreamAPITest1 {

    // 1- 筛选与切片
    @Test
    public void test1() {

        List list = EmployeeData.getEmployees();

//      filter(Predicate p) --- 接受Lambda,从流中排除某些元素。
        Stream stream = list.stream();
        //查询员工表中薪资大于7000的员工信息

        stream.filter(new Predicate() {
            @Override
            public boolean test(Employee e) {
                return e.getSalary()>7000;
            }
        }).forEach(System.out::println);

        //stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println);

        System.out.println("-------------------------");

//      limit(n) --- 截断流,使其元素不超过给定数量。
        //限制输出前5个元素 list.stream():之前的流已被终止,生成一个新的Stream
        list.stream().limit(5).forEach(System.out::println);

        System.out.println("-------------------------");
//      skip(n) --- 跳过元素,返回一个扔掉了前 n 个元素的流。若流中的元素不足 n 个,则返回一个空流。与limit(n)互补。
        //跳过前三个数据
        list.stream().skip(3).forEach(System.out::println);

        System.out.println("-------------------------");
//      distinct()-- 筛选,通过流锁生成元素的hashCode() 和equals()去除重复元素
        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));
        //System.out.println(list);

        list.stream().distinct().forEach(System.out::println);
    }
}

2.映射

Day.36 Java 8新特性: Stream API、Optional 类_第4张图片

 Stream map(Function f)

接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

DoubleStream mapToDouble(ToDoubleFunction f)

接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。

IntStream mapToInt(ToIntFunction f)

接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。

LongStream mapToLong(ToLongFunction f)

接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。

 Stream flatMap(Function f)

接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

Stream peek(Consumer action) 可以使用foreack查看中间的数据,只能有一个终止操作

接收Lambda,对流中的每个数据执行Lambda体操作

  •  代码
    @Test// 2- 映射
    public void test2(){
        //map(Function f)
        //接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
        List list = Arrays.asList("aa", "bb", "cc", "dd");
        //将字符串转换为大写
        list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);

        System.out.println("-------------------------");

        //练习1: 获取员工姓名长度大于3的员工名字
        List employees = EmployeeData.getEmployees();
        Stream namsStream = employees.stream().map(e -> e.getName());   //获取全部员工名字 的string
        namsStream.filter(name -> name.length() > 3).forEach(System.out :: println);    //获取长度大于3

        System.out.println("-------------------------");

        //练习2: Map 实现 flatMap 功能(悲壮) 类似for嵌套for
        Stream> streamStream = list.stream().map(StreamAPITest1::fromStringToStream);
        streamStream.forEach(s ->{
            s.forEach(System.out::println);
        });

        System.out.println("-------------------------");

        //flatMap(Function f)   理解参考test3
        //接受一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
        Stream characterStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);
        characterStream.forEach(System.out::println);
    }
    //将字符串中的多个字符构成的集合转换为对应的Stream的实例
    public static Stream fromStringToStream(String str){
        ArrayList list = new ArrayList<>();
        for(Character c : str.toCharArray()){
            list.add(c);
        }
        return list.stream();

    }
    @Test
    public void test3(){
        ArrayList list1 = new ArrayList();
        list1.add(1);
        list1.add(2);
        list1.add(3);

        ArrayList list2 = new ArrayList();
        list2.add(4);
        list2.add(5);
        list2.add(6);

        //list1.add(list2); //4元素
        list1.addAll(list2);    //6元素
        System.out.println(list1);
    }

3.排序 

Day.36 Java 8新特性: Stream API、Optional 类_第5张图片

Stream sorted()

产生一个新流,其中按自然顺序排序。

Stream sorted(Comparator com)

产生一个新流,其中按比较器顺序排序

    // 3- 排序
    @Test
    public void test4(){
        //sorted() -- 自然排序
        List list = Arrays.asList(12, 43, 65, 34, 87, 0, -98, 7);
        list.stream().sorted().forEach(System.out::println);

        //抛异常,原因: EmployeeData 没有实现 Comparable接口
//        List employees = EmployeeData.getEmployees();
//        employees.stream().sorted().forEach(System.out::println);

        //sorted(Comparator com) -- 定制排序
        List employees = EmployeeData.getEmployees();
        /*employees.stream().sorted((e1,e2) -> {
            return Integer.compare(e1.getAge(),e2.getAge());
        }).forEach(System.out::println);*/
        employees.stream().sorted((e1,e2) -> Integer.compare(e1.getAge(),e2.getAge()))
                .forEach(System.out::println);
    }
}

三、终止操作

1.匹配与查找

Day.36 Java 8新特性: Stream API、Optional 类_第6张图片

Day.36 Java 8新特性: Stream API、Optional 类_第7张图片

void

forEach(Consumer c)

迭代遍历流

boolean

allMatch(Predicate p)

检查是否匹配所有元素

boolean

anyMatch(Predicate p)

检查是否至少匹配一个元素

boolean

noneMatch(Predicate p)

检查是否没有匹配所有元素

long count()

返回流中元素总数

Optional

findFirst()

返回第一个元素

Optional

findAny()

返回当前流中的任意元素

Optional

max(Comparator c)

返回流中最大值

Optional

min(Comparator c)

返回流中最小值

T

reduce(T iden, BinaryOperator b)

可以将流中元素反复结合起来,得到一个值。返回 T

U

reduce(BinaryOperator b)

可以将流中元素反复结合起来,得到一个值。返回 Optional

R

collect(Collector c)   (将数据收集、转为集合)

将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法

  • 代码实现 
/*
* 测试Stream的终止操作
*
* */
public class StreamAPITest2 {

    // 1 - 匹配与查找
    @Test
    public void test1(){
        List employees = EmployeeData.getEmployees();

        //allMatch(Predicate p) --- 检查是否匹配所有元素。
        // 练习:是否所有的员工的年龄都大于18
        boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);
        System.out.println(allMatch);   //false

        //anyMatch(Predicate p) --- 检查是否至少匹配一个元素。
        // 练习:是否存在员工的工资大于10000
        boolean anyMatch = employees.stream().allMatch(e -> e.getSalary() > 10000);
        System.out.println(anyMatch);   //false

        //noneMatch(Predicate p) --- 检查是否没有匹配的元素。
        // 练习: 是否存在员工姓"雷"                                       startsWith:是否以*开头
        boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("雷"));
        System.out.println(noneMatch);   //false

        //findFirst --- 返回第一个元素
        Optional employee = employees.stream().findFirst();
        System.out.println(employee);

        //findAny --- 返回当前流中的任意元素
        Optional employee1 = employees.parallelStream().findAny();
        System.out.println(employee1);
    }

    @Test
    public void test2(){
        List employees = EmployeeData.getEmployees();

        //count --- 返回流中元素的总个数
        long count = employees.stream().filter(e -> e.getSalary() > 5000).count();
        System.out.println(count);  //5

        //max(Comparator c) --- 返回流中最大值
        // 练习: 返回最高的工资
        Stream salaryStream = employees.stream().map(e -> e.getSalary());
        Optional maxSalary = salaryStream.max(Double::compare);
        System.out.println(maxSalary);

        //min(Comparator c) --- 返回流中最小值
        // 练习: 返回最低工资的员工
        Optional employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(employee);

        //forEach(Consumer c) --- 内部迭代
        employees.stream().forEach(System.out::println);

        //使用集合的遍历操作方法 (与上面不同)
        employees.forEach(System.out::println);
    }
}

2. 归约

Day.36 Java 8新特性: Stream API、Optional 类_第8张图片

T

reduce(T iden, BinaryOperator b)

可以将流中元素反复结合起来,得到一个值。返回 T

U

reduce(BinaryOperator b)

可以将流中元素反复结合起来,得到一个值。返回 Optional

    // 2 - 归约
    @Test
    public void test3(){
        //reduce(T identity,BinaryOperator b) --- 可以将流中元素反复结合起来,得到一个值。返回T
        //练习1: 计算1-10的自然数的和
        List list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer sum = list.stream().reduce(0, Integer::sum);//0:初始值
        System.out.println(sum);

        //reduce(BinaryOperator b) --- 可以将流中元素反复结合起来,得到一个值。返回 Optional
        //练习2: 计算公司所有员工工资的综合
        List employees = EmployeeData.getEmployees();
        Stream salaryStream = employees.stream().map(e -> e.getSalary());
        //Optional sumMoney = salaryStream.reduce((s1,s2) -> s1 + s2);
        Optional sumMoney = salaryStream.reduce(Double::sum);
        System.out.println(sumMoney);   //Optional[48424.08]

    }

3. 收集 --- Collectors类

Day.36 Java 8新特性: Stream API、Optional 类_第9张图片

  •  Collectors类方法 

Day.36 Java 8新特性: Stream API、Optional 类_第10张图片

Day.36 Java 8新特性: Stream API、Optional 类_第11张图片

R

collect(Collector c)

将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法

  •  代码
    // 3 - 收集
    @Test
    public void test4(){
        //collect(Collector c) --- 将流转换为其他形式。接受一个Collector接口的实现,用于给Stream中元素做汇总的方法
        //练习1: 查找工资大于6000的员工 结果返回为一个List或Set

        List employees = EmployeeData.getEmployees();
        List employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());

        employeeList.forEach(System.out::println);
        System.out.println("-------------------------------");

        Set employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
        employeeSet.forEach(System.out::println);

    }

Stream常用方法

static  Stream of(T... values)

返回其元素是指定值的顺序排序流。

static  Stream of(T t)

返回包含单个元素的顺序 Stream

Stream filter(Predicate predicate)

接受Lambda,从流中排除某些元素。

Stream limit(long maxSize)

截断流,使其元素不超过给定数量。

Stream skip(long n)

跳过元素,返回一个扔掉了前 n 个元素的流。若流中的元素不足 n 个,则返回一个空流。与limit(n)互补。

Stream distinct()

筛选,通过流锁生成元素的hashCode() 和equals()去除重复元素

 Stream map(Function mapper)

接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

 Stream flatMap(Function> mapper)

接受一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

终止操作 ------------------------------------------------------------------------------
void forEach(Consumer action)

对此流的每个元素执行操作。

boolean allMatch(Predicate predicate)

检查是否匹配所有元素。

boolean anyMatch(Predicate predicate)

检查是否至少匹配一个元素。

boolean noneMatch(Predicate predicate)

检查是否没有匹配的元素。

Optional findFirst()

返回第一个元素

Optional findAny()

返回当前流中的任意元素

long count()

返回此流中的元素数。

Optional max(Comparator comparator)

根据提供的 Comparator返回此流的最大元素。

Optional min(Comparator comparator)

根据提供的 Comparator返回此流的最小元素。

T reduce(T identity, BinaryOperator accumulator)

可以将流中元素反复结合起来,得到一个值。返回T

Optional reduce(BinaryOperator accumulator)

可以将流中元素反复结合起来,得到一个值。返回 Optional

 U reduce(U identity, BiFunction accumulator, BinaryOperator combiner)

执行 reduction在此流中的元素,使用所提供的身份,积累和组合功能。

static  Stream.Builder builder()

返回一个 Stream的构建器。

 R collect(Collector collector)

使用 Collector对此流的元素执行 mutable reduction Collector

 R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)

对此流的元素执行 mutable reduction操作。

static  Stream empty()

返回一个空的顺序 Stream

DoubleStream flatMapToDouble(Function mapper)

返回一个 DoubleStream ,其中包含将该流的每个元素替换为通过将提供的映射函数应用于每个元素而产生的映射流的内容的结果。

IntStream flatMapToInt(Function mapper)

返回一个 IntStream ,其中包含将该流的每个元素替换为通过将提供的映射函数应用于每个元素而产生的映射流的内容的结果。

LongStream flatMapToLong(Function mapper)

返回一个 LongStream ,其中包含将该流的每个元素替换为通过将提供的映射函数应用于每个元素而产生的映射流的内容的结果。

void forEachOrdered(Consumer action)

如果流具有定义的遇到顺序,则以流的遇到顺序对该流的每个元素执行操作。

static  Stream generate(Supplier s)

返回无限顺序无序流,其中每个元素由提供的 Supplier

static  Stream iterate(T seed, UnaryOperator f)

返回有序无限连续 Stream由函数的迭代应用产生 f至初始元素 seed ,产生 Stream包括 seedf(seed)f(f(seed)) ,等

DoubleStream mapToDouble(ToDoubleFunction mapper)

返回一个 DoubleStream ,其中包含将给定函数应用于此流的元素的结果。

IntStream mapToInt(ToIntFunction mapper)

返回一个 IntStream ,其中包含将给定函数应用于此流的元素的结果。

LongStream mapToLong(ToLongFunction mapper)

返回一个 LongStream ,其中包含将给定函数应用于此流的元素的结果。

Stream peek(Consumer action)

返回由该流的元素组成的流,另外在从生成的流中消耗元素时对每个元素执行提供的操作。

Stream sorted()

返回由此流的元素组成的流,根据自然顺序排序。

Stream sorted(Comparator comparator)

返回由该流的元素组成的流,根据提供的 Comparator进行排序。

Object[] toArray()

返回一个包含此流的元素的数组。

 A[] toArray(IntFunction generator)

使用提供的 generator函数返回一个包含此流的元素的数组,以分配返回的数组,以及分区执行或调整大小可能需要的任何其他数组。

Optional 类

Day.36 Java 8新特性: Stream API、Optional 类_第12张图片

Day.36 Java 8新特性: Stream API、Optional 类_第13张图片

static  Optional

ofNullable(T value)

返回一个 Optional指定值的Optional,如果非空,则返回一个空的 Optional

T

orElse(T other)

如果空指针,返回 other

T

orElseGet(Supplier other)

供给型接口

如果空指针,则调用 other并返回该调用的结果。


T

orElseThrow(Supplier exceptionSupplier)

如果空指针,则抛出由提供的供应商创建的异常。

创建Optional类对象

创建Optional类对象的方式:

- Optional.of(T t) : 创建一个 Optional 实例,t必须非空;
- Optional.empty() : 创建一个空的 Optional 实例
- Optional.ofNullable(T t):t可以为nul

//方法
orElse() 如果为空则
    @Test
    public void test1(){
        Girl girl = new Girl();
        girl = null;
        Optional optionalGirl = Optional.of(girl);
        //NullPointerException
    }
    @Test
    public void test2(){
        Girl girl = new Girl();
        girl = null;
        Optional optionalGirl = Optional.ofNullable(girl);
        System.out.println(optionalGirl);//Optional.empty
        //orElse(T t): 如果当前的Optional内部封装的t是非空的,则返回内部的t
        //如果内部的t是空的,则返回orElse()方法中的参数t1
        Girl girl1 = optionalGirl.orElse(new Girl("赵丽颖"));
        System.out.println(girl1);//Girl{name='赵丽颖'}
    }
  • 出现空指针的情况

  @Test
    public void test3(){
        Boy boy = new Boy();
        String girlName = getGirlName(boy);
        System.out.println(girlName);
        //NullPointerException
    }
    public String getGirlName(Boy boy){
        return boy.getGirl().getName();
    }
  • 优化后

    @Test
    public void test4(){
        Boy boy = new Boy();
        String girlName = getGirlName1(boy);
        System.out.println(girlName);//null
    }

    //优化以后的getGirName();
    public String getGirlName1(Boy boy){
        if(boy != null){
            Girl girl = boy.getGirl();
            if(girl != null){
                return girl.getName();
            }
        }
        return null;
    }

使用Optional类优化

    @Test
    public void test5(){
        Boy boy = null;
        boy = new Boy();
        String girlName = getGirlName2(boy);
        System.out.println(girlName);   //迪丽热巴
    }

    //使用Optional类的getGirName();
    public String getGirlName2(Boy boy){

        Optional boyOptional = Optional.ofNullable(boy);
        //此时的boy1一定非空
        Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴")));

        Girl girl = boy1.getGirl();

        Optional girlOptional = Optional.ofNullable(girl);
        //此时的girl1一定非空
        Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));

        return girl1.getName();
    }

你可能感兴趣的:(JavaSE,java,开发语言)