栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

目录

强大的Stream API

一、创建流

二、中间操作

1.筛选与切片 

2.映射

3.排序 

三、终止操作

1.匹配与查找

2. 归约

3. 收集 --- Collectors类

Stream常用方法

Optional 类

​ 创建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 实现计算。

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

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

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

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

一、创建流

代码

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.筛选与切片 

 代码

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.映射

 代码

    @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.排序 

    // 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) -> Integer.compare(e1.getAge(),e2.getAge()))
                .forEach(System.out::println);
    }
}

三、终止操作

1.匹配与查找

代码实现 

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. 归约

    // 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类

 Collectors类方法 

 代码

    // 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  Streamof(T... values)

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

static  Streamof(T t)

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

Streamfilter(Predicate predicate)

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

Streamlimit(long maxSize)

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

Streamskip(long n)

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

Streamdistinct()

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

 Streammap(Function mapper)

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

 StreamflatMap(Function> mapper)

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

终止操作------------------------------------------------------------------------------
voidforEach(Consumer action)

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

booleanallMatch(Predicate predicate)

检查是否匹配所有元素。

booleananyMatch(Predicate predicate)

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

booleannoneMatch(Predicate predicate)

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

OptionalfindFirst()

返回第一个元素

OptionalfindAny()

返回当前流中的任意元素

longcount()

返回此流中的元素数。

Optionalmax(Comparator comparator)

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

Optionalmin(Comparator comparator)

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

Treduce(T identity, BinaryOperator accumulator)

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

Optionalreduce(BinaryOperator accumulator)

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

 Ureduce(U identity, BiFunction accumulator, BinaryOperator combiner)

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

static  Stream.Builderbuilder()

返回一个 Stream的构建器。

 Rcollect(Collector collector)

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

 Rcollect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)

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

static  Streamconcat(Stream a, Stream b)

创建一个懒惰连接的流,其元素是第一个流的所有元素,后跟第二个流的所有元素。

static  Streamempty()

返回一个空的顺序 Stream 。

DoubleStreamflatMapToDouble(Function mapper)

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

IntStreamflatMapToInt(Function mapper)

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

LongStreamflatMapToLong(Function mapper)

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

voidforEachOrdered(Consumer action)

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

static  Streamgenerate(Supplier s)

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

static  Streamiterate(T seed, UnaryOperator f)

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

DoubleStreammapToDouble(ToDoubleFunction mapper)

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

IntStreammapToInt(ToIntFunction mapper)

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

LongStreammapToLong(ToLongFunction mapper)

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

Streampeek(Consumer action)

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

Streamsorted()

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

Streamsorted(Comparator comparator)

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

Object[]toArray()

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

 A[]toArray(IntFunction generator)

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

Optional 类

 创建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();
    }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/770670.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号