首页 > 其他分享 >JDK版本特性(二)StreamAPI

JDK版本特性(二)StreamAPI

时间:2023-12-18 13:13:33浏览次数:28  
标签:JDK stream list System 版本 var StreamAPI Optional out

Stream API


1 概述

  • Stream是java8中处理集合的关键抽象概念
  • 它可以指定对集合进行的操作,比如执行肥非常复杂的查找、过滤和映射等操作
  • 还可以使用Steam API来进行并行操作

2 Steam实例化

2.1 集合创建

​ 实现自接口collection.stream()

    @Test
    public void genByCollection() {
        var list = new ArrayList<Integer>();
        Stream<Integer> stream = list.stream();
    }
2.2 数组创建

​ 来自Arrays工具类的stream方法

    @Test
    public void genByArray() {
        var arr = new int[]{1, 2, 3};
        IntStream stream = Arrays.stream(arr);

        Stream<String> stream2 = Arrays.stream(new String[]{"1", "2"});

        var es = new Employee[3];
        es[0] = new Employee();
        es[1] = new Employee();
        es[2] = new Employee();

        Stream<Employee> stream1 = Arrays.stream(es);
        
    }
2.3 Stream创建
@Test
public void genByStream() {
    Stream<Integer> integerStream = Stream.of(4, 5, 6);
}
2.4 无限流
@Test
public void test() {
    // 输出前十个偶数
    Stream.iterate(0, t -> t + 2)
            // 中间操作
            .limit(10)
            // 终止操作
            .forEach(System.out::println);

    // 生成5个随机数
    // 提供一个supplier接口
    Stream.generate(Math::random)
            // 中间操作
            .limit(5)
            // 终止操作
            .forEach(System.out::println);
}

3 Stream中间操作

3.1 常见中间流操作
  • 过滤流 filter:

  • 截断流 limit:

  • 跳跃流 skip:

  • 筛选流 distinct:去除重复元素,根据对象的HashCode

    流经过终止操作后就会被关闭,不能够再回到中间操作

/**
 * 中间操作测试
 */
@Test
public void test1() {
    var list = EmployeeData.getEmployees();
    // 过滤流
    list.stream()
            .filter(e -> e.getAge() % 2 == 1)
            .forEach(System.out::println);

    // 截断流
    list.stream()
            .limit(4)
            .forEach(System.out::println);

    // 跳跃流
    list.stream()
            .skip(3)
            .forEach(System.out::println);

    list.add(new Employee("1", 1));
    list.add(new Employee("1", 1));
    list.add(new Employee("1", 1));
    
    // 筛选流
    list.stream().distinct()
            .forEach(System.out::println);

}
3.2 映射
  • map(Function f):接收一个函数作为参数,将流中的每个值都经过该函数处理后转化为一个流,然后嵌套到最外层的流里面

            var list = Arrays.asList("aa", "bb", "cc");
    		//aa
    		//bb
    		//cc
            Stream<Stream<Character>> characterStream =
                    list.stream().map(StreamMapTest::fromStringToStream);
    
  • flatMap(Function f):接收一个函数作为参数,将流中的每个值都转化为一个流,然后把所有的流连接成一个流,类似于对流的一个扁平(flat)处理

            characterStream.forEach(s -> {
                s.forEach(System.out::print);
                System.out.println();
            });
    		
            Stream<Character> flatStream
                    = list.stream().flatMap(StreamMapTest::fromStringToStream);
            // aabbcc
    		flatStream.forEach(System.out::print);
    
  • mapToDouble(Function f):接收一个函数作为参数,将流中的每个值都处理转化为一个Double流

  • mapToInt(Function f):接收一个函数作为参数,将流中的每个值都处理转化为一个Int流

  • mapToLong(Function f):接收一个函数作为参数,将流中的每个值都处理转化为一个Long流

4 终止操作

4.1 match & find 匹配与查找
  • allMatch:true | false

  • anyMatch:true | false

  • noneMatch:true | false

  • count:返回流的元素的个数

  • findFirst:返回Optional(防止空指针)

  • findAny:返回Optional(防止空指针)

  • max:返回Optional(防止空指针)

  • min:返回Optional(防止空指针)

        @Test
        public void test() {
            var list = EmployeeData.getEmployees();
            var res1 = list.stream().allMatch(e -> e.getAge() > 18);
            // false
            System.out.println(res1);
    
            var res2 = list.stream().anyMatch(e -> e.getAge() > 18);
            // false
            System.out.println(res2);
    
            // true
            var res3 = list.stream().noneMatch(e -> e.getAge() > 18);
            System.out.println(res3);
    
            var res4 = list.stream().count();
            // 7
            System.out.println(res4);
    
            Optional<Employee> first = list.stream().findFirst();
            // Optional[Employee(name=0001, age=1)]
            System.out.println(first);
    
            Optional<Employee> any = list.parallelStream().findAny();
            // Optional[Employee(name=0005, age=5)]
            System.out.println(any);
    
            // Optional[Employee(name=0007, age=7)]
            Optional<Employee> max = list.stream().max(Comparator.comparingInt(Employee::getAge));
            System.out.println(max);
    
            // Optional[Employee(name=0001, age=1)]
            Optional<Employee> min = list.stream().min(Comparator.comparingInt(Employee::getAge));
            System.out.println(min);
        }
    
4.2 reduce 规约
  • reduce(T identity, BinaryOperator accumulator)可以将流中的元素反复结合起来,得到一个值,并返回计算的值加上初始值identity

            List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
            Integer reduce
                    = list.stream().reduce(10, Integer::sum);
            // 65
            System.out.println(reduce);
    
  • eg:获取全部员工年龄加和

            var list2 = EmployeeData.getEmployees();
            var sum = list2.stream()
                    .map(Employee::getAge)
                    .reduce(0, Integer::sum);
            System.out.println(sum);
    
4.3 收集
  • collect(Collector c):将流转化为其他形式,接收一个Collector接口实现,用于给Stream中元素做汇总的方法

  • Collector接口中的方法决定了如何对流执行收集的操作(如收集到List、Set、Map等)

        @Test
        public void test2() {
            // 查找年龄大于5的员工,并返回为一个list或者set
            var list = EmployeeData.getEmployees();
            var resList = list.stream().filter(e -> e.getAge() > 5)
                    .collect(Collectors.toList());
            System.out.println(resList);
    
            var resSet = list.stream().filter(e -> e.getAge() > 5)
                    .collect(Collectors.toSet());
            System.out.println(resSet);
        }
    
  • Collectors的相关方法有:

    • toList():把流中的元素收集到list
    • toSet():把流中的元素收集到Set
    • toCollection():
    • counting()::
    • summingInt():
    • averagingInt():
    • summarizingInt():返回值为IntSummaryStatistics,收集流中Integer属性的统计值,如平均值

5 Optional类

​ Optional通过检查空值的方式防止代码污染,避免空指针异常

5.1 Optional的创建
  • Optional.of(T t):创建一个Optional实例,t必须非空,否则会报空指针

  • Optional.empty():创建一个空Optional

  • Optional.ofNullable(T t):t可以为空,如果为空返回的是一个value为null的Optional.Empty常量

            Girl girl = new Girl();
            girl = null;
            // nullPointerException
            var optionalGirl
                    = Optional.of(girl);
    
  • Optional.orElse(T t):为空的时候指定返回值,避免了空指针问题

        public String getGirlName(Boy boy) {
            var optionalBoy = Optional.ofNullable(boy);
            // boy1一定非空
            var boy1 = optionalBoy.orElse(new Boy(new Girl("girl1")));
    
            var girl = boy1.getGirl();
            var optionalGirl = Optional.ofNullable(girl);
            var girl1 = optionalGirl.orElse(new Girl("girl2"));
            return girl1.getName();
        }
    
  • Optional.get():获取Optional封装的值,如果为空则会抛出异常

  • boolean isPresnt():判断是否包含对象

  • void ifPresent(Consumer<? extends T> consumer):如果有值,就将该值作为参数就执行Consumer接口的实现代码

  • T orElseGet(Supplier<? extends T> other):如果没有值,则执行Supplier接口返回的值作为该值返回

  • T orElseThrow(Supplier<? extends X> eceptionSupplier):如果存在值则将值返回,否则抛出supplier接口得到的异常

4 动态代理

  • 代理模式的原理

    使用一个代理对象将对象包装起来,然后使用该代理对象包装原始对象,任何对原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上

  • 静态代理举例:

    thread就是一个代理对象,t则是被代理对象,当执行start方法的时候,实际上就是执行的MyThread被代理类的run方法

    public class MyThread implements Runnable{
        @Override
        public void run() {
    
        }
    
        @Test
        public void test() {
            MyThread t = new MyThread();
            Thread thread = new Thread(t);
            thread.start();
        }
    }
    
  • 静态代理的缺点:

    • 每个代理类只能为一个接口服务,程序开发必然会产生过多的代理
    • 代理类和目标类(被代理类)都是在编译期间确定下来,不利于程序的扩展
    • 最好能够通过一个代理类实现全部的代理功能——动态代理
  • 动态代理指的是客户通过代理类来调用其他对象方法,并且在程序运行时根据需要动态创建目标类的代理对象

  • 动态代理需要解决的问题:

    • 如何根据加载到内存的被代理类,动态地创建一个代理类及其对象(通过Proxy.newProxyInstance)
    • 当通过代理类的对象调用方法a的时候,如何动态地去调用被代理的同名方法a

标签:JDK,stream,list,System,版本,var,StreamAPI,Optional,out
From: https://www.cnblogs.com/tod4/p/17910956.html

相关文章

  • JDK版本特性(一)JDK8
    Java8新特性速度更快:如HashMap底层使用红黑树代码更少强大的StreamAPI便于并行最大化减少空指针异常:OptionalNashorn引擎:在JVM上运行JS应用1Lambda表达式1.1Lambda表达式的格式(o1,o2)->Integer.compare(o1,o2)->:lambda操作符或者箭头操作符左边:lambda形......
  • spirng、springboot、jdk、maven、tomcat版本问题
    引入springboot依赖时会自动安装spring对应依赖,版本由springboot决定。springboot2.x.x及以下使用jdk11、jdk8都可以,springboot3.x.x最低要求jdk17maven与jdk版本关系,参照链接:https://maven.apache.org/docs/history.htmlApacheTomcat是JakartaEE(JavaEE)技术子集的开源......
  • 新增“失窃设备保护”:苹果发布iOS 17.3测试版本
    12月13日消息,在昨天发布iOS17.2正式版之后,今天苹果向开发者推送了iOS17.3Beta版本更新,新增了“失窃设备保护”功能。iOS17.3首个Beta版本更新引入了“设备被盗保护”(StolenDeviceProtection)功能,可以在小偷或其他攻击者知道用户的私人密码时保护用户信息。当此功能开启后,如......
  • linux 进程间通信 --- 共享内存(POSIX 版本)
    POSIX进程间通信POSIX进程间通信(InterprocessCommunication,IPC)是SystemV进程间通信的变体。它是在Solaris7发行版中引入的。与SystemV对象类似,POSIXIPC对象的属主、属主的组以及其他用户具有读取和写入权限,但是没有执行权限。POSIXIPC对象的属主无法将对象......
  • 数据库版本历史的总结-非信创部分
    数据库版本历史的总结-非信创部分OracleOracle数据库是最悠久的关系型数据库.诞生于美国军方的管理项目他的第一个版本是Oracle2上世纪八九十年代的Oracle8和Oracle9是非常成功的版本.进入21世纪后Oracle发布了三个大版本Oracle10goracle11goracle12c(Oracle9......
  • Windows利用nvm进行node版本控制(node 版本管理工具nvm的安装与使用)
    为什么需要对node进行版本管理?不同项目的node的版本并不相同,不同版本之间的兼容性并不好,所以需要工具(node版本管理工具)进行快速切换node版本。下载与安装(Windows)1.卸载电脑原有node直接去控制面板/win11设置卸载就行2.安装nvmGithub下载地址下载地址里面有两类nv......
  • 非动态数组版本下的筛选
    问题:一对多查找(筛选)的结果需要横向排列,但是表格暂时不支持动态数组。右拉下拉公式解决:{=IFERROR(INDEX(FILTER($E:$E,$D:$D=$G2),COLUMN(A1)),"")}公式中的Filter部分筛选出满总D列中等产于G2对应E列的内容,其结果是多个单元格组成的数组。使用Index提取数组中的内容,第......
  • Redis不同版本,内存分配,硬件的性能研究
    Redis不同版本,内存分配,硬件的性能研究前言Konwmore!Domore!Gainmore!骨折之后开始减肥.前段时间跳绳导致膝盖不舒服,现在改骑车和走路.在有限的没人有烦的时间里,还是想能够多学习一些东西.之前了解了isolcpus现在突然想内存分配可能也有性能影响.所以想研......
  • JDK&HDFS安装
    一、环境操作系统:CentOS7.964位JDK版本:8HADOOP版本:3.3.0二、安装包:2.1JDK百度网盘地址及提取码:地址:https://pan.baidu.com/s/1sbgLPROfd9e_valSfv0YAQ 提取码:4qps2.2HADOOP百度网盘地址及提取码:地址:https://pan.baidu.com/s/180Q7Lbyyo6qpwyu1AAFR_Q 提取码:ras4......
  • 【JDK+jenkins+gitee实现CI/CD(之二)】 配置jenkins拉取gitee代码自动构建项目
    前面我们已经学习了如何在阿里云Linux环境中安装jenkins和java环境这一节我们来配置已经安装好了的jenkins,并拉取GITEE上的仓库代码来自动构建项目一,安装jenkins必须的插件汉化插件Chinese,如果安装的jenkins自动中文片,可以跳过这一些安装gitee插件[GiteePlugin]安装docker......