乐趣区

关于java:Java9新特性及代码示例

你好啊,我是大阳,明天给大家介绍一下 Java9 的新个性,并提供一些代码示例。

Java 9 带来了许多新的加强性能,这些加强性能将在很大水平上影响你的编程格调和习惯。最大的变动是 Java 的模块化。这是继 Java 8 中的 Lambdas 之后的另一个重大变动。在本文中,我将列出 Java 9 版本的一部分更新内容。

本文次要内容:

  • Java 模块化
  • 接口公有办法
  • HTTP/ 2 客户端
  • JShell – REPL 工具
  • 平台和 JVM 日志记录
  • Process API 更新
  • Collection(汇合)API 更新
  • Stream(流)API 改良
  • 多版本 Jar 文件
  • @Deprecated 注解更改
  • Java 文档更新
  • 其余性能

1. Java 模块化

JPMS(Java Platform Module System)是 Java 9 发行版的外围亮点。它也被称为 Jigshaw 我的项目。模块是新的构造,就像咱们曾经有包一样。应用新的模块化编程开发的应用程序能够看作是交互模块的汇合,这些模块之间具备明确定义的边界和依赖关系。

JPMS 包含为编写模块化应用程序提供反对,以及将 JDK 源代码模块化。JDK 9 附带了大概 92 个模块(在 GA 版本中能够进行更改)。Java 9 Module System 有一个 “java.base” 模块。它被称为根本模块。它是一个独立的模块,不依赖于任何其余模块。默认状况下,所有其余模块都依赖于 ”java.base”。

在 java 模块化编程中:

  • 一个模块通常只是一个 jar 文件,在根目录下有一个文件module-info.class
  • 要应用模块,请将 jar 文件蕴含到 modulepath 而不是 classpath. 增加到类门路的模块化 jar 文件是一般的 jar 文件,module-info.class 文件将被疏忽。

典型的 module-info.java 类如下所示:

module helloworld {exports cn.dayangshuo.demo;}
 
module test {requires helloworld;}

2. 接口公有办法

Java 8 容许在接口中编写默认办法,这是一个广受欢迎的性能。从 Java 9 开始,您能够在接口中蕴含公有办法。

这些公有办法将进步接口外部的代码可重用性。例如,如果两个默认办法须要共享代码,公有接口办法将容许它们这样做,但不会将该公有办法裸露给它的实现类。

在接口中应用公有办法有四个规定:

  • 公有接口办法不能是形象的。
  • 公有办法只能在接口外部应用。
  • 公有静态方法能够在其余动态和非动态接口办法中应用。
  • 公有非静态方法不能在公有静态方法中应用。

示例:

public interface CustomCalculator {default int addEvenNumbers(int... nums) {return add(n -> n % 2 == 0, nums);
    }
  
    default int addOddNumbers(int... nums) {return add(n -> n % 2 != 0, nums);
    }
  
    private int add(IntPredicate predicate, int... nums) {return IntStream.of(nums)
                .filter(predicate)
                .sum();}
}

3. HTTP/ 2 客户端

HTTP/1.1 客户端于 1997 年公布。尔后产生了很多变动。因而,Java 9 引入了新的 API,它应用起来更洁净、更清晰,并且还减少了对 HTTP/2 的反对。新 API 应用 3 个次要类 HttpClientHttpRequestHttpResponse.

要发出请求,就像获取客户端、构建申请并发送它一样简略,示例:

HttpClient httpClient = HttpClient.newHttpClient(); 
HttpRequest httpRequest = HttpRequest.newBuilder().uri(new URI("https://baidu.com/")).GET().build(); 
HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandler.asString()); 
System.out.println(httpResponse.body()); 

下面的代码看起来更清晰易读。

httpClient.sendAsync()API 还反对应用办法的异步 HTTP 申请。它返回 CompletableFuture 可用于确定申请是否已实现。它还能够在 HttpResponse 申请实现后拜访。如果你违心,甚至能够在申请实现之前勾销它。

示例:

if(httpResponse.isDone()) {System.out.println(httpResponse.get().statusCode());
    System.out.println(httpResponse.get().body());
} else {httpResponse.cancel(true);
}

4. JShell – REPL 工具

JShell 是 JDK 9 发行版 [JEP 222]附带的新命令行交互式工具,用于评估用 Java 编写的申明、语句和表达式。JShell 容许咱们执行 Java 代码片段并立刻取得后果,而无需创立解决我的项目。

Jshell 很像咱们在 linux 操作系统中的命令窗口。不同之处在于 JShell 是特定于 Java 的。除了执行简略的代码片段之外,它还有许多其余性能,例如:

  • 在独自的窗口中启动内置代码编辑器
  • 在独自的窗口中启动你抉择的代码编辑器
  • 在这些内部编辑器中产生保留操作时执行代码
  • 从文件系统加载事后编写的类

5. 平台和 JVM 日志记录

JDK 9 通过新的日志记录 API 改良了平台类(JDK 类)和 JVM 组件中的日志记录。它容许开发者指定本人抉择的日志记录框架(例如 Log4J2)作为日志记录工具,用于记录来自 JDK 类的音讯。

对于这个 API,你应该晓得几件事:

  • API 旨在供 JDK 中的类应用,而不是由应用程序类应用。
  • 对于利用程序代码,开发者将像以前一样持续应用其余日志记录 API。
  • API 不容许开发者以编程形式配置记录器。

API 由以下局部组成:

  • 服务接口,java.lang.System.LoggerFinder是一个形象动态类
  • java.lang.System.Logger提供日志记录 API 的接口
  • getLogger()类中的一个重载办法java.lang.System,它返回一个记录器实例。

JDK 9 还增加了一个新的命令行选项,-Xlog它使开发者能够单点拜访从 JVM 的所有类记录的所有音讯。以下是应用该 -Xlog 选项的语法:

-Xlog[:][:[][:[][:]]]

所有选项都是可选的。如果短少后面的局部,-Xlog则必须为该局部应用冒号。例如,-Xlog::stderr示意所有局部都是默认的,输入设置为stderr.

6. Process API 更新

在 Java 5 之前,生成新过程的惟一办法是应用该 Runtime.getRuntime().exec() 办法。而后在 Java 5 中,ProcessBuilder引入了 API,它反对一种更简洁的形式来生成新过程。当初,Java 9 增加了一种获取无关以后过程和任何衍生过程的信息的新办法。

要获取任何过程的信息,当初您应该应用 java.lang.ProcessHandle.Info 接口。此界面可用于获取大量信息,例如:

  • 用于启动过程的命令
  • 命令的参数
  • 过程开始的时刻
  • 它和创立它的用户破费的总工夫
ProcessHandle processHandle = ProcessHandle.current();
ProcessHandle.Info processInfo = processHandle.info();
 
System.out.println(processHandle.getPid());
System.out.println(processInfo.arguments().isPresent());
System.out.println(pprocessInfo.command().isPresent());
System.out.println(processInfo.command().get().contains("java"));
System.out.println(processInfo.startInstant().isPresent());

要获取新衍生过程的信息,请应用 process.toHandle() 办法获取 ProcessHandle 实例。其余所有如上。

String javaPrompt = ProcessUtils.getJavaCmd().getAbsolutePath();
ProcessBuilder processBuilder = new ProcessBuilder(javaPrompt, "-version");
Process process = processBuilder.inheritIO().start();
ProcessHandle processHandle = process.toHandle();

也用于 ProcessHandle.allProcesses() 获取零碎中所有可用过程的 ProcessHandle 流。

要获取所有子过程的列表(间接以及 n 级深度),请应用 children()descendants()办法。

Stream<ProcessHandle> children    = ProcessHandle.current().children();
Stream<ProcessHandle> descendants = ProcessHandle.current().descendants();

6. Collection(汇合)API 更新

从 Java 9 开始,您能够应用新的工厂办法创立不可变汇合,例如不可变 list、不可变 set 和不可变 map。例如:

import java.util.List;
  
public class ImmutableCollections {public static void main(String[] args) {List<String> namesList = List.of("Lokesh", "Amit", "John");
 
        Set<String> namesSet = Set.of("Lokesh", "Amit", "John");
 
        Map<String, String> namesMap = Map.ofEntries(Map.entry("1", "Lokesh"),
                          Map.entry("2", "Amit"),
                          Map.entry("3", "Brian"));
    }
}

7. Stream(流)API 改良

Java 9 引入了两种与 Streams 交互的新办法,即 takeWhile/dropWhile 办法。此外,它还增加了两个重载办法,即 ofNullableiterate办法。

新办法 takeWhiledropWhile 容许开发者基于谓词获取流的一部分

  • 在有序流上,takeWhile返回从流中获取的与给定谓词匹配的元素的“最长前缀”,从流的结尾开始。dropWhile返回与 不匹配的残余我的项目takeWhile
  • 在无序流上,takeWhile返回与给定谓词(但不是全副)匹配的流元素的子集,从流的结尾开始。dropWhile在删除与给定谓词匹配的元素子集后返回残余的流元素。
List<String> alphabets = List.of("a", "b", "c", "d", "e", "f", "g", "h", "i");
List<String> subset1 = alphabets
        .stream()
        .takeWhile(s -> !s.equals("d"))
        .collect(Collectors.toList());
// 打印出:[a, b, c] 
System.out.println(subset1);

List<String> alphabets = List.of("a", "b", "c", "d", "e", "f", "g", "h", "i");
List<String> subset2 = alphabets
        .stream()
        .dropWhile(s -> !s.equals("d"))
        .collect(Collectors.toList());
 // 打印出:[d, e, f, g, h, i]
System.out.println(subset2);

同样,在 Java 8 之前,流中不能有 null 值。它会导致 NullPointerException. 从 Java 9 开始,Stream.ofNullable() 办法容许您创立一个单元素流,该流包装一个不为 null 的值,否则为空流。从技术上讲,Stream.ofNullable()在流 API 的上下文中,与空条件查看十分类似。

8. 多版本 Jar 文件

此加强与如何将应用程序类打包到 jar 文件中无关。以前,开发者必须将所有类打包到一个 jar 文件中,而后放入心愿应用它的另一个应用程序的类门路中。

应用多版本个性,当初一个 jar 能够蕴含一个类的不同版本——兼容不同的 JDK 版本。对于一个类的不同版本,以及加载的类应该抉择哪个类的 JDK 版本的信息存储在 MANIFEST.MF 文件中。在这种状况下,文件在其次要局部中 MANIFEST.MF 蕴含该条目Multi-Release: true

此外,META-INF 蕴含一个版本子目录,其以整数命名的子目录——从 9 开始(对于 Java 9)——存储特定于版本的类和资源文件。例如

JAR content root
  A.class
  B.class
  C.class
  D.class
  META-INF
     MANIFEST.MF
     versions
        9
           A.class
           B.class

假如在 JDK 10 A.class 中更新为利用一些 Java 10 新个性,那么这个 Jar 文件能够像这样更新:

JAR content root
  A.class
  B.class
  C.class
  D.class
  META-INF
     MANIFEST.MF
     versions
        9
           A.class
           B.class
        10
           A.class

它看起来十分有心愿解决在大型应用程序中常常看到的依赖天堂,其中不同版本的 jar 彼此不兼容。此性能能够为解决这些状况提供很大帮忙。

9. @Deprecated 注解更改

从 Java 9 开始,@Deprecated 注解将具备两个属性,即 forRemovalsince.

  • forRemoval – 批示带正文的元素是否会在将来版本中被删除。
  • since – 它返回正文元素被弃用的版本。

强烈建议应用 @deprecated javadoc 标记在文档中解释弃用程序元素的起因。如果实用,文档还应倡议并链接到举荐的代替 API。替换 API 通常具备奥妙不同的语义,因而也应探讨此类问题。

10. Java 文档更新

Java 9 加强了 javadoc 生成 HTML5 标记的工具。它目前以 HTML 4.01 生成页面。

为了生成 HTML5 Javadoc,参数 -html5 须要放在命令行参数中。要在命令行上生成文档,你将运行:

javadoc [选项] [包名] [源文件] [@files]

应用 HTML5 能够带来更简略的 HTML5 构造的益处。它还实现了可拜访性的 WAI-ARIA 规范。这旨在使身材或视觉阻碍的人更容易应用屏幕阅读器等工具拜访 javadocs 页面。

JEP 225 提供了在 javadoc 中搜寻程序元素和标记的单词和短语的能力。

以下内容将被索引和搜寻:

  • 模块的申明名称
  • 套餐
  • 类型和成员
  • 办法参数类型的简略名称

这是在客户端实现的,带有一个新的search.jsJavascript 文件,以及生成 javadoc 时生成的索引。生成的 HTML5 API 页面上有一个搜寻框。

请留神,默认状况下会增加搜寻选项,但能够应用参数敞开:-noindex

11. 其余性能

Java 9 中还有其余性能,我在此处列出以供疾速参考。咱们将在接下来的帖子中探讨所有这些性能。

  • 反应式流 API
  • GC(垃圾收集器)改良
  • 过滤传入的序列化数据
  • 弃用 Applet API
  • 批示字符串连贯
  • 加强的办法句柄
  • 紧凑的字符串
  • Nashorn 解析器 API
退出移动版