Java 9 新个性
- 模块零碎 :模块是一个包的容器,Java 9 最大的变动之一是引入了模块零碎(Jigsaw 我的项目)。
- REPL (JShell):交互式编程环境。
- HTTP 2 客户端 :HTTP/ 2 规范是 HTTP 协定的最新版本,新的 HTTPClient API 反对 WebSocket 和 HTTP2 流以及服务器推送个性。
- 改良的 Javadoc:Javadoc 当初反对在 API 文档中的进行搜寻。另外,Javadoc 的输入当初合乎兼容 HTML5 规范。
- 多版本兼容 JAR 包 :多版本兼容 JAR 性能能让你创立仅在特定版本的 Java 环境中运行库程序时抉择应用的 class 版本。
- 汇合工厂办法 :List,Set 和 Map 接口中,新的动态工厂办法能够创立这些汇合的不可变实例。
- 公有接口办法 :在接口中应用 private 公有办法。咱们能够应用 private 拜访修饰符在接口中编写公有办法。
- 过程 API: 改良的 API 来管制和治理操作系统过程。引进 java.lang.ProcessHandle 及其嵌套接口 Info 来让开发者逃离时常因为要获取一个本地过程的 PID 而不得不应用本地代码的困境。
- 改良的 Stream API:改良的 Stream API 增加了一些便当的办法,使流解决更容易,并应用收集器编写简单的查问。
- 改良 try-with-resources:如果你曾经有一个资源是 final 或等效于 final 变量, 您能够在 try-with-resources 语句中应用该变量,而无需在 try-with-resources 语句中申明一个新变量。
- 改良的弃用注解 @Deprecated:注解 @Deprecated 能够标记 Java API 状态,能够示意被标记的 API 将会被移除,或者曾经毁坏。
- 改良钻石操作符 (Diamond Operator):匿名类能够应用钻石操作符 (Diamond Operator)。
- 改良 Optional 类 :java.util.Optional 增加了很多新的有用办法,Optional 能够间接转为 stream。
- 多分辨率图像 API:定义多分辨率图像 API,开发者能够很容易的操作和展现不同分辨率的图像了。
- 改良的 CompletableFuture API:CompletableFuture 类的异步机制能够在 ProcessHandle.onExit 办法退出时执行操作。
- 轻量级的 JSON API:内置了一个轻量级的 JSON API
- 响应式流(Reactive Streams) API: Java 9 中引入了新的响应式流 API 来反对 Java 9 中的响应式编程。
更多的新个性能够参阅官网:What’s New in JDK 9
JDK 9 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk9-doc-downloads-3850606.html
在对于 Java 9 文章的实例,咱们均应用 jdk 1.9 环境,你能够应用以下命令查看以后 jdk 的版本:
$ java -version
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+163)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+163, mixed mode)
1\. Java 平台级模块零碎
Java 9 的定义性能是一套全新的模块零碎。当代码库越来越大,创立简单,盘根错节的“意大利面条式代码”的几率呈指数级的增长。这时候就得面对两个根底的问题: 很难真正地对代码进行封装, 而零碎并没有对不同局部(也就是 JAR 文件)之间的依赖关系有个明确的概念。每一个公共类都能够被类门路之下任何其它的公共类所拜访到, 这样就会导致无心中应用了并不想被公开拜访的 API。此外,类门路自身也存在问题: 你怎么通晓所有须要的 JAR 都曾经有了, 或者是不是会有反复的项呢? 模块零碎把这俩个问题都给解决了。
模块化的 JAR 文件都蕴含一个额定的模块形容器。在这个模块形容器中, 对其它模块的依赖是通过“requires”来示意的。另外,“exports”语句管制着哪些包是能够被其它模块拜访到的。所有不被导出的包默认都封装在模块的外面。如下是一个模块形容器的示例,存在于“module-info.java”文件中:
module blog {
exports com.pluralsight.blog;
requires cms;
}
请留神,两个模块都蕴含封装的包,因为它们没有被导出(应用橙色盾牌可视化)。没有人会偶尔地应用来自这些包中的类。Java 平台自身也应用本人的模块零碎进行了模块化。通过封装 JDK 的外部类,平台更平安,继续改良也更容易。
当启动一个模块化利用时,JVM 会验证是否所有的模块都能应用,这基于 requires
语句——比软弱的类门路迈进了一大步。模块容许你更好地强制结构化封装你的利用并明确依赖。你能够在这个课程中学习更多对于 Java 9 中模块工作的信息。
2\. Linking
当你应用具备显式依赖关系的模块和模块化的 JDK 时,新的可能性呈现了。你的利用程序模块当初将申明其对其余利用程序模块的依赖以及对其所应用的 JDK 模块的依赖。为什么不应用这些信息创立一个最小的运行时环境,其中只蕴含运行应用程序所需的那些模块呢?这能够通过 Java 9 中的新的 jlink 工具实现。你能够创立针对应用程序进行优化的最小运行时映像而不须要应用齐全加载 JDK 装置版本。
3\. JShell : 交互式 Java REPL
许多语言曾经具备交互式编程环境,Java 当初退出了这个俱乐部。您能够从控制台启动 jshell,并间接启动输出和执行 Java 代码。jshell 的即时反馈使它成为摸索 API 和尝试语言个性的好工具。
测试一个 Java 正则表达式是一个很好的阐明 jshell 如何使您的生存更轻松的例子。交互式 shell 还能够提供良好的教学环境以及进步生产力,您能够在此理解更多信息。在教人们如何编写 Java 的过程中,不再须要解释“public static void main(String [] args)”这句废话。
4\. 改良的 Javadoc
有时一些小事件能够带来很大的不同。你是否就像我一样在始终应用 Google 来查找正确的 Javadoc 页面呢?这不再须要了。Javadoc 当初反对在 API 文档中的进行搜寻。另外,Javadoc 的输入当初合乎兼容 HTML5 规范。此外,你会留神到,每个 Javadoc 页面都蕴含无关 JDK 模块类或接口起源的信息。
5\. 汇合工厂办法
通常,您心愿在代码中创立一个汇合(例如,List 或 Set),并间接用一些元素填充它。实例化汇合,几个“add”调用,使得代码反复。Java 9,增加了几种汇合工厂办法:
Set<Integer> ints = Set.of(1 , 2 , 3);
List<String> strings = List.of("first" , "second");</pre>
除了更短和更好浏览之外,这些办法也能够防止您抉择特定的汇合实现。事实上,从工厂办法返回已放入数个元素的汇合实现是高度优化的。这是可能的,因为它们是不可变的:在创立后,持续增加元素到这些汇合会导致“UnsupportedOperationException”。
6\. 改良的 Stream API
长期以来,Stream API 都是 Java 规范库最好的改良之一。通过这套 API 能够在汇合上建设用于转换的申明管道。在 Java 9 中它会变得更好。Stream 接口中增加了 4 个新的办法:dropWhile, takeWhile, ofNullable。还有个 iterate 办法的新重载办法,能够让你提供一个 Predicate (判断条件) 来指定什么时候完结迭代:
IntStream.iterate(1 , i -> i < 100 , i -> i + 1).forEach(System.out::println);</pre>
第二个参数是一个 Lambda,它会在以后 IntStream 中的元素达到 100 的时候返回 true。因而这个简略的示例是向控制台打印 1 到 99。
除了对 Stream 自身的扩大,Optional 和 Stream 之间的联合也失去了改良。当初能够通过 Optional 的新办法 stram
将一个 Optional 对象转换为一个 (可能是空的) Stream 对象:
Stream<Integer> s = Optional.of(1).stream();</pre>
在组合简单的 Stream 管道时,将 Optional 转换为 Stream 十分有用。
7\. 公有接口办法
Java 8 为咱们带来了接口的默认办法。接口当初也能够蕴含行为,而不仅仅是办法签名。然而,如果在接口上有几个默认办法,代码简直雷同,会产生什么状况?通常,您将重构这些办法,调用一个可复用的公有办法。但默认办法不能是公有的。将复用代码创立为一个默认办法不是一个解决方案,因为该辅助办法会成为公共 API 的一部分。应用 Java 9,您能够向接口增加公有辅助办法来解决此问题:
public interface MyInterface {
void normalInterfaceMethod();
default void interfaceMethodWithDefault() {init();
}
default void anotherDefaultMethod() {init();
}
// This method is not part of the public API exposed by MyInterface
private void init() { System.out.println( "Initializing");
}
}
如果您应用默认办法开发 API,那么公有接口办法可能有助于构建其实现。
8\. HTTP/2
Java 9 中有新的形式来解决 HTTP 调用。这个早退的个性用于代替老旧的 HttpURLConnection
API,并提供对 WebSocket 和 HTTP/2 的反对。留神:新的 HttpClient API 在 Java 9 中以所谓的孵化器模块交付。也就是说,这套 API 不能保障 100% 实现。不过你能够在 Java 9 中开始应用这套 API:
HttpClient client = HttpClient.newHttpClient();
HttpRequest req =
HttpRequest.newBuilder(URI.create( "http://www.google.com"))
.header("User-Agent" , "Java")
.GET()
.build();
HttpResponse<String> resp = client.send(req, HttpResponse.BodyHandler.asString());
HttpResponse<String> resp = client.send(req, HttpResponse.BodyHandler.asString()); 除了这个简略的申请 / 响应模型之外,HttpClient 还提供了新的 API 来解决 HTTP/2 的个性,比方流和服务端推送。
9. 多版本兼容 JAR
咱们最初要来着重介绍的这个个性对于库的维护者而言是个特地好的音讯。当一个新版本的 Java 呈现的时候,你的库用户要花费数年工夫才会切换到这个新的版本。这就意味着库得去向后兼容你想要反对的最老的 Java 版本 (许多状况下就是 Java 6 或者 7)。这实际上意味着将来的很长一段时间,你都不能在库中使用 Java 9 所提供的新个性。侥幸的是,多版本兼容 JAR 性能能让你创立仅在特定版本的 Java 环境中运行库程序时抉择应用的 class 版本:
multirelease.jar
├── META-INF
│ └── versions
│ └── 9
│ └── multirelease
│ └── Helper. class
├── multirelease
├── Helper. class
└── Main. class
在上述场景中,multirelease.jar 能够在 Java 9 中应用, 不过 Helper 这个类应用的不是顶层的 multirelease.Helper 这个 class, 而是处在“META-INF/versions/9”上面的这个。这是特地为 Java 9 筹备的 class 版本,能够使用 Java 9 所提供的个性和库。同时,在晚期的 Java 诸版本中应用这个 JAR 也是能运行的,因为较老版本的 Java 只会看到顶层的这个 Helper 类。
10. 多分辨率图像 API
Java 9 定义多分辨率图像 API,开发者能够很容易的操作和展现不同分辨率的图像了。
以下是多分辨率图像的次要操作方法:
- Image getResolutionVariant(double destImageWidth, double destImageHeight) − 获取特定分辨率的图像变体 - 示意一张已知分辨率单位为 DPI 的特定尺寸大小的逻辑图像,并且这张图像是最佳的变体。。
- List<Image> getResolutionVariants() − 返回可读的分辨率的图像变体列表。
实例
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import java.awt.Image;
import java.awt.image.MultiResolutionImage;
import java.awt.image.BaseMultiResolutionImage;
import javax.imageio.ImageIO;
public class Tester {public static void main(String[] args) throws IOException, MalformedURLException {
List<String> imgUrls = List.of("http://www.runoob.com/wp-content/themes/runoob/assets/img/runoob-logo@2x.png",
"http://www.runoob.com/wp-content/themes/runoob/assets/img/runoob-logo.png",
"http://www.runoob.com/wp-content/themes/runoob/assets/images/qrcode.png");
List<Image> images = new ArrayList<Image>();
for (String url : imgUrls) {images.add(ImageIO.read(new URL(url)));
}
// 读取所有图片
MultiResolutionImage multiResolutionImage =
new BaseMultiResolutionImage(images.toArray(new Image[0]));
// 获取图片的所有分辨率
List<Image> variants = multiResolutionImage.getResolutionVariants();
System.out.println("Total number of images:" + variants.size());
for (Image img : variants) {System.out.println(img);
}
// 依据不同尺寸获取对应的图像分辨率
Image variant1 = multiResolutionImage.getResolutionVariant(156, 45);
System.out.printf("\nImage for destination[%d,%d]: [%d,%d]",
156, 45, variant1.getWidth(null), variant1.getHeight(null));
Image variant2 = multiResolutionImage.getResolutionVariant(311, 89);
System.out.printf("\nImage for destination[%d,%d]: [%d,%d]", 311, 89,
variant2.getWidth(null), variant2.getHeight(null));
Image variant3 = multiResolutionImage.getResolutionVariant(622, 178);
System.out.printf("\nImage for destination[%d,%d]: [%d,%d]", 622, 178,
variant3.getWidth(null), variant3.getHeight(null));
Image variant4 = multiResolutionImage.getResolutionVariant(300, 300);
System.out.printf("\nImage for destination[%d,%d]: [%d,%d]", 300, 300,
variant4.getWidth(null), variant4.getHeight(null));
}
}
11.CompletableFuture API
Java 8 引入了 CompletableFuture<T>* 类,可能是 java.util.concurrent.Future<T> 明确的实现版(设置了它的值和状态),也可能被用作 java.util.concurrent.CompleteStage。反对 future 实现时触发一些依赖的函数和动作。Java 9 引入了一些 CompletableFuture 的改良:
Java 9 对 CompletableFuture 做了改良:
- 反对 delays 和 timeouts
- 晋升了对子类化的反对
- 新的工厂办法
反对 delays 和 timeouts
public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)
在 timeout(单位在 java.util.concurrent.Timeunits units 中,比方 MILLISECONDS)前以给定的 value 实现这个 CompletableFutrue。返回这个 CompletableFutrue。
public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit)</pre>
如果没有在给定的 timeout 内实现,就以 java.util.concurrent.TimeoutException 实现这个 CompletableFutrue,并返回这个 CompletableFutrue。
加强了对子类化的反对
做了许多改良使得 CompletableFuture 能够被更简略的继承。比方,你兴许想重写新的 public Executor defaultExecutor() 办法来代替默认的 executor。
另一个新的使子类化更容易的办法是:
public <U> CompletableFuture<U> newIncompleteFuture()</pre
新的工厂办法
Java 8 引入了 <U> CompletableFuture<U> completedFuture(U value) 工厂办法来返回一个曾经以给定 value 实现了的 CompletableFuture。Java 9 以 一个新的 <U> CompletableFuture<U> failedFuture(Throwable ex) 来补充了这个办法,能够返回一个以给定异样实现的 CompletableFuture。
除此以外,Java 9 引入了上面这对 stage-oriented 工厂办法,返回实现的或异样实现的 completion stages:
- <U> CompletionStage<U> completedStage(U value): 返回一个新的以指定 value 实现的 CompletionStage,并且只反对 CompletionStage 里的接口。
- <U> CompletionStage<U> failedStage(Throwable ex): 返回一个新的以指定异样实现的 CompletionStage,并且只反对 CompletionStage 里的接口。