Java 9功能和增强功能

Java 9带来了许多新的增强功能,它们将在很大程度上影响您的编程风格和习惯。最大的变化是Java的模块化。这之后的又一大变化lambda表达式的Java 8。在本文中,我列出了将作为JDK 9版本的一部分的更改。

Java 9的新增功能

Java平台模块系统
接口私有方法
HTTP 2客户端
JShell-REPL工具
平台和JVM记录
过程API更新
集合API更新
 Stream API改进
多发行版JAR文件
@弃用的标记更改
堆栈
遍历Java文档更新
其他

Java平台模块系统

JPMS(Java平台模块系统)是新Java 9版本的核心亮点。它也被称为Project Jigshaw。模块是新的结构,就像我们已经有了软件包一样。使用新的模块化编程开发的应用程序可以看作是交互模块的集合,这些模块之间具有明确定义的边界和依赖性。

JPMS包括为编写模块化应用程序以及模块化JDK源代码提供支持。JDK 9随附约92个模块(GA版本中可能会进行更改)。Java 9模块系统具有一个“ java.base”模块。它被称为基本模块。它是一个独立模块,不依赖于任何其他模块。默认情况下,所有其他模块都依赖于“ java.base”。

在Java模块化编程中-

  1. 模块通常只是一个jar文件,该module-info.class文件的根目录。
  2. 要使用模块,请将jar文件(modulepath而不是)包含在内classpath。添加到类路径的模块化jar文件是普通的jar文件,该module-info.class文件将被忽略。

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

module helloworld {
    exports com.how2codex.demo;
}
 
module test {
    requires helloworld;
}

阅读更多:Java 9模块教程

接口私有方法

Java 8允许您在接口中编写默认方法,这是广受赞赏的功能。因此,在此之后,接口仅缺少一些东西,只有非私有方法是其中之一。从Java 9开始,您可以在接口中包含私有方法。

这些私有方法将改善接口内部的代码可重用性。举个例子,如果需要两个默认方法共享代码,则可以使用私有接口方法来共享代码,但是不必将该私有方法暴露给实现类。

在接口中使用私有方法有四个规则:

  1. 专用接口方法不能是抽象的。
  2. 私有方法只能在接口内部使用。
  3. 私有静态方法可以在其他静态和非静态接口方法中使用。
  4. 私有非静态方法不能在私有静态方法内部使用。

在接口中使用私有方法的示例–

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();
    }
}

Java 9 –接口中的私有方法

HTTP / 2客户端

HTTP / 1.1客户端于1997年发布。此后发生了很多变化。因此,对于Java 9,引入了新的API,该API使用起来更加简洁明了,并且还增加了对HTTP / 2的支持。新的API使用3个主要类别,即HttpClientHttpRequestHttpResponse

要发出请求,就像获取客户,建立请求并发送它一样简单,如下所示。

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

上面的代码看起来更简洁易读。

新的API还支持使用httpClient.sendAsync()方法的异步HTTP请求。它返回CompletableFuture可用于确定请求是否已完成的对象。HttpResponse一旦请求完成,它还为您提供访问权限。最好的部分是,如果您愿意,甚至可以在请求完成之前取消它。例如

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

JShell – REPL工具

JShellJDK 9发行版[ JEP 222 ] 附带的新命令行交互工具,用于评估用Java编写的声明,语句和表达式。JShell允许我们执行Java代码段并获得即时结果,而无需创建解决方案或项目。

Jshell非常类似于linux OS中的命令窗口。区别在于JShell是Java特定的。除了执行简单的代码片段外,它还有许多其他功能。例如

  • 在单独的窗口中启动内置代码编辑器
  • 在单独的窗口中启动您选择的代码编辑器
  • 在这些外部编辑器中发生“保存”操作时执行代码
  • 从文件系统加载预编写的类

Java 9 JShell教程

平台和JVM日志记录

JDK 9通过新的日志记录API改进了平台类(JDK类)和JVM组件中的日志记录。它使您可以将所选日志记录框架(例如Log4J2)指定为日志记录后端,用于记录来自JDK类的消息。关于此API,您应该了解几件事:

  1. 该API是由JDK中的类而非应用程序类使用的。
  2. 对于您的应用程序代码,您将像以前一样继续使用其他日志记录API。
  3. 该API不允许您以编程方式配置记录器。

该API包含以下内容:

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

JDK 9还添加了一个新的命令行选项,-Xlog使您可以单点访问从JVM所有类记录的所有消息。以下是使用该-Xlog选项的语法:

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

所有选项都是可选的。如果-Xlog缺少前面的部分,则必须在该部分使用冒号。例如,-Xlog::stderr指示所有部件均为默认部件,将输出wich设置为stderr

我将在单独的文章中深入讨论该主题。

处理API更新

在Java 5之前,产生新进程的唯一方法是使用该Runtime.getRuntime().exec()方法。然后在Java 5中,ProcessBuilder引入了API,该API支持更干净的方式产生新进程。现在,Java 9添加了一种获取有关当前进程和任何衍生进程的信息的新方法。

要获取任何进程的信息,现在应该使用java.lang.ProcessHandle.Infointerface。该界面在获取大量信息方面很有用,例如

  • 用于启动过程的命令
  • 命令的参数
  • 进程开始的瞬间
  • 它和创建它的用户所花费的总时间
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 Stream 。

要获取所有子进程(直接和n级深度)的列表,请使用children()descendants()方法。

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

集合API更新

从Java 9开始,您可以使用新的工厂方法创建不可变集合,例如不可变列表,不可变集合和不可变映射。例如

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"));
    }
}

Java 9 Collections API的改进

Stream API的改进

Java 9引入了两种与Streams交互的新方法,即takeWhiledropWhile方法。此外,它还添加了两个重载方法,即ofNullableiterate方法。

这些新方法takeWhile,并dropWhile让你获得基于 Predicate Stream 的部分。

  1. 在有序 Stream 上,takeWhile从 Stream 的开头开始,返回与给定 Predicate 匹配的,从 Stream 中获取的元素的“最长前缀”。dropWhile返回与不匹配的其余项takeWhile
  2. 在无序 Stream 上,takeWhile从 Stream 的开头开始,返回与给定 Predicate (但不是全部)匹配的 Stream 元素的子集。dropWhile在删除与给定 Predicate 匹配的元素子集之后,返回剩余的 Stream 元素。

同样,在Java 8之前,您无法null在 Stream 中获得价值。那会造成的NullPointerException。从Java 9开始,Stream.ofNullable()方法允许您创建一个单元素 Stream ,如果不是null,则包装一个值,否则为空 Stream 。从技术上讲,Stream.ofNullable()在 Stream API上下文中进行交谈时,它与空条件检查非常相似。

Java 9 Stream API的改进

多版本JAR文件

此增强与将应用程序类打包到jar文件中的方式有​​关。以前,您必须将所有类打包到一个jar文件中,并放到另一个要使用它的应用程序的类路径中。

现在,通过使用多发行版功能,一个jar可以包含一个类的不同版本–与不同的JDK版本兼容。有关类的不同版本的信息以及通过加载的类应采用哪个JDK版本的类的信息存储在MANIFEST.MF文件中。在这种情况下,MANIFEST.MF文件的Multi-Release: true主要部分包括该条目。

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

JAR内容根
  一类
  B级
  C类
  D类
  META-INF
     清单文件
     版本
        9
           一类
           B级

假设在JDK 10中A.class进行了更新以利用某些Java 10功能,那么可以像下面这样更新此Jar文件:

JAR内容根
  一类
  B级
  C类
  D类
  META-INF
     清单文件
     版本
        9
           一类
           B级
        10
           一类

解决具有多种版本的jar彼此不兼容的大型应用程序中经常出现的依赖地狱,这看起来确实是很有前途的一步。此功能可能对解决这些情况有很大帮助。

@不推荐使用的标签更改

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

  1. forRemoval –指示注解的元素是否在将来的版本中会被删除。
  2.  –开始,它不赞成使用带注解的元素的版本。

强烈建议在文档中使用@deprecated javadoc标记说明不赞成使用程序元素的原因。该文档还应该建议并链接到建议的替代API(如果适用)。替换API的语义通常会有所不同,因此也应讨论此类问题。

栈走

堆栈是后进先出(LIFO)数据结构。在JVM级别,堆栈存储帧。每次调用方法时,都会创建一个新框架并将其推入堆栈的顶部。方法调用完成后,框架将被破坏(从堆栈中弹出)。堆栈上的每个帧都包含其自己的局部变量数组,以及其自己的操作数堆栈,返回值和对当前方法类的运行时常量池的引用。

在给定线程中,任何时候只有一帧处于活动状态。活动帧称为当前帧,其方法称为当前方法。[ 阅读更多 ]

直到Java 8 StackTraceElement代表一个堆栈框架。要获得完整的堆栈,您必须使用Thread.getStackTrace()Throwable.getStackTrace()。它返回一个数组StackTraceElement,您可以迭代该数组以获取所需的信息。

在Java 9中,StackWalker引入了一个新类。该类使用当前线程的堆栈帧顺序 Stream 提供简单有效的堆栈遍历。该StackWalker班是非常有效的,因为它懒洋洋地评估堆栈帧。

// Prints the details of all stack frames of the current thread
StackWalker.getInstance().forEach(System.out::println);

您可以使用此信息 Stream 执行其他许多操作,我们将在其他一些专用文章中介绍这些内容。

Java文档更新

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

为了生成HTML5 Javadoc,该参数-html5需要放在命令行参数中。要在命令行上生成文档,可以运行:

javadoc [选项] [程序包名称] [源文件] [@文件]

使用HTML5可以带来更轻松的HTML5结构的好处。它还实现了WAI-ARIA标准的可访问性。这样做的目的是使身体或视觉障碍的人更容易使用屏幕阅读器等工具访问javadocs页面。

JEP 225使您能够在Javadoc中搜索程序元素以及标记的单词和短语。

以下内容将被索引并可以搜索:

  • 声明的模块名称
  • 配套
  • 类型和成员
  • 方法参数类型的简单名称

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

请注意,默认情况下会添加“搜索”选项,但可以使用参数来将其关闭-noindex

其他功能

Java 9中还有其他功能,我在这里列出以供快速参考。我们将在以后的文章中讨论所有这些功能。

  • 反应式 Stream API
  • GC(垃圾收集器)改进
  • 筛选传入的序列化数据
  • 弃用Applet API
  • 字符串化连接
  • 增强的方法句柄
  • 紧凑弦
  • Nashorn的解析器API
Java 9计划于2017年9月21日发布。有关最新更改,请点击此链接

saigon has written 1440 articles

One thought on “Java 9功能和增强功能

Leave a Reply