• 这里有你不得不了解的Java 11版本特性说明


    • 「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」
    • 当然 不论新老朋友 我相信您都可以 从中获益。如果觉得 「不错」 的朋友,欢迎 「关注 + 留言 + 分享」,文末有完整的获取链接,您的支持是我前进的最大的动力!

    Java 11 为什么重要?

    Java 11 是继 Java 8 之后的第二个 LTS(long-term support)版本。自 Java 11 起,Oracle JDK 将不再免费提供商业用途

    您可以在开发阶段使用它,但要在商业上使用它,则需要购买许可证。

    Java 10 是最后一个可以下载的免费 Oracle JDK。

    Oracle 从 2019 年 1 月开始就停止了对 Java 8 的支持。您需要支付更多的支持费用。

    如果不这样做,虽然您可以继续使用它,但不会获得任何补丁/ 安全更新。

    自 Java 11 起,Oracle 将不再为任何单个 Java 版本提供免费的长期支持(LTS)。

    尽管 Oracle JDK 不再免费,但是您始终可以从 Oracle 或其他提供商(例如 AdoptOpenJDK,Azul,IBM,Red Hat 等..)下载 Open JDK 构建。

    什么是 LTS Module

    从 2017 年开始,Oracle 和 Java 社区宣布了向 Java 的新 6 个月节奏的转变。它已迁移到 Oracle Java SE 产品的长期支持(LTS)模型。

    LTS 版本的产品将提供 Oracle 的首要和持续的支持,目标是每三年一次。

    每个 Java 版本都以一两个主要特性为模型,这些特性驱动了版本的发布。任何障碍都会推迟发布和上市时间。Jigsaw 项目就是 Java 9 的一个主要特性,它多次推迟了发布日期,并且发布时间被推迟了超过 1.5 年。6 个月一版的发车节奏将让特性紧随。发布的列车每 6 个月有一个时间表。赶上这列火车的特征会被留下,否则他们就等下一班火车。

    Oracle JDK 与 Open JDK

    为了对开发人员更加友好,Oracle & Java 社区现在将 OpenJDK 二进制文件作为主要 JDK 进行推广。

    这与早期的 JDK 二进制文件是由 Oracle 专有并由 Oracle 许可的模式相比,很大程度上减轻了人们的负担,因为 Oracle 对重新发布有各种限制。

    然而,Oracle 将继续生产他们的 JDK,但仅限于长期支持版本。这是朝着对云和容器更友好的方向迈出的一步,因为开放 JDK 二进制文件可以作为容器的一部分分发。

    Open JDK 的二进制文件每 6 个月发布一次,而 Oracle JDK 的二进制文件每 3 年发布一次(LTS版本)。

    特性总览

    在了解完了 Java 11 附带的负担之后,现在让我们作为开发人员分析 Java 11 中的重要功能。

    以下是 Java 11 中的引入的部分新特性。关于 Java 11 新特性更详细的介绍可参考这里

    • 基于嵌套的访问控制(JEP 181)
    • 使用单个命令运行Java文件(JEP 330)
    • Lambda 参数的局部变量语法(JEP 323)
    • 动态类文件常量(JEP 309)
    • HTTP 客户端(JEP 321)
    • Epsilon-无操作垃圾收集器(JEP 318)
    • 可扩展的低延迟垃圾收集器-ZGC(JEP 333)
    • Unicode 10(JEP 327)
    • 低开销堆分析(JEP 331)
    • API 变更
    • 其他变更
      • 删除 Java EE 和 CORBA 模块(JEP 320)
      • 飞行记录器(JEP 328)
      • ChaCha20 和 Poly1305 加密算法(JEP 329)
      • 改进 Aarch64 内部特征(JEP 315)
      • 弃用 Nashorn JavaScript 引擎(JEP 335)
      • 传输层安全性(TLS)1.3(JEP 332)
      • 弃用 Pack200 工具和 API(JEP 336)

    一. 基于嵌套的访问控制(JEP 181)

    在 Java 11 之前,从嵌套类访问主类的 private 方法是可能的:

    public class Main {
     
        public void myPublic() {
        }
     
        private void myPrivate() {
        }
     
        class Nested {
    
            public void nestedPublic() {
                myPrivate();
            }
        }
    }
    

    但是,如果我们使用反射,它就会给出一个 IllegalStateException

    jshell> Main ob = new Main();
    ob ==> Main@533ddba
    
    jshell> import java.lang.reflect.Method;
    
    jshell> Method method = ob.getClass().getDeclaredMethod("myPrivate");
    method ==> private void Main.myPrivate()
    
    jshell> method.invoke(ob);
    |  异常错误 java.lang.IllegalAccessException:class REPL.$JShell$15 cannot access a member of class REPL.$JShell$11$Main with modifiers "private"
    |        at Reflection.newIllegalAccessException (Reflection.java:376)
    |        at AccessibleObject.checkAccess (AccessibleObject.java:647)
    |        at Method.invoke (Method.java:556)
    |        at (#5:1)
    
    jshell>
    

    这是因为 JVM 访问规则不允许嵌套类之间进行私有访问。我们能通过第一种方式访问是因为 JVM 在编译时为我们隐式地创建了私有的 桥接方法

    而且这发生在幕后。这种桥接方法会稍微增加已部署应用程序的大小,并可能使用户和工具感到困惑。

    Java 11 引入嵌套访问控制解决了这一问题。

    Java 11 将嵌套的概念和相关的访问规则引入了JVM。这简化了 Java 源代码编译器的工作。

    为此,类文件格式现在包含两个新属性:

    1. 一个嵌套成员(通常是顶级类)被指定为嵌套主类。它包含一个属性(NestMembers)来标识其他静态已知的嵌套成员。
    2. 其他每个嵌套成员都有一个属性(NestHost)来标识其嵌套主类。

    因此,要使类型 C 和 D 成为嵌套伙伴,它们必须具有相同的嵌套主类。如果类型 C 在其 NestHost 属性中列出 D,则它声称是 D 托管的嵌套的成员。如果 D 还在其 NestMembers 属性中列出 C ,则将验证成员资格。另外,类型 D 隐式为其所托管的嵌套成员。

    现在,编译器无需生成桥接方法

    java.lang.Class 在反射 API 中介绍了三种方法:getNestHost()getNestMembers(),和isNestmateOf(),用于支持上述的工作。

    更多请阅读:https://www.baeldung.com/java-nest-based-access-control

    二. 使用单个命令运行Java文件(JEP 330)

    该 JEP 是在学习 Java 早期阶段的一个友好功能,但是在实际的 Java 开发中没有太大的用处,我们都使用 IDE。

    假设我们现在有以下的源代码(.java 文件):

    public class HelloJava {
    
        public static void main(String[] args) {
            System.out.println("Hello World!");
        }
    }
    

    在 Java 11 编译运行需要:

    $ javac HelloJava.java
    
    $ java HelloJava
    
    Hello World!
    

    在 Java 11 中:

    $ java HelloJava.java
    
    Hello World!
    

    另外,我们也可以使用 Linux Shebang 运行单个的 Java 程序:

    #!/opt/java/openjdk/bin/java --source 11
    public class SheBang {
    
        public static void main(String[] args) {
    
            System.out.println("Hello World!");
    
        }
    }
    

    这里是在 Docker 中如此使用 Linux Shebang 运行 Java 的例子:https://mkyong.com/java/java-11-shebang-example-in-docker/

    三. Lambda 参数的局部变量语法(JEP 323)

    该 JEP 是 Java 11 中唯一的语言功能的加强。

    我们知道,在 Java 10 中,引入了局部变量类型推断。因此,我们可以从 RHS 推断出变量的类型:var list = new ArrayList<String>();

    JEP 323 允许 var 用于声明隐式类型的 Lambda 表达式的形式参数:

    List<String> list = Arrays.asList("关注", "我没有三颗心脏", "更多精彩内容分享");
    String result = list.stream()
            .map((var x) -> x.toUpperCase())
            .collect(Collectors.joining(","));
    System.out.println(result2);
    

    上面与下面这个等效:

    List<String> list = Arrays.asList("关注", "我没有三颗心脏", "更多精彩内容分享");
    String result = list.stream()
            .map(x -> x.toUpperCase())
            .collect(Collectors.joining(","));
    

    这(省略类型声明的形式)在 Java 8 中也是允许的,但是在 Java 10 中删除了。现在,它又回到 Java 11 中以保持一致。

    为什么支持 var 来声明隐式的 Lambda 参数呢?(特别是当我们只需跳过 Lambda 类型时)

    答案是如果您想要像 @NotNull 一样 注释参数 时,则不能在不定义类型的情况下这样做:

    import org.jetbrains.annotations.NotNull;
    
    List<String> list = Arrays.asList("关注", "我没有三颗心脏", "更多精彩内容分享", null);
    String result = list.stream()
      .map((@NotNull var x) -> x.toUpperCase())
      .collect(Collectors.joining(","));
    System.out.println(result3);
    

    此功能也有一定的 局限性——您必须在所有参数上指定 var 类型,或者不指定任何类型。

    在用于 Lambda 内部的参数声明中,不可能出现以下这几种情况:

    (var s1, s2) -> s1 + s2 //no skipping allowed
    (var s1, String y) -> s1 + y //no mixing allowed
    
    var s1 -> s1 //not allowed. Need parentheses if you use var in lambda.
    

    四. 动态类文件常量(JEP 309)

    为了使 JVM 对动态语言更具吸引力,Java SE 7 已将 invokedynamic 引入了其指令集。Java 开发人员通常不会注意到此功能,因为它隐藏在 Java 字节码中。

    简而言之,通过使用 invokedynamic,可以将方法调用的绑定延迟到第一次调用之前。

    例如,Java 语言使用此技术来实现 Lambda 表达式,这些表达式仅在首次使用时才需要出现。

    如此,invokedynamic 已发展成为一种基本的语言功能。在 constantdynamic 中,Java 11 引入了一种类似的机制,只是它延迟的是常数值的创建。

    但 Java 11 本身缺少对 constantdynamic 的支持,所以这里不做详细赘述。

    这篇文章详细讨论了该特性的目的和内部工作原理,并展示了如何使用 Byte Buddy 库生成使用此新指令的代码,感兴趣的可以阅读一下:https://mydailyjava.blogspot.com/2018/08/hands-on-constantdynamic-class-file.html

    五. HTTP 客户端(JEP 321)

    Java 11 标准化了 Http CLient API。

    新的 API 支持 HTTP / 1.1 和 HTTP / 2。它旨在提高客户端发送请求和从服务器接收响应的整体性能。它还原生支持 WebSockets。

    下面是一个使用 Java 11 HttpClient 发送一个简单 GET 请求的例子:

    HttpClient httpClient = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_1_1)
            .connectTimeout(Duration.ofSeconds(10))
            .build();
    
    HttpRequest request = HttpRequest.newBuilder()
            .GET()
            .uri(URI.create("https://www.wmyskxz.com"))
            .setHeader("User-Agent", "Java 11 HttpClient Bot")
            .build();
    
    HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    
    HttpHeaders headers = response.headers();
    headers.map().forEach((k, v) -> System.out.println(k + ":" + v));
    
    System.out.println(response.statusCode());
    System.out.println(response.body());
    

    关于 HttpClient 更多内容请阅读:https://mkyong.com/java/java-11-httpclient-examples/

    六. Epsilon-无操作垃圾收集器(JEP 318)

    与负责分配内存并释放内存的 JVM GC 不同,Epsilon 仅分配内存。

    它为以下内容分配内存:

    • 性能测试。
    • 内存压力测试。
    • VM 接口测试。
    • 寿命极短的工作。
    • 最后一滴延迟改进。(Last-drop latency improvements.)
    • 最终吞吐量提高。

    现在,Elipson 仅适用于测试环境。这将导致生产中的 OutOfMemoryError 并使应用程序崩溃。

    Elipson 的好处是没有内存清除开销。因此,它将给出准确的性能测试结果,我们不再可以通过 GC 来停止它。

    注意:这是一项实验性功能。

    七. 可扩展的低延迟垃圾收集器-ZGC(JEP 333)

    Z垃圾收集器(ZGC)是可伸缩的低延迟垃圾收集器。ZGC 可以同时执行所有昂贵的工作,而不会将应用程序线程的执行停止超过 10 毫秒,这使得它们适合于要求低延迟和/或使用非常大的堆(数TB)的应用程序。

    Z 垃圾收集器可作为实验功能使用,可以通过命令行选项启用 -XX:+UnlockExperimentalVMOptions -XX:+UseZGC

    (ps:该垃圾收集器在 JDK 15 才生产准备就绪——JEP 377——所以可以不怎么关注它,因为我们大概率很长一段时间都不会用上)

    OpenJDK-wiki:https://wiki.openjdk.java.net/display/zgc/Main

    八. Unicode 10(JEP 327)

    以下是 Unicode 10.0 发行版中可用的新表情符号:

    关于 Unicode 10.0 的更新,你可以在 这里 看到详细的内容,概括起来就是:

    “ Unicode 10.0增加了8,518个字符,总共136,690个字符。这些增加包括4个新脚本,总共139个脚本,以及56个新表情符号字符。”

    代码演示:

    public class PrintUnicode {
    
        public static void main(String[] args) {
            String codepoint = "U+1F92A";   // crazy face
            System.out.println(convertCodePoints(codepoint));
        }
    
        // Java, UTF-16
        // Convert code point to unicode
        static char[] convertCodePoints(String codePoint) {
            Integer i = Integer.valueOf(codePoint.substring(2), 16);
            char[] chars = Character.toChars(i);
            return chars;
    
        }
    }
    

    好文推荐:

    在 Java 中使用 Unicode 的乐趣:https://www.codetab.org/post/java-unicode-basics/

    该文章详细介绍了编码和解码以及 Unicode 的基础知识,并通过 Java 编程详细的展示了 Unicode 在 Java 中的使用例子。

    九. 低开销堆分析(JEP 331)

    Java 虚拟机工具接口(JVM TI)是在 Java SE 5 引入的,它可以监控 JVM 内部事件的执行,也可以控制 JVM 的某些行为,可以实现调试、监控、线程分析、覆盖率分析工具等。

    该 JEP 在 JVM TI 中添加了新的低开销的堆分析 API。

    进一步阅读:Oracle 官方 JVM TI 文档 - https://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html

    十. API 变更

    字符串新增方法

    isBlank()

    isBlank() ——此实例方法返回一个布尔值。空字符串和仅包含空格的字符串将被视为空。

    import java.util.*;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            System.out.println(" ".isBlank()); //true
            
            String s = "wmyskxz";
            System.out.println(s.isBlank()); //false
            String s1 = "";
            System.out.println(s1.isBlank()); //true
        }
    }
    

    lines()

    此方法返回字符串流,它是按行分割的所有子字符串的集合。

    jshell> import java.util.stream.Collectors;
    
    jshell> String str = "JD
    JD
    JD";
    str ==> "JD
    JD
    JD"
    
    jshell> System.out.println(str);
    JD
    JD
    JD
    
    jshell> System.out.println(str.lines().collect(Collectors.toList()));
    [JD, JD, JD]
    
    jshell>
    

    strip() / stripLeading() / stripTrailing()

    strip()——删除字符串开头和结尾的空格。

    stripLeading()——删除字符串开头的空格。

    stripTrailing()——删除字符串结尾的空格。

    jshell> String str = " 我没有三颗心脏 ";
    str ==> " 我没有三颗心脏 "
    
    jshell> System.out.print("关注" + str.strip() + "更多精彩内容");
    关注我没有三颗心脏更多精彩内容
    jshell> System.out.print("关注" + str.stripLeading() + "更多精彩内容");
    关注我没有三颗心脏 更多精彩内容
    jshell> System.out.print("关注" + str.stripTrailing() + "更多精彩内容");
    关注 我没有三颗心脏更多精彩内容
    jshell>
    

    repeat(int)

    repeat 方法简单地以 int 形式将字符串重复多次。

    jshell> String str = "关注【我没有三颗心脏】获取更多精彩内容!".repeat(3);
    str ==> "关注【我没有三颗心脏】获取更多精彩内容!关注【我没有三颗心脏】获取更多精彩内容!关注【我没有三颗心脏】获取更多精彩内容!"
    
    jshell>
    

    文件读写字符串

    Java 11 致力于 String 的读写变得方便。它引入了以下用于读写文件的方法:

    • readString();
    • writeString();

    以下是代码示例:

    Path path = Files.writeString(Files.createTempFile("test", ".txt"), "This was posted on wmyskxz.com");
    System.out.println(path);
    String s = Files.readString(path);
    System.out.println(s); //This was posted on wmyskxz.com
    

    十一. 其他变更

    删除 Java EE 和 CORBA 模块(JEP 320)

    Java 9 中已经弃用了这些模块,现在将它们完全删除。

    下面的包被删除:java.xml.wsjava.xml.bindjava.activationjava.xml.ws.annotationjava.corbajava.transactionjava.se.eejdk.xml.wsjdk.xml.bind

    飞行记录器(JEP 328)

    Flight Recorder 以前是 Oracle JDK 中的商业附加组件,现已开放源代码,因为 Oracle JDK 本身已不再免费。

    JFR 是一种分析工具,用于从正在运行的 Java 应用程序中收集诊断信息和分析数据。它的性能开销可以忽略不计,通常低于 1%。因此,它可以用于生产应用。

    默认情况下,JVM 禁用了 JFR,要启动 JFR,必须使用 -XX:+FlightRecorder 选项启动。例如,我们要启动名为 MyApp 的应用程序:

    java -XX:+ UnlockCommercialFeatures -XX:+ FlightRecorder MyApp
    

    Java Fliight Recorder 小试牛刀 - https://juejin.im/post/6844903684912988167

    ChaCha20 和 Poly1305 加密算法(JEP 329)

    Java 11 提供了 ChaCha20 和 ChaCha20-Poly1305 密码实现。这些算法将在 SunJCE 提供程序中实现。

    有详细了解需求的朋友可以参看:https://mkyong.com/java/java-11-chacha20-poly1305-encryption-examples/

    改进 Aarch64 内部特征(JEP 315)

    改进现有的字符串和数组内在函数,并在 AArch64 处理器上为 java.lang.Math 包下的 sincoslog 函数实现新的内在函数。

    弃用 Nashorn JavaScript 引擎(JEP 335)

    Nashorn JavaScript脚本引擎和jjs工具已被弃用,将来的发行版中可能会删除它。

    (ps:Nashorn 是在 Java 8 JEP 174 中引入,以代替 Rhino Javascript 引擎。)

    传输层安全性(TLS)1.3(JEP 332)

    Java 11 支持 RFC 8446 传输层安全性(TLS)1.3协议。但是,并非所有TLS 1.3功能都已实现,有关详细信息,请参考此 JEP 332

    Java 安全套接字扩展(JSSE)+ TLS 1.3 示例。

    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.SSLSocketFactory;
    
    SSLSocketFactory factory =
            (SSLSocketFactory) SSLSocketFactory.getDefault();
    socket =
            (SSLSocket) factory.createSocket("google.com", 443);
    
    socket.setEnabledProtocols(new String[]{"TLSv1.3"});
    socket.setEnabledCipherSuites(new String[]{"TLS_AES_128_GCM_SHA256"});
    

    弃用 Pack200 工具和 API(JEP 336)

    该 JEP 不推荐 pack200unpack200 工具以及软件包中的 Pack200 API java.util.jar,并且可能会在将来的版本中删除。

    (ps:Java 14 JEP 367 中删除了 Pack200 工具和 API 。)

    参考资料

    1. OpenJDK 官方说明 - http://openjdk.java.net/projects/jdk/10/
    2. Java 11 Features - https://www.journaldev.com/24601/java-11-features
    3. What is new in Java 11 - https://mkyong.com/java/what-is-new-in-java-11/
    4. Java 11 Nest Based Access Control | Baeldung - https://www.baeldung.com/java-nest-based-access-control

    文章推荐

    1. 这都JDK15了,JDK7还不了解? - https://www.wmyskxz.com/2020/08/18/java7-ban-ben-te-xing-xiang-jie/
    2. 全网最通透的 Java 8 版本特性讲解 - https://www.wmyskxz.com/2020/08/19/java8-ban-ben-te-xing-xiang-jie/
    3. Java9的这些史诗级更新你都不知道? - https://www.wmyskxz.com/2020/08/20/java9-ban-ben-te-xing-xiang-jie/
    4. 你想了解的 JDK 10 版本更新都在这里 - https://www.wmyskxz.com/2020/08/21/java10-ban-ben-te-xing-xiang-jie/
    5. 「MoreThanJava」系列文集 - https://www.wmyskxz.com/categories/MoreThanJava/
    • 本文已收录至我的 Github 程序员成长系列 【More Than Java】,学习,不止 Code,欢迎 star:https://github.com/wmyskxz/MoreThanJava
    • 个人公众号 :wmyskxz,个人独立域名博客:wmyskxz.com,坚持原创输出,下方扫码关注,2020,与您共同成长!

    非常感谢各位人才能 看到这里,如果觉得本篇文章写得不错,觉得 「我没有三颗心脏」有点东西 的话,求点赞,求关注,求分享,求留言!

    创作不易,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!

  • 相关阅读:
    04.DRF-开发REST 接口
    03.DRF-设计方法
    02.DRF-认识RESTful
    01.DRF-Web应用模式
    14.Django-xadmin和富文本编辑器
    13.Django-分页
    12.Django-admin
    11.Django-form表单上传文件
    android 基于wifi模块通信开发
    android蓝牙通讯开发(详细)
  • 原文地址:https://www.cnblogs.com/wmyskxz/p/13544669.html
Copyright © 2020-2023  润新知