JDK9新特性揭秘

2017年9月JDK -9发布,官网声明:Oracle will not post further updates of Java SE 8 to its public download sites for commercial use after September 2018.尽早规划新版本的使用,不失为一种好的选择,本文着重介绍JDK9新特性

安装与环境变量配置

JDK9安装

JDK9较之前版本,目录结构和配置方面,稍有不同
首先下载最新版的JDK-9

安装方式与之前版本一样,没有任何差别,但安装后的目录结构不同,如下图所示

为了直观对比,下面贴出JDK8的目录结构,如下图所示

新版jdk目录中,没有jre文件夹了,这导致环境变量配置有所不同

JDK9配置

1
2
3
4
JAVA_HOME=jdk安装路径
JRE_HOME=jre安装路径
PATH= .;%JAVA_HOME%\bin;%JRE_HOME%\bin
CLASSPATH=.;%JAVA_HOME%\lib;%JRE_HOME%\lib

原来CLASSPATH里的几个jar包不需要再配置了,也找不到了,以下是JDK8配置

1
2
3
4
5
6
7
8
JAVA_HOME=jdk安装路径
PATH=$JAVA_HOME/bin
CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar

JAVA_HOME=jdk安装路径
JRE_HOME=jre安装路径
PATH=${JAVA_HOME}/bin
CLASSPATH=.;${JAVA_HOME}/lib:${JRE_HOME}/lib

IDEA配置JDK

file -> Project Structure -> SDKs -> 点击加号,然后选择JDK目录即可

JDK9 新特性

模块化

首先,我们创建一个普通的Java项目,然后创建一个模块 tools

IntelliJ IDEA 会引导你在工程中为你的模块创建一个module-info.java

之后,在需要使用ConvertUtils类的地方,进行模块引入即可

注意:模块引入可以由IntelliJ IDEA自动完成

如你所料,进行这个操作后IntelliJ IDEA对module-info.java文件进行了正确的更改
当然,也可以自己编辑module-info.java文件,IDEA 会有自动补全和提示信息

网络请求

Java 9 中有新的方式来处理 HTTP 调用。这个迟到的特性用于代替老旧的 HttpURLConnection API,并提供对 WebSocket 和 HTTP/2 的支持。
注意:新的 HttpClient API 在 Java 9 中以所谓的孵化器模块交付。也就是说,这套 API 不能保证 100% 完成。不过你可以在 Java 9 中开始使用这套 API
module-info.java引入如下代码

1
2
3
module JDK9 {
requires jdk.incubator.httpclient;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.cnlod.blog;
import jdk.incubator.http.HttpClient;
import jdk.incubator.http.HttpRequest;
import jdk.incubator.http.HttpResponse;
import java.io.IOException;
import java.net.URI;

public class Http2 {
private static String url = "http://xxx.xxx.com/xx?a=1";
public static void main(String[] args) throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url)).header("User-Agent","Java").GET().build();
//除了这个简单的请求/响应模型之外,HttpClient 还提供了新的 API 来处理 HTTP/2 的特性,比如流和服务端推送
HttpResponse<String> resp = client.send(request, HttpResponse.BodyHandler.asString());
System.out.println(resp.body());
}
}

更多HTTP/2使用方法,请参考《HTTP/2 Client API

改进的 Stream API

长期以来,Stream API 都是 Java 标准库最好的改进之一。通过这套 API 可以在集合上建立用于转换的申明管道。在 Java 9 中它会变得更好。
Stream 接口中添加了 4 个新的方法:dropWhile, takeWhile, ofNullable。还有个 iterate 方法的新重载方法,
可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代:

1
2
3
4
5
public static void main(String[] args) {
IntStream.iterate(1,i -> i<10,i -> i+1).forEach(System.out::println);
Stream<Integer> it = Optional.of(2).stream();
System.out.println("=="+it.count());
}

集合工厂

通常,您希望在代码中创建一个集合(例如,List 或 Set ),并直接用一些元素填充它。 实例化集合,几个 “add” 调用,使得代码重复。
Java 9,添加了几种集合工厂方法

1
2
3
4
5
6
7
8
public static void main(String[] args) {
Set sets1 = Set.of();//空集合
System.out.println(sets1.size()+"==========");
Set<String> sets2 = Set.of("a","b","c");
System.out.println(sets2.size()+"---------");
List<String> lists1 = List.of("h","m","d");
System.out.println(lists1.size()+"++++++++++");
}

Java8:Optional类

这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static void main(String[] args) {
/**
* 1.of方法通过工厂方法创建Optional类。需要注意的是,创建对象时传入的参数不能为null。如果传入参数为null,则抛出NullPointerException 。
*/
Optional<String> name = Optional.of("Andy");
/**
* 2.ofNullable与of方法相似,唯一的区别是可以接受参数为null的情况
* 为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional。
*/
Optional empty = Optional.ofNullable(null);
//System.out.println(empty.isPresent()); //如果值存在返回true,否则返回false。

//3.如果Optional实例有值则为其调用consumer,否则不做处理
/*name.ifPresent((value) -> {
System.out.println(value);
});*/

//4.orElse:如果有值则将其返回,否则返回指定的其它值。
/*System.out.println(empty.orElse("没有值,采用此默认值!"));
System.out.println(name.orElse("有值,不采用此默认值!"));*/

/**
* 5.orElseGet:orElseGet与orElse方法类似,区别在于得到的默认值。
* orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。示例如下:
*/
//System.out.println(empty.orElseGet(() -> "Default Value"));
//System.out.println(name.orElseGet(() -> "Default Value"));
}

Java8:接口中定义默认方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface MyInterface {
//接口定义普通方法
void sayHelloToMe();
/**
* Java 8 为我们带来了接口的默认方法。 接口现在也可以包含行为,而不仅仅是方法签名。
*/
default void sayHelloToOurTeam(){
System.out.println("团队成员你们好");
}
default void sayHelloToMyLeader(){
myInit("首长好!");
}
/**
* This method is not part of the public API
*/
private void myInit(String content){
System.out.println(content);
}
}
1
2
3
4
5
public class MyInterfaceImpl implements MyInterface {
@Override
public void sayHelloToMe() {
}
}
1
2
3
4
5
6
7
8
9
public class MyInterfaceImpl2 implements MyInterface {
@Override
public void sayHelloToMe() {
}
@Override
public void sayHelloToOurTeam() {
System.out.println("技术部的团队成员你们好!");
}
}

Java8:eta-conversion

Java8开始支持ETA转换,代码更简洁,用::表示函数引用,比如静态方法的引用String::valueOf;比如构造器的引用,ArrayList::new等

1
2
3
for (Object n : list) { System.out.println(n); } # 普通循环
list.forEach(n -> System.out.println(n)); # lambda
list.forEach(System.out::println); ## ::引用

JDK9新特性DEMO
更多信息请参考Everything about Java 8

文章目录
  1. 1. 安装与环境变量配置
    1. 1.1. JDK9安装
    2. 1.2. JDK9配置
    3. 1.3. IDEA配置JDK
  2. 2. JDK9 新特性
    1. 2.1. 模块化
    2. 2.2. 网络请求
    3. 2.3. 改进的 Stream API
    4. 2.4. 集合工厂
    5. 2.5. Java8:Optional类
    6. 2.6. Java8:接口中定义默认方法
    7. 2.7. Java8:eta-conversion