• JDK8以上提高开发效率


    1 接口的默认方法和静态方法

    1.1 接口中可以定义默认方法和静态方法。

    • 默认方法使用default修饰,静态方法和默认方法可以多个;
    • 静态方法通过接口直接调用,默认方法通过接口实现类调用
    • 默认方法可以重写
    public interface InterfaceTest {
      
        default String defaultMethod(){
            return "InterfaceTest  defaultMethod";
        }
        static String staticMethod(){
            return "InterfaceTest  staticMethod";
        }
    }
    
    public class InterfaceMain {
        public static void main(String[] args) {
      
            //接口中的默认方法必须通过接口实现类调用
            InterfaceTestImpl impl = new InterfaceTestImpl();
            System.out.println(impl.defaultMethod());
      
            // 接口中的静态方法可以直接通过接口调用
            System.out.println(InterfaceTest.staticMethod());
        }
    }
    

    接口中默认方法可以重写

    1.2 如果子类继承父类和实现接口中方法重名,采用类优先原则 调用父类方法

    public class Inter {
        public String defaultMethod(){
            return "Inter defaultMethod";
        }
    }
    
    public interface InterfaceTest {
    
        default String defaultMethod(){
            return "InterfaceTest  defaultMethod";
        }
    }
    
    public class InterfaceMain extends Inter implements InterfaceTest{
        public static void main(String[] args) {
            InterfaceMain i =  new InterfaceMain();
            System.out.println(i.defaultMethod());
        }
    }
    

    输入结果:Inter defaultMethod

    2 Lambda表达式

    2.1 Lambda基础格式

    (参数列表)->{
      方法体
    }
    
    1. 没有参数的Lambda表达式,方法体只有一个可以省略return
      ()-> new Student();
    2. 只有一个参数的Lambda表达式
    x->{
    	System.out.prontle(x);
    	return x;
    }
    
    1. 有多个参数的Lambda表达式
    (int x,int y)->{
    	System.out.prontle(x);
    	System.out.prontle(y);
    	return x+y;
    }
    

    上述写法可以简化,参数列表中的参数的数据类型JVM可以根据上下文进行推断,所以可以不定义类型

    (x,y)->{
    	System.out.prontle(x);
    	System.out.prontle(y);
    	return x+y;
    }
    
    1. 一个参数和仅一条语句的Lambda表达式
      x -> 3+x;
    2. 多个参数和鲸一条语句的Lambda表达式
      (x+y)->x+y;

    2.2 Lambda使用案例

    1. Lambda简化匿名内部类写法
    Runnable runnable1 = new Runnable() {
        @Override
        public void run() {
            System.out.println("hello Lambda");
        }
     };
    

    //Lambda简化匿名内部类写法
    Runnable runnable2 = ()-> System.out.println("hello Lambda");
    2. Lambda对数组排序

    String[] arr = new String[]{"c","b","a"};
    
    //原写法
    Arrays.sort(arr, new Comparator<String>() {
      @Override
      public int compare(String o1, String o2) {
         return o1.compareTo(o2);
      }
    });
    //Lambda简化写法1
    Arrays.sort(arr,(o1,o2)->(o1.compareTo(o2)));
    //Lambda简化写法2,再次简化
    Arrays.sort(arr, String::compareTo);
    

    3 函数式接口

    Java8为了让现有的函数更加友好的使用Lambda表达式,引入了函数式接口。函数式接口仅有一个抽象方法,如果声明多个抽象方法则会报错,但默认方法和静态方法在此接口中可以有多个。

    3.1 函数式接口声明和使用

    自定义函数接口需要在接口上加@FunctionalInterface

    //函数式接口定义
    @FunctionalInterface
    public interface MyInterface {
        void excute();
    }
    
    //函数式接口调用
    public static void demo(MyInterface myInterface) {
      myInterface.excute();
    }
    
    public static void main(String[] args) {
      demo(() -> System.out.println("函数式接口调用"));
    }
    

    3.2 常见应用

    ​ 在Java8类库设计中,已经引入了几个函数式接口:Predicate、Consumer、Function、Supplier

    3.2.1 Predicate

    ​ Predicate属于java.util.function包下,用于进行判断操作,内部顶一个抽象方法test、三个默认方法and、negate、or、一个静态方法isEqual。

    3.2.2 Consumer

    ​ Comsumer,用于==获取数据的操作==。内部定义了一个抽象方法accept,一个默认方法andThen。

    3.2.3 Function

    ​ Function主要用于==进行类型转换的操作==。内部提供一个抽象方法apply、两个默认方法compose、andThen、一个静态方法identity。

    3.2.4 Supplier

    ​ Supplier也是用来==获取值操作==,内部只有一个抽象方法get。与Consumer 的 accept方法不同于 Consumer 的 accept没有返回值,supplier中的get方法有返回值。

    4 类型检查&推断

    ​ 自动类型推断:在Java8中可以省略Lambda表达式的所有参数类型,在编译的时根据Lambda表达式的上下文信息推断出参数的正确类型,这就是所谓的类型推断。

    5 方法引用

    ​ 方法引用更进一步的优化了Lambda的使用。它让代码感觉更加的自然。我们可以直接使用::来简化Lambda表达式的使用。其语法如下:类名或实例名::属性

    List<Student> students = new ArrayList<>();
    students.add(new Student(2,"张三","N"));
    students.add(new Student(1,"李四","V"));
    students.add(new Student(3,"万维","V"));
    
    students.sort(Comparator.comparing(Student::getId));
    

    6 Stream流

    ​ Stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或IO等。在stream中的操作每一次都会产生新的流,内部不会像普通集合操作一样立刻获取值,而是惰性取值,只有等到用户真正需要结果的时候才会执行。
    **案例1:**获取年龄小于20岁学生,并且年龄从小到大排序,只取姓名

    List<Student> students = new ArrayList();
    
    @BeforeEach
    public void init(){
      students.add(new Student(1,"张三","N",19));
      students.add(new Student(2,"赵六","N",17));
      students.add(new Student(4,"王五","V",22));
      students.add(new Student(3,"李四","V",23));
    }
    
    /**
         * 获取年龄小于20岁学生,并且年龄从小到大排序,只取姓名
         * 期望:赵六 张三
         */
    @Test
    public void filter20AndSort(){
      List<String> list = students.stream()
        .filter(s -> s.getAge() < 20) //获取年龄小于20岁学生
        .sorted(Comparator.comparing(Student::getAge)) //按年龄排序
        .map(Student::getName)//取姓名
        .collect(Collectors.toList()); //收集成list
      System.out.println(list);
    }
    

    6.1 流操作详解

    6.1.1 筛选

    1. filter( ) 筛选符合条件的数据
      获取及格学生名单
    List<Student> students = new ArrayList();
    
    @BeforeEach
    public void init(){
        students.add(new Student(1,"张三","N",19,false));
        students.add(new Student(2,"赵六","N",17,true));
        students.add(new Student(4,"王五","V",22,true));
        students.add(new Student(3,"李四","V",23,false));
    }
    
    /**
    * 获取及格学生名单
    */
    @Test
    public void filterIspass(){
        List<Student> passStudents = students.stream()
        .filter(Student::isIspass)
        .collect(Collectors.toList());
        System.out.println(passStudents);
    }
    
    1. distinct( )去重
      ​ 底层通过LinkHashSize实现。注意:对象去重需重写equals和hashcode方法
    @Test
    public void distinct(){
        List<Integer> list = Arrays.asList(1,2,3,2,6,1,4,5);
        List<Integer> result = list.stream().distinct().collect(Collectors.toList());
        System.out.println(result);
    }
    

    6.1.2 切片

    1. limit ( ) 返回一个不超过给定长度的流。从前往后
    @BeforeEach
    public void init(){
        students.add(new Student(1,"张三","N",19,false));
        students.add(new Student(2,"赵六","N",17,true));
        students.add(new Student(4,"王五","V",22,true));
        students.add(new Student(3,"李四","V",23,false));
    }
    //取第一条数据
    @Test
    public void limt(){
        List<Student> result = students.stream().limit(1).collect(Collectors.toList());
        System.out.println(result);
    }
    
    1. skip( ) 跳过给定数量 取剩余的数据
    @BeforeEach
    public void init(){
        students.add(new Student(1,"张三","N",19,false));
        students.add(new Student(2,"赵六","N",17,true));
        students.add(new Student(4,"王五","V",22,true));
        students.add(new Student(3,"李四","V",23,false));
    }
    @Test
    public void skip(){
    		//取最后一条数据
        List<Student> result = students.stream().skip(3).collect(Collectors.toList());
        System.out.println(result);
    }
    

    skip与limit结合使用
    ​ 跳过前2条取1条数据

    @BeforeEach
    public void init(){
        students.add(new Student(1,"张三","N",19,false));
        students.add(new Student(2,"赵六","N",17,true));
        students.add(new Student(4,"王五","V",22,true));
        students.add(new Student(3,"李四","V",23,false));
        students.add(new Student(3,"韩七","V",25,false));
    }
    @Test
    public void limtAndSkip(){
        List<Student> result = students.stream().skip(2).limit(1).collect(Collectors.toList());
        System.out.println(result);
    }
    

    6.1.3 映射

    ​ 在对集合进行操作的时候,我们经常会从某些对象中选择性的提取某些元素的值。可以使用map( )进行映射

    @BeforeEach
    public void init(){
        students.add(new Student(1,"张三","N",19,false));
        students.add(new Student(2,"赵六","N",17,true));
        students.add(new Student(4,"王五","V",22,true));
        students.add(new Student(3,"李四","V",23,false));
    }
    @Test
    public void map(){
        List<String> result = students.stream()
        .map(Student::getName) //只取集合中的姓名值
        .collect(Collectors.toList());
        System.out.println(result);
    }
    

    案例:将集合类型转换并求和

    @Test
    public void map2(){
        List<String> list = Arrays.asList("1","2","3","2","6");
        int result = list.stream()
                .mapToInt(s->Integer.parseInt(s))//类型转换
                .sum(); //求和
        System.out.println(result);
    }
    

    6.1.4 匹配

    ​ 用于判断集合中某些元素是否匹配对应的条件,如果有的话,再进行后续的操作。如anyMatch、allMatch等,对应&& 和|| ||运算符。

    1. anyMatch( ) 只要有1条数据满足条件即返回TRUE 否则返回FALSE
    @BeforeEach
    public void init(){
        students.add(new Student(1,"张三","N",19,false));
        students.add(new Student(2,"赵六","N",22,true));
        students.add(new Student(4,"王五","V",22,true));
        students.add(new Student(3,"李四","V",23,false));
    }
    
    @Test
    public void anyMath(){
        if(students.stream().anyMatch(s->s.getAge()==22)){
            System.out.println("集合中有22岁的学生");
        }
    }
    
    1. allMatch( ) 当所有数据满足条件后返回TRUE 否则返回FALSE。
    @BeforeEach
    public void init(){
        students.add(new Student(1,"张三","N",19,false));
        students.add(new Student(2,"赵六","N",22,true));
        students.add(new Student(4,"王五","V",22,true));
        students.add(new Student(3,"李四","V",23,false));
    }
    
    @Test
    public void allMath(){
        if(students.stream().allMatch(Student::isIspass)){
            System.out.println("所有学生及格");
        }else{
            System.out.println("还有学生不及格");
        }
    }
    

    6.1.5 查找

    1. findAny( ) 随机查找符合条件的数据,找到返回该数据(并行流情况下才会随机返回)
    @BeforeEach
    public void init(){
        students.add(new Student(1,"张三","N",19,false));
        students.add(new Student(2,"赵六","N",22,true));
        students.add(new Student(4,"王五","V",22,true));
        students.add(new Student(3,"李四","V",23,false));
    }
    @Test
    public void findAny(){
        Optional<Student> optional = students.stream().filter(s -> s.getAge() > 10).findAny();
        if(optional.isPresent()){
            Student student = optional.get();
            System.out.println(student);
        }
    }
    
    1. findFirst( ) 返回第一个符合条件的数据

    6.1.6 聚合

    1. reduce()累加。参数一表示初始值*(累加后会再次加上初始的值)*。
    public void reduce(){
        List<Integer> list = Arrays.asList(1,2,3,4,5);
    //        Integer sum = list.stream().reduce(0, (a, b) -> a + b);
    //        Integer sum = list.stream().reduce(0, Integer::sum);
        System.out.println(sum);
        
        Optional<Integer> optional = list.stream().reduce(Integer::sum);
        if(optional.isPresent()){
            System.out.println(optional.get());
        }
    }
    
    1. max( ) 取出数据中最大的值
    @Test
    public void max(){
        List<Integer> list = Arrays.asList(1,2,3,4,5);
    //        Optional<Integer> optional = list.stream().reduce(Integer::max);
        Optional<Integer> optional = list.stream().max(Integer::compareTo);
        if(optional.isPresent()){
            System.out.println(optional.get());
        }
    }
    
    1. min( )最小值。使用同max

    6.1.7 构建流

    1. 基于数组创建
      public void create(){
      //1.通过of方法创建
      Stream stream = Stream.of(1, 2, 3);
      //2.通过数组stream方法创建,底层实现相同
      IntStream stream1 = Arrays.stream(new int[]{1, 2, 3});
      }
    2. 基于文件创建

    6.1.8 收集器

    1. collect( ) 可以收集流中的数据到集合或者数组中
    public void collect(){
        //1.通过of方法创建
        Stream<Integer> stream = Stream.of(1, 2, 3);
        List<Integer> list = stream.collect(Collectors.toList());
    }
    
    1. 分组/分区/拼接
      分组:groupingBy( )
      通过Collectors.groupingBy( )完成。分组可以分多个
    @BeforeEach
    public void init() {
        students.add(new Student(1, "张三", "N", 19, false));
        students.add(new Student(2, "赵六", "N", 22, true));
        students.add(new Student(4, "王五", "V", 22, true));
        students.add(new Student(3, "李四", "V", 23, false));
    }
    
    @Test
    public void groupingBy() {
        //按性别分组
        Map<String, List<Student>> map = students.stream()
                .collect(Collectors.groupingBy(Student::getSex));
    }
    

    分区:partitioningBy( )
    ​ 分组通过Collectors.partitioningBy( )完成。分区只能分2个。根据返回值是否为TRUE,把集合分为2个列表,一个TRUE列表,一个FALSE列表。

    @BeforeEach
    public void init() {
        students.add(new Student(1, "张三", "N", 19, false));
        students.add(new Student(2, "赵六", "N", 22, true));
        students.add(new Student(4, "王五", "V", 22, true));
        students.add(new Student(3, "李四", "V", 23, false));
    }
    @Test
    public void partitioningBy() {
        Map<Boolean, List<Student>> map = students.stream()
                .collect(Collectors.partitioningBy(s -> s.getSex().endsWith("N")));
        System.out.println(map);
        //{
        // false=[Student(id=4, name=王五, sex=V, age=22, ispass=true), Student(id=3, name=李四, sex=V, age=23, ispass=false)], 
        // true=[Student(id=1, name=张三, sex=N, age=19, ispass=false), Student(id=2, name=赵六, sex=N, age=22, ispass=true)]
        // }
    }
    

    拼接:joining( )
    Collectors.joining() 会根据指定的连接符,将所有元素连接成一个字符串。

    @BeforeEach
        public void init() {
            students.add(new Student(1, "张三", "N", 19, false));
            students.add(new Student(2, "赵六", "N", 22, true));
            students.add(new Student(4, "王五", "V", 22, true));
            students.add(new Student(3, "李四", "V", 23, false));
        }
        @Test
        public void joining() {
            String names = students.stream()
                    .map(Student::getName)
                    .collect(Collectors.joining());
            System.out.println(names);//张三赵六王五李四
        }
    

    6.2 数据并行化

    ​ parallelStream( )替换stream( )

    6.2.1 并行和并发

    ​并行:多个任务在同一时间点发生,并由不同的CPU进行处理,互相不抢占资源。

    并发:多个任务在同一时间内同时发生,但由同一个CPU处理,互相抢夺资源。

    6.2.2 并行流原理介绍

    ​ 对于并行流,其在底层中,是沿用Java7提供的fork\join分解合并框架进行实现。fork根据==CPU可用核数==进行数据分块,join对各个fork进行合并,实现过程如下图。
    ​ 假如现在的操作是运行一台4核机器上

    7 异步编程CompleTableFuture

    ​ completableFuture是Java1.8提供的一个新类,其实现了Future与completionStage两个接口。提供了诸多API扩展功能,可以通过stream形式简化异步编程的复杂度,同时提供通过回调方式处理计算结果

    7.1 创建异步任务

    ​ 在completableFuture中提供了四个静态方法用于创建异步任务:

    runAsync(Runnable runnable) //不带返回值,默认使用守护进程线程池,不推荐
    runAsync(Runnable runnable,Executor executor)//无返回值,自定义线程池
    supplyAsync(Supplier<U> supplier)//有返回值,默认使用守护进程线程池,不推荐
    supplyAsync(Supplier<U> supplier,Executor executor)//有回值,自定义线程池
    
  • 相关阅读:
    基础抽象代数
    斜堆
    WC2018
    WC2019
    有向图上不相交路径计数
    生成树计数
    Pr&#252;fer序列
    反演
    1.1 Linux中的进程 --fork、孤儿进程、僵尸进程、文件共享分析
    Python程序的执行过程 解释型语言和编译型语言
  • 原文地址:https://www.cnblogs.com/dooor/p/jdk8_0226.html
Copyright © 2020-2023  润新知