乐趣区

关于java:Java-18-新功能介绍

大家好啊,我是阿朗,最近工作中须要用到限流,这篇文章介绍常见的限流形式。

文章继续更新,能够关注公众号程序猿阿朗或拜访未读代码博客。
本文 Github.com/niumoo/JavaNotes 曾经收录, 欢送 Star。
Java 18 在 2022 年 3 月 22 日正式公布,Java 18 不是一个长期反对版本,这次更新共带来 9 个新性能。

OpenJDK Java 18 下载:https://jdk.java.net/18/

OpenJDK Java 18 文档:https://openjdk.java.net/projects/jdk/18/

JEP 形容
JEP 400 默认为 UTF-8
JEP 408 简略的网络服务器
JEP 413 Java API 文档中的代码片段
JEP 416 应用办法句柄从新实现外围反射
JEP 417 Vector API(三次孵化)
JEP 418 互联网地址解析 SPI
JEP 419 Foreign Function & Memory API (二次孵化)
JEP 420 switch 模式匹配(二次预览)
JEP 421 弃用实现删除

JEP 400:默认 UTF-8 字符编码

JDK 始终都是反对 UTF-8 字符编码,这次是把 UTF-8 设置为了默认编码,也就是在不加任何指定的状况下,默认所有须要用到编码的 JDK API 都应用 UTF-8 编码,这样就能够防止因为不同零碎,不同地区,不同环境之间产生的编码问题。

Mac OS 默认应用 UTF-8 作为默认编码,然而其余操作系统上,编码可能取决于零碎的配置或者所在区域的设置。如中国大陆的 windows 应用 GBK 作为默认编码。很多同学初学 Java 时可能都遇到过一个失常编写 Java 类,在 windows 零碎的命令控制台中运行却呈现乱码的状况。

应用上面的命令能够输入 JDK 的以后编码。

# Mac 零碎,默认 UTF-8
➜  ~ java -XshowSettings:properties -version 2>&1 | grep file.encoding
    file.encoding = UTF-8
    file.encoding.pkg = sun.io
➜  ~

上面编写一个简略的 Java 程序,输入默认字符编码,而后输入中文汉字”你好“,看看 Java 18 和 Java 17 运行区别。

零碎环境:Windows 11

import java.nio.charset.Charset;

public class Hello{public static void main(String[] args) {System.out.println(Charset.defaultCharset());
        System.out.println("你好");
    }
}

从上面的运行后果中能够看到,应用 JDK 17 运行输入的默认字符编码是 GBK,输入的中文”你好“曾经乱码了;乱码是因为 VsCode 默认的文本编辑器编码是 UTF-8,而中国地区的 Windows 11 默认字符编码是 GBK,也是 JDK 17 默认获取到的编码,所以会在控制台输入时乱码;而应用 JDK 18 输入的默认编码就是 UTF-8,所以能够失常的输入中文”你好“。

JEP 408:简略的 Web 服务器

在 Java 18 中,提供了一个新命令 jwebserver,运行这个命令能够启动一个 简略的、最小化的 动态 Web 服务器,它不反对 CGI 和 Servlet,所以最好的应用场景是用来测试、教育、演示等需要。

其实在如 Python、Ruby、PHP、Erlang 等许多平台都提供了开箱即用的 Web 服务器,可见一个简略的 Web 服务器是一个常见的需要,Java 始终没有这方面的反对,当初能够了。

在 Java 18 中,应用 jwebserver 启动一个 Web 服务器,默认公布的是当前目录。

在当前目录创立一个网页文件 index.html

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<h1> 题目 </h1>
</body>
</html>

启动 jwebserver.

➜  bin ./jwebserver
Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or "-b ::".
Serving /Users/darcy/develop/jdk-18.jdk/Contents/Home/bin and subdirectories on 127.0.0.1 port 8000
URL http://127.0.0.1:8000/

浏览器拜访:

有申请时会在控制台输入申请信息:

127.0.0.1 - - [26/ 3 月 /2022:16:53:30 +0800] "GET /favicon.ico HTTP/1.1" 404 -
127.0.0.1 - - [26/ 3 月 /2022:16:55:13 +0800] "GET / HTTP/1.1" 200 -

通过 help 参数能够查看 jwebserver 反对的参数。

➜  bin ./jwebserver --help
Usage: jwebserver [-b bind address] [-p port] [-d directory]
                  [-o none|info|verbose] [-h to show options]
                  [-version to show version information]
Options:
-b, --bind-address    - 绑定地址. Default: 127.0.0.1 (loopback).
                        For all interfaces use "-b 0.0.0.0" or "-b ::".
-d, --directory       - 指定目录. Default: current directory.
-o, --output          - Output format. none|info|verbose. Default: info.
-p, --port            - 绑定端口. Default: 8000.
-h, -?, --help        - Prints this help message and exits.
-version, --version   - Prints version information and exits.
To stop the server, press Ctrl + C.

JEP 413:Javadoc 中反对代码片段

在 Java 18 之前,曾经反对在 Javadoc 中引入代码片段,这样能够在某些场景下更好的展现形容信息,然而之前的反对性能无限,比方我想高亮代码片段中的某一段代码是无能为力的。当初 Java 18 优化了这个问题,减少了 @snippet 来引入更高级的代码片段。

在 Java 18 之前,应用 <pre>{@code ...}</pre> 来引入代码片段。

 /**
  * 工夫工具类
  * Java 18 之前引入代码片段:* <pre>{@code
  *     public static String timeStamp() {*        long time = System.currentTimeMillis();
  *         return String.valueOf(time / 1000);
  *     }
  * }</pre>
  *
  */

生成 Javadoc 之后,成果如下:

高亮代码片段

从 Java 18 开始,能够应用 @snippet 来生成正文,且能够高亮某个代码片段。

/**
 * 在 Java 18 之后能够应用新的形式
 * 上面的代码演示如何应用 {@code Optional.isPresent}:
 * {@snippet :
 * if (v.isPresent()) {*     System.out.println("v:" + v.get());
 * }
 * }
 *
 * 高亮显示 println
 *
 * {@snippet :
 * class HelloWorld {*     public static void main(String... args) {*         System.out.println("Hello World!");      // @highlight substring="println"
 *     }
 * }
 * }
 *
 */

成果如下,更直观,成果更好。

正则高亮代码片段

甚至能够应用正则来高亮某一段中的某些关键词:

/** 
  * 正则高亮:* {@snippet :
  *   public static void main(String... args) {*       for (var arg : args) {                 // @highlight region regex = "\barg\b"
  *           if (!arg.isBlank()) {*               System.out.println(arg);
  *           }
  *       }                                      // @end
  *   }
  *   }
  */

生成的 Javadoc 成果如下:

替换代码片段

能够应用正则表达式来替换某一段代码。

 /** 
   * 正则替换:* {@snippet :
   * class HelloWorld {*     public static void main(String... args) {*         System.out.println("Hello World!");  // @replace regex='".*"' replacement="..."
   *     }
   * }
   * }
   */

这段正文会生成如下 Javadoc 成果。

class HelloWorld {public static void main(String... args) {System.out.println(...);
    }
}

附:Javadoc 生成形式

# 应用 javadoc 命令生成 Javadoc 文档
➜  bin ./javadoc -public -sourcepath ./src -subpackages com -encoding utf-8 -charset utf-8 -d ./javadocout
# 应用 Java 18 的 jwebserver 把生成的 Javadoc 公布测试
➜  bin ./jwebserver -d /Users/darcy/develop/javadocout

拜访测试:

JEP 416:应用办法句柄从新实现反射外围性能

Java 18 改良了 java.lang.reflect.MethodConstructor 的实现逻辑,使之性能更好,速度更快。这项改变不会改变相干 API,这意味着开发中不须要改变反射相干代码,就能够体验到性能更好反射。

OpenJDK 官网给出了新老实现的反射性能基准测试后果。

Java 18 之前:

Benchmark                                     Mode  Cnt   Score  Error  Units
ReflectionSpeedBenchmark.constructorConst     avgt   10  68.049 ± 0.872  ns/op
ReflectionSpeedBenchmark.constructorPoly      avgt   10  94.132 ± 1.805  ns/op
ReflectionSpeedBenchmark.constructorVar       avgt   10  64.543 ± 0.799  ns/op
ReflectionSpeedBenchmark.instanceFieldConst   avgt   10  35.361 ± 0.492  ns/op
ReflectionSpeedBenchmark.instanceFieldPoly    avgt   10  67.089 ± 3.288  ns/op
ReflectionSpeedBenchmark.instanceFieldVar     avgt   10  35.745 ± 0.554  ns/op
ReflectionSpeedBenchmark.instanceMethodConst  avgt   10  77.925 ± 2.026  ns/op
ReflectionSpeedBenchmark.instanceMethodPoly   avgt   10  96.094 ± 2.269  ns/op
ReflectionSpeedBenchmark.instanceMethodVar    avgt   10  80.002 ± 4.267  ns/op
ReflectionSpeedBenchmark.staticFieldConst     avgt   10  33.442 ± 2.659  ns/op
ReflectionSpeedBenchmark.staticFieldPoly      avgt   10  51.918 ± 1.522  ns/op
ReflectionSpeedBenchmark.staticFieldVar       avgt   10  33.967 ± 0.451  ns/op
ReflectionSpeedBenchmark.staticMethodConst    avgt   10  75.380 ± 1.660  ns/op
ReflectionSpeedBenchmark.staticMethodPoly     avgt   10  93.553 ± 1.037  ns/op
ReflectionSpeedBenchmark.staticMethodVar      avgt   10  76.728 ± 1.614  ns/op

Java 18 的新实现:

Benchmark                                     Mode  Cnt    Score   Error  Units
ReflectionSpeedBenchmark.constructorConst     avgt   10   32.392 ± 0.473  ns/op
ReflectionSpeedBenchmark.constructorPoly      avgt   10  113.947 ± 1.205  ns/op
ReflectionSpeedBenchmark.constructorVar       avgt   10   76.885 ± 1.128  ns/op
ReflectionSpeedBenchmark.instanceFieldConst   avgt   10   18.569 ± 0.161  ns/op
ReflectionSpeedBenchmark.instanceFieldPoly    avgt   10   98.671 ± 2.015  ns/op
ReflectionSpeedBenchmark.instanceFieldVar     avgt   10   54.193 ± 3.510  ns/op
ReflectionSpeedBenchmark.instanceMethodConst  avgt   10   33.421 ± 0.406  ns/op
ReflectionSpeedBenchmark.instanceMethodPoly   avgt   10  109.129 ± 1.959  ns/op
ReflectionSpeedBenchmark.instanceMethodVar    avgt   10   90.420 ± 2.187  ns/op
ReflectionSpeedBenchmark.staticFieldConst     avgt   10   19.080 ± 0.179  ns/op
ReflectionSpeedBenchmark.staticFieldPoly      avgt   10   92.130 ± 2.729  ns/op
ReflectionSpeedBenchmark.staticFieldVar       avgt   10   53.899 ± 1.051  ns/op
ReflectionSpeedBenchmark.staticMethodConst    avgt   10   35.907 ± 0.456  ns/op
ReflectionSpeedBenchmark.staticMethodPoly     avgt   10  102.895 ± 1.604  ns/op
ReflectionSpeedBenchmark.staticMethodVar      avgt   10   82.123 ± 0.629  ns/op

能够看到在某些场景下性能略微好些。

JEP 417:Vector API(三次孵化)

在 Java 16 中引入一个新的 API 来进行向量计算,它能够在运行时牢靠的编译为反对的 CPU 架构,从而实现更优的计算能力。

在 Java 17 中改良了 Vector API 性能,加强了例如对字符的操作、字节向量与布尔数组之间的互相转换等性能。

当初在 JDK 18 中将持续优化其性能。

JEP 418:互联网地址解析 SPI

对于互联网地址解析 SPI,为主机地址和域名地址解析定义一个 SPI,以便 java.net.InetAddress 能够应用平台内置解析器以外的解析器。

InetAddress inetAddress = InetAddress.getByName("www.wdbyte.com");
System.out.println(inetAddress.getHostAddress());
// 输入
// 106.14.229.49

JEP 419:Foreign Function & Memory API (第二次孵化)

新的 API 容许 Java 开发者与 JVM 之外的代码和数据进行交互,通过调用内部函数,能够在不应用 JNI 的状况下调用本地库。

这是一个孵化性能;须要增加 --add-modules jdk.incubator.foreign 来编译和运行 Java 代码,Java 18 改良了相干 API,使之更加简略易用。

历史

  • Java 14 JEP 370 (opens new window)引入了内部内存拜访 API(孵化器)。
  • Java 15 JEP 383 (opens new window)引入了内部内存拜访 API(第二孵化器)。
  • Java 16 JEP 389 (opens new window)引入了内部链接器 API(孵化器)。
  • Java 16 JEP 393 (opens new window)引入了内部内存拜访 API(第三孵化器)。
  • Java 17 JEP 412 (opens new window)引入了内部函数和内存 API(孵化器)。

JEP 420:switch 表达式(二次孵化)

从 Java 17 开始,对于 Switch 的改良就曾经在进行了,Java 17 的 JEP 406 曾经对 Switch 表达式进行了加强,使之能够缩小代码量。

上面是几个例子:

// JDK 17 以前
static String formatter(Object o) {
    String formatted = "unknown";
    if (o instanceof Integer i) {formatted = String.format("int %d", i);
    } else if (o instanceof Long l) {formatted = String.format("long %d", l);
    } else if (o instanceof Double d) {formatted = String.format("double %f", d);
    } else if (o instanceof String s) {formatted = String.format("String %s", s);
    }
    return formatted;
}

而在 Java 17 之后,能够通过上面的写法进行改良:

// JDK 17 之后
static String formatterPatternSwitch(Object o) {return switch (o) {case Integer i -> String.format("int %d", i);
        case Long l    -> String.format("long %d", l);
        case Double d  -> String.format("double %f", d);
        case String s  -> String.format("String %s", s);
        default        -> o.toString();};
}

switch 能够和 null 进行联合判断:

static void testFooBar(String s) {switch (s) {case null         -> System.out.println("Oops");
        case "Foo", "Bar" -> System.out.println("Great");
        default           -> System.out.println("Ok");
    }
}

case 时能够退出简单表达式:

static void testTriangle(Shape s) {switch (s) {case Triangle t && (t.calculateArea() > 100) ->
            System.out.println("Large triangle");
        default ->
            System.out.println("A shape, possibly a small triangle");
    }
}

case 时能够进行类型判断:

sealed interface S permits A, B, C {}
final class A implements S {}
final class B implements S {}
record C(int i) implements S {}  // Implicitly final

static int testSealedExhaustive(S s) {return switch (s) {
        case A a -> 1;
        case B b -> 2;
        case C c -> 3;
    };
}

扩大:JEP 406:Switch 的类型匹配(预览)

JEP 421:弃用删除相干

在将来将删除 Finalization,目前 Finalization 仍默认放弃启用状态,然而曾经能够手动禁用;在将来的版本中,将会默认禁用;在当前的版本中,它将被删除。须要进行资源管理能够尝试 try-with-resources 或者 java.lang.ref.Cleaner

参考

  • JDK 18 Features(https://openjdk.java.net/projects/jdk/18/)

订阅

能够微信搜一搜程序猿阿朗或拜访未读代码博客浏览。
本文 Github.com/niumoo/JavaNotes 曾经收录,欢送 Star。

退出移动版