JDK新特性

JDK新特性

1. JDK8

1.1 函数式接口

  • 函数式接口主要指只包含一个抽象方法的接口

  • 匿名内部类实现函数式接口

    IDEA中print方法快捷生成方式:变量.sout

    // 1.匿名内部类的语法格式: 父类/接口类型  引用变量名 = new 父类/接口类型(){ 方法的重写 };
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("我是既没有参数又没有返回值的方法!");
        }
    };
    runnable.run(); // 我是既没有参数又没有返回值的方法!
    
    System.out.println("----------------------------------------------------------------------");
    //Consumer中accept方法有参数,无返回值
    Consumer consumer = new Consumer() {
        @Override
        public void accept(Object o) {
            System.out.println(o + "有参但没有返回值的方法就是我!");
        }
    };
    consumer.accept("友情提示:"); // 友情提示:有参但没有返回值的方法就是我!
    
    System.out.println("----------------------------------------------------------------------");
    //Supplier中get方法无参数,有返回值
    Supplier supplier = new Supplier() {
        @Override
        public Object get() {
            return "无参有返回值!";
        }
    };
    System.out.println(supplier.get()); // 无参有返回值
    
    System.out.println("----------------------------------------------------------------------");
    //Function中apply方法有参数,有返回值
    Function function = new Function() {
        @Override
        public Object apply(Object o) {
            return o;
        }
    };
    System.out.println(function.apply("有参有返回值的方法")); // 有参有返回值的方法
    
    System.out.println("----------------------------------------------------------------------");
    //Comparator中compare方法有两个参数,有返回值
    Comparator comparator = new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            return 0;
        }
    };
    System.out.println(comparator.compare(10, 20)); // 0
    
    System.out.println("----------------------------------------------------------------------");
    //Predicate中test方法有参数,返回值为布尔类型,判断传参是否满足条件
    Predicate predicate = new Predicate() {
        @Override
        public boolean test(Object o) {
            return false;
        }
    };
    System.out.println(predicate.test("hello")); // false
    

1.2 Lambda表达式

  • Lambda表达式实现函数式接口

    // 1.匿名内部类的语法格式: 父类/接口类型  引用变量名 = new 父类/接口类型(){ 方法的重写 };
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("我是既没有参数又没有返回值的方法!");
        }
    };
    runnable.run(); // 我是既没有参数又没有返回值的方法!
    
    // 使用lambda表达式实现函数式接口对象的创建: (参数列表)->{方法体;}
    //Runnable runnable1 = () -> { System.out.println("我是既没有参数又没有返回值的方法!"); };
    Runnable runnable1 = () -> System.out.println("我是既没有参数又没有返回值的方法!");
    runnable1.run();
    
    System.out.println("----------------------------------------------------------------------");
    Consumer consumer = new Consumer() {
        @Override
        public void accept(Object o) {
            System.out.println(o + "有参但没有返回值的方法就是我!");
        }
    };
    consumer.accept("友情提示:"); // 友情提示:有参但没有返回值的方法就是我!
    
    //Consumer consumer1 = (Object o) -> {System.out.println(o + "有参但没有返回值的方法就是我!");};
    //Consumer consumer1 = (o) -> System.out.println(o + "有参但没有返回值的方法就是我!");
    // 省略了()、参数类型、{}, 自动类型推断
    Consumer consumer1 = o -> System.out.println(o + "有参但没有返回值的方法就是我!");
    consumer1.accept("友情提示:");
    
    System.out.println("----------------------------------------------------------------------");
    Supplier supplier = new Supplier() {
        @Override
        public Object get() {
            return "无参有返回值!";
        }
    };
    System.out.println(supplier.get()); // 无参有返回值
    
    //Supplier supplier1 = () -> {return "无参有返回值!";};
    Supplier supplier1 = () -> "无参有返回值!";
    System.out.println(supplier1.get());
    
    System.out.println("----------------------------------------------------------------------");
    Function function = new Function() {
        @Override
        public Object apply(Object o) {
            return o;
        }
    };
    System.out.println(function.apply("有参有返回值的方法")); // 有参有返回值的方法
    
    // return 和 {} 都可以省略
    Function function1 = o -> o;
    System.out.println(function1.apply("有参有返回值的方法"));
    
    System.out.println("----------------------------------------------------------------------");
    Comparator comparator = new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            return 0;
        }
    };
    System.out.println(comparator.compare(10, 20)); // 0
    
    Comparator comparator1 = (o1, o2) -> 0;
    System.out.println(comparator1.compare(10, 20));
    
    System.out.println("----------------------------------------------------------------------");
    Predicate predicate = new Predicate() {
        @Override
        public boolean test(Object o) {
            return false;
        }
    };
    System.out.println(predicate.test("hello")); // false
    
    Predicate predicate1 = o -> false;
    System.out.println(predicate1.test("hello"));
    

1.3 方法引用

  • 方法引用是在特定场景下Lambda表达式的一种简化表示,可以进一步简化代码的编写使代码更加紧凑简洁,从而减少冗余代码

  • 方法引用主要指通过方法的名字来指向一个方法而不需要为方法引用提供方法体,该方法的调用交给函数式接口执行

    // 1.使用匿名内部类的方式通过函数式接口Runnable中的方法实现对Person类中show方法的调用
    Person person = new Person("zhangfei", 30);
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            person.show();
        }
    };
    runnable.run(); // 没事出来秀一下哦
    
    System.out.println("-------------------------------------------------------------");
    // 2.使用lambda表达式的方式实现Person类中show方法的调用
    Runnable runnable1 = () -> person.show();
    runnable1.run(); // 没事出来秀一下哦
    
    System.out.println("-------------------------------------------------------------");
    // 3.使用方法引用的方式实现Person类中show方法的调用
    Runnable runnable2 = person::show;
    runnable2.run();
    
    System.out.println("-------------------------------------------------------------");
    // 4.使用匿名内部类的方式通过函数式接口Consumer中的方法来实现Person类中setName方法的调用
    Consumer<String> consumer = new Consumer<String>() {
        @Override
        public void accept(String s) {
            person.setName(s);
        }
    };
    consumer.accept("guanyu");
    System.out.println("person = " + person); // guanyu 30
    
    System.out.println("-------------------------------------------------------------");
    // 5.使用lambda表达式的方式实现Person类中setName方法的调用
    Consumer<String> consumer1 = s -> person.setName(s);
    consumer1.accept("liubei");
    System.out.println("person = " + person); // liubei 30
    
    System.out.println("-------------------------------------------------------------");
    // 6.使用方法引用的方式实现Person类中setName方法的调用
    Consumer<String> consumer2 = person::setName;
    consumer2.accept("zhangfei");
    System.out.println("person = " + person); // zhangfei 30
    
    System.out.println("-------------------------------------------------------------");
    // 7.使用匿名内部类的方式通过函数式接口Supplier中的方法来实现Person类中getName方法的调用
    Supplier<String> supplier = new Supplier<String>() {
        @Override
        public String get() {
            return person.getName();
        }
    };
    System.out.println(supplier.get()); // zhangfei
    
    Supplier<String> supplier1 = () -> person.getName();
    System.out.println(supplier1.get()); // zhangfei
    
    Supplier<String> supplier2 = person::getName;
    System.out.println(supplier2.get()); // zhangfei
    
    System.out.println("-------------------------------------------------------------");
    // 8.使用匿名内部类的方式通过函数式接口Function中的方法实现Integer类中parseInt方法的调用
    Function<String, Integer> function = new Function<String, Integer>() {
        @Override
        public Integer apply(String s) {
            return Integer.parseInt(s);
        }
    };
    System.out.println(function.apply("12345")); // 12345
    
    Function<String, Integer> function1 = s -> Integer.parseInt(s);
    System.out.println(function1.apply("12345")); // 12345
    
    Function<String, Integer> function2 = Integer::parseInt;
    System.out.println(function2.apply("12345")); // 12345
    
    System.out.println("-------------------------------------------------------------");
    // 9.使用匿名内部类的方式通过函数式接口Comparator中的方法实现Integer类中compare方法的调用
    Comparator<Integer> comparator = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1, o2);
        }
    };
    System.out.println(comparator.compare(10, 20));  // -1
    
    Comparator<Integer> comparator1 = (o1, o2) -> Integer.compare(o1, o2);
    System.out.println(comparator1.compare(10, 20)); // -1
    
    Comparator<Integer> comparator2 = Integer::compare;
    System.out.println(comparator2.compare(10, 20)); // -1
    
    System.out.println("-------------------------------------------------------------");
    // 10.使用匿名内部类的方式通过类名来调用非静态方法
    //使用条件:其中一个参数对象作为调用对象来调用方法时,可以使用上述方式   更抽象
    Comparator<Integer> comparator3 = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1.compareTo(o2);
        }
    };
    System.out.println(comparator3.compare(10, 20)); // -1
    
    Comparator<Integer> comparator4 = (o1, o2) -> o1.compareTo(o2);
    System.out.println(comparator4.compare(10, 20)); // -1
    
    Comparator<Integer> comparator5 = Integer::compareTo;
    System.out.println(comparator5.compare(10, 20)); // -1
    
    System.out.println("-------------------------------------------------------------");
    // 11.使用匿名内部类的方式通过Supplier函数式接口创建Person类型的对象并返回
    //构造器的引用 ClassName :: new
    Supplier<Person> supplier3 = new Supplier<Person>() {
        @Override
        public Person get() {
            return new Person();
        }
    };
    System.out.println(supplier3.get()); // null 0
    
    Supplier<Person> supplier4 = () -> new Person();
    System.out.println(supplier4.get()); // null 0
    
    Supplier<Person> supplier5 = Person::new;
    System.out.println(supplier5.get()); // null 0
    
    System.out.println("-------------------------------------------------------------");
    // 12.使用匿名内部类的方式通过BiFunction函数式接口采用有参方式创建Person类型的对象并返回
    //BiFunction前两个泛型为方法传参类型(依次),第三个参数为返回值参数类型
    BiFunction<String, Integer, Person> biFunction = new BiFunction<String, Integer, Person>() {
        @Override
        public Person apply(String s, Integer integer) {
            return new Person(s, integer);
        }
    };
    System.out.println(biFunction.apply("zhangfei", 30)); // zhangfei 30
    
    BiFunction<String, Integer, Person> biFunction1 = (s, integer) -> new Person(s, integer);
    System.out.println(biFunction1.apply("zhangfei", 30)); // zhangfei 30
    
    BiFunction<String, Integer, Person> biFunction2 = Person::new;
    System.out.println(biFunction2.apply("zhangfei", 30)); // zhangfei 30
    
    System.out.println("-------------------------------------------------------------");
    // 12.使用匿名内部类的方式通过Function函数式接口创建指定数量的Person类型的对象数组并返回
    Function<Integer, Person[]> function3 = new Function<Integer, Person[]>() {
        @Override
        public Person[] apply(Integer integer) {
            return new Person[integer];
        }
    };
    Person[] pArr = function3.apply(3);
    System.out.println(Arrays.toString(pArr));
    
    Function<Integer, Person[]> function4 = integer -> new Person[integer];
    System.out.println(Arrays.toString(function4.apply(4)));
    
    Function<Integer, Person[]> function5 = Person[]::new;
    System.out.println(Arrays.toString(function5.apply(5)));
    

1.4 Stream接口

  • java.util.stream.Stream接口是对集合功能的增强,可以对集合元素进行复杂的查找、过滤、筛选等操作

    使用步骤:

    • 创建Stream,通过一个数据源来获取一个流。

    • 转换Stream,每次转换返回一个新的Stream对象。

    • 对Stream进行聚合操作并产生结果

  • 问题:准备一个List集合并放入Person类型的对象,将集合中所有成年人过滤出来放到另外一个集合并打印出来

    //使用for each遍历集合进行过滤
    
    // 1.准备一个List集合并放入Person类型的对象后打印
    List<Person> list = new LinkedList<>();
    list.add(new Person("zhangfei", 30));
    list.add(new Person("xiaoqiao", 17));
    list.add(new Person("zhouyu", 20));
    list.add(new Person("zhangfei", 30));
    list.add(new Person("guanyu", 35));
    list.add(new Person("liubei", 40));
    for (Person tp: list) {
        System.out.println(tp);
    }
    
    System.out.println("-------------------------------------------------------");
    // 2.将List集合中所有成年人过滤出来并放入另外一个集合中打印
    List<Person> list1 = new LinkedList<>();
    for (Person tp : list) {
        if (tp.getAge() >= 18) {
            list1.add(tp);
        }
    }
    for (Person tp : list1) {
        System.out.println(tp);
    }
    System.out.println("-------------------------------------------------------");
    
  • 中间操作:使用Stream流实现集合元素的过滤和打印

    // 3.使用Stream接口实现上述功能
    list.stream().filter(new Predicate<Person>() {
        @Override
        public boolean test(Person person) {
            return person.getAge() >= 18;
        }
    }).forEach(new Consumer<Person>() {
        @Override
        public void accept(Person person) {
            System.out.println(person);
        }
    });
    
    System.out.println("-------------------------------------------------------");
    // 4.使用lambda表达式对上述代码进行优化
    //list.stream().filter(person -> person.getAge() >= 18).forEach(person -> System.out.println(person));
    list.stream().filter(person -> person.getAge() >= 18).forEach(System.out::println);
    System.out.println("-------------------------------------------------------");
    
  • 中间操作:使用Stream流实现集合元素的切片

    System.out.println("-------------------------------------------------------");
    // 5.实现对集合中元素通过流跳过2个元素后再取3个元素后打印
    list.stream().skip(2).limit(3).forEach(System.out::println);
    
  • 中间操作:使用Stream流实现集合元素的映射

    Stream map(Function<? super T,? extends R> mapper)

    返回每个处理过元素组成的流

    System.out.println("-------------------------------------------------------");
    // 6.实现集合中所有元素中的年龄获取出来并打印
    list.stream().map(new Function<Person, Integer>() {
        @Override
        public Integer apply(Person person) {
            return person.getAge();
        }
    }).forEach(System.out::println);
    
    //list.stream().map(person -> person.getAge()).forEach(System.out::println);
    list.stream().map(Person::getAge).forEach(System.out::println);
    
  • 中间操作:使用Stream流集合元素的排序

    System.out.println("-------------------------------------------------------");
    // 7.实现集合中所有元素的自然排序并打印
    list.stream().sorted().forEach(System.out::println);
    
  • 终止操作:使用Stream流实现集合元素的匹配和查找

    System.out.println("-------------------------------------------------------");
    // 8.判断集合中是否没有元素的年龄是大于45岁的
    boolean b1 = list.stream().noneMatch(new Predicate<Person>() {
        @Override
        public boolean test(Person person) {
            return person.getAge() > 45;
        }
    });
    System.out.println("b1 = " + b1); // true
    
    b1 = list1.stream().noneMatch(person -> person.getAge() > 45);
    System.out.println("b1 = " + b1); // true
    
    System.out.println("-------------------------------------------------------");
    // 9.按照指定的比较器规则获取集合所有元素中的最大值
    Optional<Person> max = list.stream().max(new Comparator<Person>() {
        @Override
        public int compare(Person o1, Person o2) {
            return o1.getAge() - o2.getAge();
        }
    });
    System.out.println("按照年龄排序后的最大值是:" + max);
    
    max = list.stream().max((o1, o2) -> o1.getAge() - o2.getAge());
    System.out.println("按照年龄排序后的最大值是:" + max);
    
  • 终止操作:使用Stream流实现集合元素的规约和收集

    Optional reduce(BinaryOperator accumulator) 返回结合后的元素值

    <R,A> R collect(Collector<? super T,A,R> collector)使用收集器对元素进行处理

    System.out.println("-------------------------------------------------------");
    // 10.实现将集合中所有元素的年龄映射出来并进行累加后打印
    Optional<Integer> reduce = list.stream().map(Person::getAge).reduce(new BinaryOperator<Integer>() {
        @Override
        public Integer apply(Integer integer, Integer integer2) {
            return integer + integer2;
        }
    });
    System.out.println("最终所有年龄的累加和是:" + reduce); // 172
    
    //reduce = list.stream().map(Person::getAge).reduce(((integer, integer2) -> integer + integer2));
    reduce = list.stream().map(Person::getAge).reduce((Integer::sum));
    System.out.println("最终所有年龄的累加和是:" + reduce); // 172
    
    System.out.println("-------------------------------------------------------");
    // 11.实现将集合中所有元素的姓名映射出来并收集到集合中打印
    list.stream().map(Person::getName).collect(Collectors.toList()).forEach(System.out::println);
    

1.5 Optional类

  • Optional

    java.util.Optional类可以理解为一个简单的容器,其值可能是null或者不是null,代表一个值存在或不存在

    /*
    案例题目
    判断字符串是否为空,若不为空则打印字符串的长度,否则打印0
    */
    public class OptionalTest {
    
        public static void main(String[] args) {
    
            //String str1 = "hello";
            String str1 = null;
            if (null != str1) {
                System.out.println("字符串的长度是:" + str1.length()); // 5  空指针异常
            } else {
                System.out.println("字符串为空,因此长度为0!");
            }
    
            System.out.println("----------------------------------------------------");
            // Java8中使用Optional类实现空值的处理
            // 1.将数据str1装到Optional对象代表的容器中
            Optional<String> optional = Optional.ofNullable(str1);
            // 2.建立映射关系  使用字符串的长度与字符串建立映射关系
            /*Optional<Integer> integer = optional.map(new Function<String, Integer>() {
                @Override
                public Integer apply(String s) {
                    return s.length();
                }
            });*/
            //Optional<Integer> integer = optional.map(s -> s.length());
            Optional<Integer> integer = optional.map(String::length);
            // 3.若字符串为空则打印0,否则打印字符串的数值
            System.out.println("integer = " + integer); // Optional.empty
            System.out.println(integer.orElse(0)); // 0
        }
    }
    

2. JDK9

2.1 模块化

  • 在 module-info.java 文件中,我们可以用新的关键词module来声明一个模块,具体如下:

    module 模块名称 {
    }
    
  • 在项目的模块中,两个模块间使用模块化可以共用类

2.2 钻石操作符新特性

  • 在Java9中允许在匿名内部类的使用中使用钻石操作符

    public class DiamondTest {
    
        public static void main(String[] args) {
    
            // 实现匿名内部类和钻石操作符的搭配使用
            //Comparator<Integer> comparator = new Comparator<Integer>() {
            Comparator<Integer> comparator = new Comparator<>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return 0;
                }
            };
        }
    }
    

2.3 集合工厂方法

  • Java9的List、Set和Map集合中增加了静态工厂方法of实现不可变实例的创建。

    不可变体现在无法添加、修改和删除它们的元素。

    不允许添加null元素对象

    public class CollectionTest {
    
        public static void main(String[] args) {
    
            // 创建List类型的不可变实例
            List<Integer> list = List.of(1, 2, 3, 4, 5);
            //list.add(6); // 编译ok,运行发生UnsupportedOperationException不支持此操作的异常
            System.out.println(list); // [1, 2, 3, 4, 5]
    
            Set<Integer> set = Set.of(6, 7, 8);
            //set.add(null);// 编译ok,运行发生UnsupportedOperationException不支持此操作的异常
    
            Map<Integer, String> map = Map.of(1, "one", 2, "two");
            //map.put(3, "three");// 编译ok,运行发生UnsupportedOperationException不支持此操作的异常
        }
    }
    

2.4 InputStream的增强

  • InputStream类中提供了transferTo方法实现将数据直接传输到OutputStream中

    public class InputStreamTest {
    
        public static void main(String[] args) {
    
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                inputStream = new FileInputStream("d:/a.txt");
                outputStream = new FileOutputStream("d:/b.txt");
                inputStream.transferTo(outputStream); // 实现数据的复制,底层是read和write方法的调用
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (null != outputStream) {
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (null != inputStream) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

3. JDK10

3.1 局部变量类型推断

  • Java10可以使用var作为局部变量类型推断标识符,此符号仅适用于局部变量,增强for循环的索引,以及传统for循环的本地变量

    public class VarTest {
    
        public static void main(String[] args) {
    
            // 由初始值可以推断出变量的类型,因此可以使用var取代
            //int num = 10;
            var num = 10;
    
            //List<Integer> list = new LinkedList<>();
            var list = new LinkedList<Integer>();
            list.add(10);
    
            for (var v : list) {
                System.out.println(v);
            }
    
            for (var i = 0; i < 10; i++) {}
        }
    }
    

4. JDK11

4.1 简化的编译运行操作

4.2 String类新增方法

posted @ 2022-02-14 11:39  Ramentherapy  阅读(64)  评论(0)    收藏  举报