Java 9带来了许多新的增强功能,它们将在很大程度上影响编程风格和习惯。最大的变化是Java的模块化,这是继Java8 lambda表达式之后的又一重大变化。在本文中,我列出了JDK 9的部分变化。
目录
1.模块系统(Java platform module system)
JPMS(Java平台模块系统)是新Java 9的核心亮点。它也被称为Project Jigshaw。模块是新的结构,就像我们已经有了软件包一样。使用新的模块化编程开发的应用程序可以看作是交互模块的集合,这些模块之间具有明确定义的边界和依赖性。
JPMS包括提供对编写模块化应用程序以及对JDK源代码进行模块化的支持。JDK 9随附约92个模块(GA版本中可能会进行更改)。Java 9模块系统具有一个“ java.base”模块。它被称为基本模块。它是一个独立模块,不依赖于任何其他模块。默认情况下,所有其他模块都依赖于“ java.base”。
在Java模块化编程中:
- 模块通常只是一个jar文件,module-info.class其根目录中有一个文件。
- 要使用模块,请将jar文件(modulepath而不是)包含到其中classpath。添加到类路径的模块化jar文件是普通的jar文件,该module-info.class文件将被忽略。
典型的module-info.java类如下所示:
module helloworld {
exports com.howtodoinjava.demo;
}
module test {
requires helloworld;
}
2.接口私有方法(Interface Private Methods)
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客户端
HTTP1.1客户端于1997年发布。此后发生了很多变化。对于Java 9,引入了新的API,该API使用起来更加简洁明了,并且还增加了对HTTP 2的支持。新的API使用3个主要类,即HttpClient,HttpRequest和HttpResponse。
要发出请求,就像获取客户建立请求并发送它一样简单,如下所示:
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest httpRequest = HttpRequest.newBuilder().uri(new URI("//howtodoinjava.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);
}
4.JShell – REPL工具
JShell是JDK 9发行版[ JEP 222 ]附带的新命令行交互工具,用于评估用Java编写的声明,语句和表达式。JShell允许我们执行Java代码段并获得即时结果,而无需创建解决方案或项目。Jshell非常类似于linux OS中的命令窗口。区别在于JShell是Java特定的。除了执行简单的代码片段外,它还具有许多其他功能。例如:
- 在单独的窗口中启动内置代码编辑器
- 在单独的窗口中启动您选择的代码编辑器
- 在这些外部编辑器中发生“保存”操作时执行代码
- 从文件系统加载预编写的类
5.平台和JVM日志记录(Platform and JVM Logging)
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表示所有零件均为默认零件,输出wich设置为stderr。我将在单独的文章中深入讨论该主题。
6.进程API更新(Process API Updates)
在Java 5之前,产生新进程的唯一方法是使用该Runtime.getRuntime().exec()方法。然后在Java 5ProcessBuilder中引入了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流。
要获取所有子进程(直接和n级深度)的列表,请使用children()和descendants()方法。
Stream<ProcessHandle> children = ProcessHandle.current().children();
Stream<ProcessHandle> descendants = ProcessHandle.current().descendants();
7.集合API更新(Collection API Updates)
从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"));
}
}
8.流API的改进(Stream API Improvements)
Java 9引入了两种与Streams交互的新方法,即takeWhile/dropWhile方法。此外,它还添加了两个重载方法,即ofNullable和iterate方法。
这些新方法takeWhile,并dropWhile让你获得基于谓词流的部分。
- 在有序流上,takeWhile从流的开头开始,返回与给定谓词匹配的,从流中获取的元素的“最长前缀”。dropWhile返回与不匹配的其余项takeWhile。
- 在无序流上,takeWhile从流的开头开始,返回与给定谓词(但不是全部)匹配的流元素的子集。dropWhile在删除与给定谓词匹配的元素子集之后,返回剩余的流元素。
同样,在Java 8之前,您无法null在流中获得价值。那会造成的NullPointerException。从Java 9开始,Stream.ofNullable()方法允许您创建一个单元素流,如果不是null,则包装一个值,否则为空流。从技术上讲,Stream.ofNullable()在流API上下文中进行交谈时,它与空条件检查非常相似。
9.多版本兼容JAR包(Multi-Release JAR Files)
多版本兼容 JAR 功能能让你创建仅在特定版本的 Java 环境中运行库程序时选择使用的 class 版本
10.Javadoc的改进
javadoc 工具可以生成 Java 文档, Java 9 的 javadoc 的输出现在符合兼容 HTML5 标准。
11.Optional 类的改进
Optional 类在 Java 8 中引入,Optional 类的引入很好的解决空指针异常。。在 java 9 中, 添加了三个方法来改进它的功能:
- stream()
- ifPresentOrElse()
- or()
stream() 方法
语法
public Stream<T> stream()
stream 方法的作用就是将 Optional 转为一个 Stream,如果该 Optional 中包含值,那么就返回包含这个值的 Stream,否则返回一个空的 Stream(Stream.empty())。
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Tester {
public static void main(String[] args) {
List<Optional<String>> list = Arrays.asList (
Optional.empty(),
Optional.of("A"),
Optional.empty(),
Optional.of("B"));
//filter the list based to print non-empty values
//if optional is non-empty, get the value in stream, otherwise return empty
List<String> filteredList = list.stream()
.flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
.collect(Collectors.toList());
//Optional::stream method will return a stream of either one
//or zero element if data is present or not.
List<String> filteredListJava9 = list.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());
System.out.println(filteredList);
System.out.println(filteredListJava9);
}
}
执行输出结果为:
[A, B]
[A, B]
ifPresentOrElse() 方法
语法
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
ifPresentOrElse 方法的改进就是有了 else,接受两个参数 Consumer 和 Runnable。
ifPresentOrElse 方法的用途是,如果一个 Optional 包含值,则对其包含的值调用函数 action,即action.accept(value),这与 ifPresent 一致;与 ifPresent 方法的区别在于,ifPresentOrElse 还有第二个参数 emptyAction —— 如果 Optional 不包含值,那么 ifPresentOrElse 便会调用 emptyAction,即 emptyAction.run()。
import java.util.Optional;
public class Tester {
public static void main(String[] args) {
Optional<Integer> optional = Optional.of(1);
optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() ->
System.out.println("Not Present."));
optional = Optional.empty();
optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() ->
System.out.println("Not Present."));
}
}
执行输出结果为:
Value: 1
Not Present.
or() 方法
语法
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
如果值存在,返回 Optional 指定的值,否则返回一个预设的值。
import java.util.Optional;
import java.util.function.Supplier;
public class Tester {
public static void main(String[] args) {
Optional<String> optional1 = Optional.of("Mahesh");
Supplier<Optional<String>> supplierString = () -> Optional.of("Not Present");
optional1 = optional1.or( supplierString);
optional1.ifPresent( x -> System.out.println("Value: " + x));
optional1 = Optional.empty();
optional1 = optional1.or( supplierString);
optional1.ifPresent( x -> System.out.println("Value: " + x));
}
}
执行输出结果为:
Value: Mahesh
Value: Not Present
12.其他功能
Java 9中还有其他功能,我在这里列出以供快速参考。我们将在以后的文章中讨论所有这些功能。
- Reactive Streams API
- GC (Garbage Collector) Improvements
- Filter Incoming Serialization Data
- Deprecate the Applet API
- Indify String Concatenation
- Enhanced Method Handles
- Compact Strings
- Parser API for Nashorn
本文来自转载,原文链接: