zoukankan      html  css  js  c++  java
  • Java 17 将要发布,补一下 Java 13 中的新功能

    点赞再看,动力无限。Hello world : ) 微信搜「 程序猿阿朗 」。

    本文 Github.com/niumoo/JavaNotes未读代码博客 已经收录,有很多知识点和系列文章。

    本文章属于 Java 新特性教程 系列,已经收录在 Github.com/niumoo/JavaNotes ,点个赞,不迷路。

    Java 13 by Alena Penkova

    自从 Oracle 调整了 Java 的版本发布节奏之后,Java 版本发布越来越快,虽然都说 Java 版本任他发,我用 Java 8,不过新版本的 Java 功能还是要学习一下的。

    Java 13 早在 2019 年 9 月就已经发布,虽然不是长久支持版本,但是也带来了不少新功能。

    Java 13 官方下载:https://jdk.java.net/archive/

    Java 13 官方文档:http://openjdk.java.net/projects/jdk/13/

    Java 13 新功能

    1. JEP 350: 动态 CDS 存档
    2. JEP 351: ZGC,归还未使用的内存 (实验性)
    3. JEP 353: 重新实现 Socket API
    4. JEP 354: Switch 表达式 (二次预览)
    5. JEP 355: 文本块 (预览)

    扩展:此文章属于 Java 新特性教程 系列,会介绍 Java 每个版本的新功能,可以点击浏览。

    1. JEP 350 动态 CDS 存档

    JVM 启动时有一步是需要在内存中加载类,而如果有多个 jar,加载第一个 jar 的速度是最慢的。这就延长了程序的启动时间,为了减少这个时间,Java 10 引入了应用程序类数据共享(CDS)机制,它可以把你想共享的类共享在程序之间,使不同的 Java 进程之间共享这个类来减少这个类占用的空间以及加载速度。不过 Java 10 中使用这个功能的步骤比较繁琐。

    扩展阅读:Java 10 新功能介绍

    而 Java 13 中的 AppCDS,允许 Java 应用在程序执行结束时(如果 JVM 没有崩溃)进行动态存档;存储的内容包括所有加载的应用类型类和使用的类库,这些存储的类库本来并不存在于默认的 CDS 存档中。

    使用这个功能非常简单,只需要在程序启动时增加启动参数 。

    # ArchiveClassesAtExit,程序结束时动态存档
    bin/java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello
    # SharedArchiveFile,使用指定存档启动
    bin/java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello
    

    2. JEP 351: ZGC,归还未使用的内存 (实验性)

    在 Java 13 之前,ZGC 虽然在清理内存时导致的停顿时间非常少,但是即使内存已经长时间没有使用,ZGC 也不会将内存返还给操作系统,这对那些十分关注内存占用的应用程序非常不友好。

    比如:

    • 资源按使用量付费的云上容器环境。

    • 应用虽然长时间闲置,但是占用了内存,导致运行的其他程序内存紧张。

    而新增的这个功能,可以让 ZGC 归还长时间没有使用的内存给操作系统,这对某些用户来说十分友好。

    3. JEP 353: 重新实现 Socket API

    java.net.Socketjava.net.ServerSocket 类早在 Java 1.0 时就已经引入了,它们的实现的 Java 代码和 C 语言代码的混合,维护和调试都十分不易;而且这个实现还存在并发问题,有时候排查起来也很困难。

    因此,在 Java 13 中引入了新的实现方式,使用了新的实现 NioSocketImpl 来代替老旧的 PlainSocketImpl 实现。虽然功能相同,但是老的方式在当前以及未来几个版本内不会删除,用户随时可以通过 -Djdk.net.usePlainSocketImpl 参数切换回老的实现方式,以兼容意外情况。

    编写一个测试类可以发现这个变化。

    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    public class Test {
        public static void main(String[] args) {
            try (ServerSocket serverSocket = new ServerSocket(8000)){
                boolean running = true;
                while(running){
                    Socket clientSocket = serverSocket.accept();
                    //do something with clientSocket
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    使用 Java 13 运行,通过参数 -XX:+TraceClassLoading 追踪加载的类,日志中可以看到 NioSocketImpl

    ➜  develop ./jdk-13.0.2.jdk/Contents/Home/bin/java -XX:+TraceClassLoading Test.java | grep SocketImpl
    [0.699s][info   ][class,load] java.net.SocketImpl source: jrt:/java.base
    [0.699s][info   ][class,load] java.net.SocketImpl$$Lambda$173/0x0000000800c37440 source: java.net.SocketImpl
    [0.702s][info   ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base
    [0.702s][info   ][class,load] sun.nio.ch.NioSocketImpl source: jrt:/java.base
    [0.713s][info   ][class,load] sun.nio.ch.NioSocketImpl$FileDescriptorCloser source: jrt:/java.base
    

    但在 Java 12 并不是 NioSocketImpl

    ➜  develop ./jdk-12.0.2.jdk/Contents/Home/bin/java -XX:+TraceClassLoading Test.java | grep SocketImpl
    [0.665s][info   ][class,load] java.net.SocketImpl source: jrt:/java.base
    [0.665s][info   ][class,load] java.net.AbstractPlainSocketImpl source: jrt:/java.base
    [0.665s][info   ][class,load] java.net.PlainSocketImpl source: jrt:/java.base
    [0.665s][info   ][class,load] java.net.SocksSocketImpl source: jrt:/java.base
    [0.666s][info   ][class,load] java.net.AbstractPlainSocketImpl$1 source: jrt:/java.base
    

    4. JEP 354: Switch 表达式 (二次预览)

    你为什么不愿意使用使用 switch 表达式?我想其中一个原因应该是, switch 表达式的代码不够美观优雅,甚至有些啰嗦。比如像下面的例子。

    package com.wdbyte;
    
    public class Java13Switch {
        public static void main(String[] args) {
          //通过传入月份,输出月份所属的季节
          System.out.println(switchJava12Before("march"));
        }
        public static String switchJava12Before(String month) {
            String reuslt = null;
            switch (month) {
                case "march":
                case "april":
                case "may":
                    reuslt = "春天";
                    break;
                case "june":
                case "july":
                case "august":
                    reuslt = "夏天";
                    break;
                case "september":
                case "october":
                case "november":
                    reuslt = "秋天";
                    break;
                case "december":
                case "january":
                case "february":
                    reuslt = "冬天";
                    break;
            }
            return reuslt;
        }
    }
    

    而在 Java 12 中,已经对 switch 进行了改进,使之可以使用 cast L -> 表达式进行操作,且可以具有返回值,这样代码就更加美观使用了,不过这在 Java 12 中是一个预览功能。

    // 通过传入月份,输出月份所属的季节
    public static String switchJava12(String month) {
         return switch (month) {
            case "march", "april", "may"            -> "春天";
            case "june", "july", "august"           -> "夏天";
            case "september", "october", "november" -> "秋天";
            case "december", "january", "february"  -> "冬天";
            default -> "month erro";
        };
    }
    

    扩展阅读:Java 12 新特性介绍JEP 325: Switch 表达式

    而现在,在 Java 13 中,又对 switch 表达式进行了增强,增加了yield 关键词用于返回值,相比 break ,语义更加明确了。

    public static String switchJava13(String month) {
        return switch (month) {
            case "march", "april", "may":
                yield "春天";
            case "june", "july", "august":
                yield "夏天";
            case "september", "october", "november":
                yield "秋天";
            case "december", "january", "february":
                yield "冬天";
            default:
                yield "month error";
        };
    }
    

    5. JEP 355: 文本块 (预览)

    在这之前,如果我们把一个 JSON 赋值给字符串:

    String content = "{
    "
        + "    "upperSummary": null,
    "
        + "    "sensitiveTypeList": null,
    "
        + "    "gmtModified": "2011-08-05 10:50:09",
    "
        + "    "lowerGraph": null,
    "
        + "    "signature": "",
    "
        + "    "appName": "xxx",
    "
        + "    "lowerSummary": null,
    "
        + "    "gmtCreate": "2011-08-05 10:50:09",
    "
        + "    "type": "CALL",
    "
        + "    "name": "xxxx",
    "
        + "    "subType": "yyy",
    "
        + "    "id": 1,
    "
        + "    "projectId": 1,
    "
        + "    "status": 1
    "
        + "}";
    

    终于不用写丑陋的长字符串了,从 Java 13 开始你可以使用文本块的方式定义字符串了。

    String content2 = """
            {
            "upperSummary": null,
            "sensitiveTypeList": null,
            "gmtModified": "2011-08-05 10:50:09",
            "lowerGraph": null,
            "signature": "",
            "appName": "xxx",
            "lowerSummary": null,
            "gmtCreate": "2011-08-05 10:50:09",
            "type": "CALL",
            "name": "xxxx",
            "subType": "yyy",
            "id": 1,
            "projectId": 1,
            "status": 1
        }
                     """;
    

    不过这是一个预览功能,如果你要是在 Java 13 中使用需要手动开启预览功能,这个功能在 Java 15 中正式发布。

    如果你想尝试,可以去下载最新版了,玩的开心。

    参考

    1. http://openjdk.java.net/projects/jdk/13/
    2. https://nipafx.dev/java-application-class-data-sharing/
    3. https://www.wdbyte.com/2020/02/jdk/jdk12-feature/
    4. https://mkyong.com/java/what-is-new-in-java-13/
    5. Java 新特性教程

    相关阅读

    <完>

    Hello world : ) 我是阿朗,一线技术工具人,认认真真写文章。

    点赞的个个都是人才,不仅长得帅气好看,说话还好听。


    文章持续更新,可以关注公众号「 程序猿阿朗 」或访问「未读代码博客 」。

    回复【资料】有我准备的各系列知识点和必看书籍。

    本文 Github.com/niumoo/JavaNotes 已经收录,有很多知识点和系列文章,欢迎Star。

    等你好久

  • 相关阅读:
    python数据分析常用包之Matplotlib
    python数据分析常用包之Scipy
    python数据分析常用包之Pandas
    python数据分析常用包之numpy
    常见算法之‘插入类排序’
    CRM管理系统流程.king_admin
    常见算法之‘选择排序’
    常见的算法排序之交换类排序
    常用正则表达式
    scss在ide的命令参数
  • 原文地址:https://www.cnblogs.com/niumoo/p/15116813.html
Copyright © 2011-2022 走看看