美文网首页
JDK8 新增功能 ( Java 语言新特性 )

JDK8 新增功能 ( Java 语言新特性 )

作者: 张云飞Vir | 来源:发表于2021-07-13 23:38 被阅读0次

    1. 背景

    JDK8 是一个主要功能版本。本文档总结了其中的特性和增强功能。

    说明:用更少的简洁文字和易读代码来表达。

    2. Java 语言新特性

    2.1 默认接口方法

    在接口里可以写一个 “ 默认方法 ”,它可以在 不强制必须实现这个方法,从而很方便的往现存接口中添加新的方法。

    package com.zhangyf.javademo.stage1;
    
    /**
     * 示例:接口中写"默认方法"
     */
    interface IDemo {
        void hello(); // 这个方法需要 "被实现"。
    
        // 默认方法,不需要  "被实现"。
        default void hi() {
            System.out.println("hi,zyf");
        }
    }
    
    class Demo1 implements IDemo {
    
        // 实现类仅仅 "实现 hello 方法就可。
        // 默认方法 hi 无需实现了。
        @Override
        public void hello() {
            System.out.println("hello,zyf");
        }
    }
    
    // 执行示例
    class Stage1 {
    
        public static void main(String[] args) {
            Demo1 demo1 = new Demo1();
            demo1.hello();
            demo1.hi();
        }
    
    }
    

    “ 默认方法 ” 功能也称为扩展方法。适用于“ 为现有的类扩展新增新方法功能的场景 ”

    2.2 lambda 表达式

    /**
     * 示例:Lambda 表达式
     */
    public class Stage2 {
        public static void main(String[] args) {
            List<String> names = Arrays.asList("banana", "apple", "mike", "xenia");
            // 使用 Lambda 时:很简洁。
            Collections.sort(names, (a, b) -> a.compareTo(b));
            System.out.println("排序后:" + names);
        }
    }
    
    

    再看下,当不用 Lambda ,传统写法,很长。

            Collections.sort(names, new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return o1.compareTo(o2);
                }
            });
    

    java 编译器知道参数类型,因此您也可以省略来写。

    2.3 函数式接口

    单方法接口(称为函数式接口)

    函数式接口必须只包含一个抽象方法声明,为了防止意外的添加第二方法而导致错误,可以用 @FunctionalInterface 注解来加强声明定义,声明后编译器会帮你做检查符合函数式接口。

    函数式接口 配合 Lambda 表达式可以更简洁地表达。

    // 定义一个 " 函数式接口 ",它必须只有一个方法。
    @FunctionalInterface
    interface MyConverter<FROM, TO> {
        TO convert(FROM from);
    }
    
    class MainClass3 {
    
        public static void main(String[] args) {
            //使用 lambda 实现了一个 "函数式接口": 将 字符串 转换成 整数
            MyConverter<String, Integer> myConvert = (from) -> Integer.valueOf(from);
            //使用 "函数式接口"
            int intPara = myConvert.convert("1234");
    
            System.out.println(intPara);
        }
    
    }
    

    2.4 方法引用 ( 通过 :: 和方法名称 )

    Java 8 允许您通过::关键字传递方法的引用。上面的例子进一步简化:

    @FunctionalInterface
    interface MyConverter1<FROM, TO> {
        TO convert(FROM from);
    }
    
    class MainClass4 {
        public static void main(String[] args) {
            MyConverter1<String, Integer> myConvert = Integer::valueOf;
            int intPara = myConvert.convert("1234");
            System.out.println(intPara);
        }
    }
    

    上面代码中的 Integer::valueOf 意思是 引用 Integer.valueOf 方法,可以作为参数传递使用了。

    2.5 "方法引用" 也可以引用构造方法

    class User {
        String name;
        int age;
    
        // 构造方法1:无参
        public User() {
        }
    
        // 构造方法2:两个参数
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return name + "_" + age;
        }
    }
    
    // 一个工厂。注意是个 接口, 不是实现类
    interface UserFactory {
        User create(String name, int age);
    }
    
    // 调用者
    class MainClass5 {
        public static void main(String[] args) {
            // 通过方法引用了 User类的构造方法,好像 "粘" 在了一起。
            UserFactory userFactory = User::new;
            // 编译器通过推断,识别到 "这是两个参数的构造方法"
            User user = userFactory.create("zyf", 30);
            System.out.println(user);
        }
    }
    
    

    2.6 接口里可写“静态方法”

    interface InterfaceDemo6 {
        static void createEntity() {
            System.out.println("createEntity....");
        }
    }
    
    // 调用者
    class MainClass6 {
        public static void main(String[] args) {
            InterfaceDemo6.createEntity();
        }
    }
    

    2.7 可重复注解(一个注解可在方法里写多次)

    以前在同一个地方不能多次使用同一个注解。Java 8引入了重复注解的概念,允许在同一个地方多次使用同一个注解。

    @interface Hints {
        Hint[] value();
    }
    
    @Repeatable(Hints.class)
    @interface Hint {
        String value();
    }
    
    @Hint("hint1")
    @Hint("hint2")
    class Person {
        ...
    }
    

    3. 扩展:内置的函数接口

    JDK 1.8 API 包含许多内置 函数式接口(功能接口),这些接口经过 @FunctionalInterface 注解后 扩展已可以对 Lambda 支持。

    3.1 谓词(Predicates)

    根据给定的参数计算该谓词, 返回一个 boolean 结果。方法原型:

        boolean test(T t);
    

    示例:

            // 谓词 Predicate
            Predicate<String> n1 = (s) -> s.length() > 0;
            boolean foo = n1.test("foo"); // true
            Predicate n2 = Objects::isNull;
            Predicate<String> n3 = String::isEmpty;
    
    

    3.2 Functions

    它可以引用一个 指定 一个参数,和返回值 的方法。
    方法原型:

    R apply(T t);
    

    示例:

         // 功能 Function
            Function<String, Integer> f1 = Integer::valueOf;
            Integer interge1 = f1.apply("33432");
    

    3.3 提供者 Supplier

    它可以引用一个 构造方法。用于 返回一个对象
    方法原型:

        T get();
    

    示例:

    // 提供者 Supplier ,它可以引用一个 构造方法
            Supplier supplier1 = Object::new;
            supplier1.get();
    

    3.4 Consumers 消费者

    Consumers, 它可以引用 "一个参数",无返回值的方法
    方法原型:

        void accept(T t);
    

    示例:

            Consumer<String> consumer1 = (str) -> System.out.println(str);
            Consumer<String> consumer2 = System.out::println;
            consumer2.accept("hello");
    

    3.5 比较器 Comparator

    方法原型:

        int compare(T o1, T o2);
    

    示例:

    Comparator<String> comparator1 = (p1, p2) -> p1.compareTo(p2);
    comparator1.compare("P1","p3");
    

    3.6 “可选的” Optional

    Optional, 它不是一个 函数式接口。它 用于辅助判断 空值

            Optional<String> optional1 = Optional.of("some");
            optional1.isPresent(); // 有值,则 true
            optional1.get();
    

    4. 流:Stream

    Steam API极大得简化了集合操作,非常地强大。

    // 准备演示数据
    List<String> lst = new ArrayList<>();
    lst.add("s1");
    lst.add("s99");
    lst.add("s3");
    lst.add("ccc");
    lst.add("zzz");
    lst.add("111");
    
    System.out.println("-------- 示例:filter ---------");
    // filter 过滤器:接收一个表达式判断,返回boolean值,决定是否过滤掉
    lst.stream().filter((it) -> it.startsWith("s")).forEach(System.out::println);
    
    System.out.println("-------- 示例:sorted ---------");
    // sorted:排序
    lst.stream().sorted().forEach(System.out::println);
    
    System.out.println("-------- 示例:map ---------");
    // map:对子元素 map 映射后,成为新的集合
    lst.stream().map(String::toUpperCase).forEach(System.out::println);
    
    System.out.println("-------- 示例:匹配 ---------");
    // anyMatch: 只要有一个 匹配成功
    boolean result1 = lst.stream().anyMatch((s) -> s.startsWith("c"));
    System.out.println(result1);// true
    // allMatch: 都匹配成功,则为 true
    boolean result2 = lst.stream().allMatch((s) -> s.startsWith("c"));
    System.out.println(result2);// fasle
    // noneMatch : 都不匹配,则为 true
    boolean result3 = lst.stream().noneMatch((s) -> s.startsWith("$"));
    System.out.println(result3);//
    
    System.out.println("-------- 示例:count ---------");
    // count: 计算总数。 先过滤 s 开头的,再计算个总数
    long count1 = lst.stream().filter((p) -> p.startsWith("s")).count();
    System.out.println("count1=" + count1);//
    
    System.out.println("-------- 示例:reduce ---------");
    // reduce: 归纳。 传入两个参数,返回一个结果
    Optional<String> optional = lst.stream().sorted().reduce((t1, t2) -> t1 + "," + t2);
    System.out.println("optional=" + optional);//
    

    stream 也支持并行处理
    参考我的另一篇文章:https://www.jianshu.com/p/941fc03867ff

    5.扩展:日期 API

    Java 8 在包下包含一个全新的日期和时间的API。

    // 获得 系统的默认时区对应的 时钟对象
    Clock clock = Clock.systemDefaultZone();
    // 获得毫秒值
    long millis = clock.millis();
    System.out.println("millis: " + millis);
    
    // 本地时间
    LocalTime now1 = LocalTime.now();
    System.out.println("now1: " + now1); // 23:34:46.112
    
    // 本地时间
    LocalDate now2 = LocalDate.now();
    System.out.println("now2: " + now2); // 2021-07-13
    
    // 本地时间
    LocalDateTime now3 = LocalDateTime.now();
    System.out.println("now2: " + now3); // 2021-07-13T23:34:46.113
    
    // 持续时间
    LocalDateTime start = LocalDateTime.now();
    Thread.sleep(1234);
    LocalDateTime end = LocalDateTime.now();
    // 两个时间之间的差
    Duration duration = Duration.between(start, end);
    long mill = duration.toMillis();
    System.out.println("mill: " + mill);
    

    我的代码示例见:https://github.com/vir56k/java_demo/tree/master/java_new_feature_demo

    6.参考:

    更多新特性请阅读:https://www.oracle.com/java/technologies/javase/8-whats-new.html

    Java 语言更新
    https://docs.oracle.com/en/java/javase/15/language/java-language-changes.html#GUID-6459681C-6881-45D8-B0DB-395D1BD6DB9B

    https://docs.oracle.com/javase/tutorial/java/index.html

    https://docs.oracle.com/en/java/javase/15/language/local-variable-type-inference.html

    https://www.oracle.com/java/technologies/javase/8-whats-new.html

    相关文章

      网友评论

          本文标题:JDK8 新增功能 ( Java 语言新特性 )

          本文链接:https://www.haomeiwen.com/subject/qhlspltx.html