更多的新特性能够参阅官网:What's New in JDK 9html
JDK 9 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk9-doc-downloads-3850606.htmljava
在关于 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 平台级模块系统shell
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 中模块工做的信息 。oracle
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,开发者能够很容易的操做和展现不一样分辨率的图像了。
如下是多分辨率图像的主要操做方法:
实例
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
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: