016Java9、10、11新特性

本文详细介绍了Java 9至11的新特性,包括模块系统Jigsaw、交互式编程工具jShell、集合工厂方法的快速创建只读集合、接口的私有方法、HTTP客户端API等。同时,讨论了Java 10的局部变量类型推断升级和Java 11的ZGC低延迟垃圾收集器、字符串处理方法等。这些新特性提升了Java的开发效率和性能。
摘要由CSDN通过智能技术生成

Java9新特性:

JDK 和 JRE 目录结构的改变:

Java8目录结构:
bin 目录包含命令行开发和调试工具, 如javac, jar和javadoc。
include目录包含在编译本地代码时使用的C/C++头文件
lib 目录包含JDK工具的几个JAR和其他类型的文件。 它有一个tools.jar文件, 其中包 含javac编译器的Java类
jre/bin 目录包含基本命令, 如java命令。 在Windows平台上, 它包含系统的运行时动态链 接库(DLL) 。
jre/lib 目录包含用户可编辑的配置文件, 如.properties和.policy文件。 包含几个JAR。 rt.jar文件包含运行时的Java类和资源文件
Java9目录结构:
没有名为jre的子目录
bin 目录包含所有命令。 在Windows平台上, 它继续包含系统的运行时动态链接库。
conf 目录包含用户可编辑的配置文件, 例如以前位于jre\lib目录中的.properties和.policy文件
include 目录包含要在以前编译本地代码时使用的C/C++头文件。 它只存在于JDK中
jmods 目录包含JMOD格式的平台模块。 创建自定义运行时映像时需要它。 它只存在于JDK中
legal 目录包含法律声明
lib 目录包含非Windows平台上的动态链接本地库。 其子目录和文件不应由开发人员直接编辑或使用
模块化系统: Jigsaw 到 Modularity:

模块将由通常的类和新的模块声明文件(module-info.java) 组成。

该文件是位于java代码结构的顶层, 该模块描述符明确地定义了我们的模块需要什么依赖关系,以及哪些模块被外部使用。

在exports子句中未提及的所有包默认情况下将封装在模块中, 不能在外部使用。

要想在java9demo模块中调用java9test模块下包中的结构, 需要在java9test的module-info.java中声明:
/*exports:
控制着哪些包可以被其它模块访问到。 
所有不被导出的包默认都被封装在模块里面。*/
module java9test {
	//package we export
	exports com.bean;
}
对应在java 9demo 模块的src 下创建module-info.java文件:
//requires:指明对其它模块的依赖。S
module java9demo {
	requires java9test;
}
Java的REPL工具: jShell命令

交互式编程环境 REPL (read - evaluate - print - loop)

jShell可以从文件中加载语句或者将语句保存到文件中。

jShell可以是tab键进行自动补全和自动添加分号。

可以重新定义相同方法名和参数列表的方法, 即为对现有方法的修改(或覆盖) 。

在 JShell 环境下, 语句末尾的“;” 是可选的。

jshell没有受检异常。

调出jshell:jshell

获取帮助:/help intro

查看已经导入的所有包:/imports

列出session里所有有效的代码片段:/list

查看session下所有创建过的变量:/vars

查看session下所有创建过的方法:/methods

使用外部编辑器来编写代码:/edit add

执行java文件:/open HelloWorld.java

退出jshell:/exit

Java9中可以接口声明私有方法。
Java9中能够与匿名实现类共同使用钻石操作符<>(diamond operator) 。
Comparator<Object> com = new Comparator<>(){
	@Override
	public int compare(Object o1, Object o2) {
		return 0;
	}
};
Java 8 中, 可以实现资源的自动关闭, 但是要求执行后必须关闭的所有资源必须在try子句中初始化, 否则编译不通过。
如下例所示:
try(InputStreamReader reader = new InputStreamReader(System.in)){
	//读取数据细节省略
}catch (IOException e){
	e.printStackTrace();
}
Java 9 中, 用资源语句编写try将更容易, 我们可以在try子句中使用已经初始化过的资源, 此时的资源是final的:
InputStreamReader reader = new InputStreamReader(System.in);
OutputStreamWriter writer = new OutputStreamWriter(System.out);
try (reader; writer) {
	//reader是final的,不可再被赋值
	//reader = null;
	//具体读写操作省略
} catch (IOException e) {
	e.printStackTrace();
}
Java9中String,StringBuffer,StringBuilder不用 char[] 来存储, 改成了 byte[] 加上编码标记, 节约了一些空间。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
@Stable
private final byte[] value;
}
集合工厂方法:快速创建只读集合
Java8中:
List<String> namesList = new ArrayList <>();
namesList.add("Joe");
namesList.add("Bob");
namesList.add("Bill");
namesList = Collections.unmodifiableList(namesList);
System.out.println(namesList);
Java9中:
List<String> list = Collections.unmodifiableList(Arrays.asList("a", "b", "c"));
Set<String> set = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("a","b", "c")));
// 如下操作不适用于jdk 8 及之前版本,适用于jdk 9
Map<String, Integer> map = Collections.unmodifiableMap(new HashMap<>() {
{
	put("a", 1);
	put("b", 2);
	put("c", 3);
}
});
map.forEach((k, v) -> System.out.println(k + ":" + v));
List firsnamesList = List.of(“Joe”,”Bob”,”Bill”);

调用集合中静态方法of(), 可以将不同数量的参数传输到此工厂方法中。

此功能可用于Set和List, 也可用于Map的类似形式。

此时得到的集合, 是不可变的:在创建后, 继续添加元素到这些集合会导致 “UnsupportedOperationException” 。

由于Java 8中接口方法的实现, 可以直接在List, Set和Map的接口内定义这些方法,便于调用。

InputStream 加强:
InputStream 有了一个方法: transferTo,可以用来将数据直接传输到 OutputStream 。
ClassLoader cl = this.getClass().getClassLoader();
try (InputStream is = cl.getResourceAsStream("hello.txt");
OutputStream os = new FileOutputStream("src\\hello1.txt")) {
	is.transferTo(os); // 把输入流中的所有数据直接自动地复制到输出流中
} catch (IOException e) {
	e.printStackTrace();
}
增强的 Stream API:

Stream 接口中添加了 4 个新的方法:takeWhile, dropWhile, ofNullable,还有个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。

除了对 Stream 本身的扩展, Optional 和 Stream 之间的结合也得到了改进。

现在可以通过 Optional 的新方法 stream() 将一个 Optional 对象转换为一个(可能是空的) Stream 对象。

/*
takeWhile()的使用
用于从 Stream 中获取一部分数据, 接收一个 Predicate 来进行选择。 
在有序的Stream 中, takeWhile 返回从开头开始的尽量多的元素。
*/
List<Integer> list = Arrays.asList(45, 43, 76, 87, 42, 77, 90, 73, 67, 88);
list.stream().takeWhile(x -> x < 50).forEach(System.out::println);
System.out.println();
list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
list.stream().takeWhile(x -> x < 5).forEach(System.out::println);

/*
dropWhile()的使用
dropWhile 的行为与 takeWhile 相反, 返回剩余的元素。
*/
List<Integer> list = Arrays.asList(45, 43, 76, 87, 42, 77, 90, 73, 67, 88);
list.stream().dropWhile(x -> x < 50).forEach(System.out::println);
System.out.println();
list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
list.stream().dropWhile(x -> x < 5).forEach(System.out::println);

/*
ofNullable()的使用
Java 8 中 Stream 不能完全为null, 否则会报空指针异常。 
而 Java 9 中的 ofNullable 方法允许我们创建一个单元素 Stream, 可以包含一个非空元素, 也可以创建一个空Stream。
*/
// 报NullPointerException
// Stream<Object> stream1 = Stream.of(null);
// System.out.println(stream1.count());
// 不报异常,允许通过
Stream<String> stringStream = Stream.of("AA", "BB", null);
System.out.println(stringStream.count());// 3
// 不报异常,允许通过
List<String> list = new ArrayList<>();
list.add("AA");
list.add(null);
System.out.println(list.stream().count());// 2
// ofNullable():允许值为null
Stream<Object> stream1 = Stream.ofNullable(null);
System.out.println(stream1.count());// 0
Stream<String> stream = Stream.ofNullable("hello world");
System.out.println(stream.count());// 1

/*
iterate()重载的使用
这个 iterate 方法的新重载方法, 可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。
*/
// 原来的控制终止方式:
Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println);
// 现在的终止方式:
Stream.iterate(1, i -> i < 100, i -> i + 1).forEach(System.out::println);

/*
Optional类中stream()的使用
*/
List<String> list = new ArrayList<>();
list.add("Tom");
list.add("Jerry");
list.add("Tim");
Optional<List<String>> optional = Optional.ofNullable(list);
Stream<List<String>> stream = optional.stream();
stream.flatMap(x -> x.stream()).forEach(System.out::println);
Javascript引擎升级: Nashorn

Nashorn 项目在 JDK 9 中得到改进, 它为 Java 提供轻量级的 Javascript 运行时。

Nashorn 项目跟随 Netscape 的 Rhino 项目, 目的是为了在 Java 中实现一个高性能但轻量级的 Javascript 运行时。

Nashorn 项目使得 Java 应用能够嵌入Javascript。

它在 JDK 8 中为 Java 提供一个 Javascript 引擎。

JDK 9 包含一个用来解析 Nashorn 的 ECMAScript 语法树的 API。

这个 API 使得IDE 和服务端框架不需要依赖 Nashorn 项目的内部实现类, 就能够分析ECMAScript 代码。

Java10新特性:

JDK10一共定义了109个新特性, 其中包含12个JEP (JDK Enhancement Proposal特性加强提议) 。

局部变量类型推断
//1.局部变量的初始化
var list = new ArrayList<>();
//2.增强for循环中的索引
for(var v : list) {
	System.out.println(v);
}
//3.传统for循环中
for(var i = 0;i < 100;i++) {
	System.out.println(i);
}

/*
如下情况不适用:
 情况1: 没有初始化的局部变量声明
 情况2: 方法的返回类型
 情况3: 方法的参数类型
 情况4: 构造器的参数类型
 情况5: 属性
 情况6: catch块,Lambda表达式,方法引用,为数组静态初始化,局部变量初始值为null
 
*/
工作原理:

在处理 var时, 编译器先是查看表达式右边部分, 并根据右边变量值的类型进行推断, 作为左边变量的类型, 然后将该类型写入字节码当中。

注意:var不是一个关键字,除了不能用它作为类名,变量名或方法名等均可使用。

var并不会改变Java是一门静态类型语言的事实。 编译器负责推断出类型, 并把结果写入字节码文件 。

自 Java 9 开始, Jdk 里面为集合(List / Set / Map) 都添加了 of (jdk9新增)和copyOf (jdk10新增)方法, 它们两个都用来创建不可变的集合, 来看下它们的使用和区别如下:

//示例1:
var list1 = List.of("Java", "Python", "C");
var copy1 = List.copyOf(list1);
System.out.println(list1 == copy1); // true
//示例2:
var list2 = new ArrayList<String>();
var copy2 = List.copyOf(list2);
System.out.println(list2 == copy2); // false

/*
从源码分析,可以看出copyOf方法会先判断来源集合是不是AbstractImmutableList类型的,如果是,就直接返回,如果不是,则调用of创建一个新的集合。
示例2因为用的new创建的集合,不属于不可变AbstractImmutableList类的子类,所以copyOf方法又创建了一个新的实例,所以为false。

注意:使用of和copyOf创建的集合为不可变集合,不能进行添加、删除、替换、排序等操作,不然会报java.lang.UnsupportedOperationException异常。
上面演示了List的of和copyOf方法,Set和Map接口都有。
*/

Java11新特性:LTS (Long-Term-Support)

Java11 将带来 ZGC、Http Client 等重要特性, 一共包含 17 个 JEP(JDK Enhancement Proposals, JDK 增强提案) 。

JDK 11 是一个长期支持版本(LTS, Long-Term-Support)。

ZGC:能够保证不超过 10ms 的 GC 暂停。

新增了一系列字符串处理方法:

描述举例
判断字符串是否为空白" ".isBlank(); // true
去除首尾空白" Javastack ".strip(); // “Javastack”
去除尾部空格" Javastack “.stripTrailing(); // " Javastack”
去除首部空格" Javastack ".stripLeading(); // "Javastack "
复制字符串“Java”.repeat(3);// “JavaJavaJava”
行数统计“A\nB\nC”.lines().count(); // 3

Optional 加强:

可以很方便的将一个 Optional 转换成一个 Stream, 或者当一个空 Optional 时给它一个替代的。

新增方法描述新增的版本
boolean isEmpty()判断value是否为空JDK 11
ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)value非空,执行参数1功能;如果value 为空,执行参数2功能JDK 9
Optional or(Supplier<? extends Optional<? extends T>> supplier)value非空,返回对应的Optional; value为空,返回形参封装的OptionalJDK 9
Stream stream()value非空,返回仅包含此value的 Stream;否则,返回一个空的StreamJDK 9
T orElseThrow()value非空,返回value;否则抛异常 NoSuchElementExceptionJDK 10

局部变量类型推断升级:

在var上添加注解的语法格式,在JDK11中加入了这样的语法。

//错误的形式: 必须要有类型, 可以加上var
//Consumer<String> con1 = (@Deprecated t) ->
System.out.println(t.toUpperCase());
//正确的形式:
//使用var的好处是在使用lambda表达式时给参数加上注解。
Consumer<String> con2 = (@Deprecated var t) ->
System.out.println(t.toUpperCase());

全新的HTTP 客户端API:

HTTP,用于传输网页的协议,早在1997年就被采用在目前的1.1版本中。

直到2015年, HTTP2才成为标准。

HTTP/1.1和HTTP/2的主要区别是如何在客户端和服务器之间构建和传输数据。

HTTP/1.1依赖于请求/响应周期。

HTTP/2允许服务器“push”数据:它可以发送比客户端请求更多的数据。

这使得它可以优先处理并发送对于首先加载网页至关重要的数据。

这是 Java 9 开始引入的一个处理 HTTP 请求的的 HTTP Client API, 该API 支持同步和异步, 而在 Java 11 中已经为正式可用状态, 你可以在java.net 包中找到这个 API。

它 将 替 代 仅 适 用 于 blocking 模 式 的 HttpURLConnection( HttpURLConnection是在HTTP 1.0的时代创建的, 并使用了协议无关的方法) , 并提供对WebSocket 和 HTTP/2的支持。

HttpClient client = HttpClient.newHttpClient();
HttpRequest request =
HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/")).build();
BodyHandler<String> responseBodyHandler = BodyHandlers.ofString();
HttpResponse<String> response = client.send(request, responseBodyHandler);
String body = response.body();
System.out.println(body);

HttpClient client = HttpClient.newHttpClient();
HttpRequest request =
HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/")).build();
BodyHandler<String> responseBodyHandler = BodyHandlers.ofString();
CompletableFuture<HttpResponse<String>> sendAsync =
client.sendAsync(request, responseBodyHandler);
sendAsync.thenApply(t -> t.body()).thenAccept(System.out::println);
//HttpResponse<String> response = sendAsync.get();
//String body = response.body();
//System.out.println(body);

更简化的编译运行程序:

可以直接编译运行java文件:java Javastack.java

一个命令编译运行源代码的注意点:

执行源文件中的第一个类, 第一个类必须包含主方法。

并且不可以使用其它源文件中的自定义类, 本文件中的自定义类是可以使用的。

ZGC:

GC是java主要优势之一。

然而, 当GC停顿太长, 就会开始影响应用的响应时间。

消除或者减少GC停顿时长, java将对更广泛的应用场景是一个更有吸引力的平台。

此外, 现代系统中可用内存不断增长,用户和程序员希望JVM能够以高效的方式充分利用这些内存, 并且无需长时间的GC暂停时间。

ZGC, A Scalable Low-Latency Garbage Collector(Experimental)ZGC, 这应该是JDK11最为瞩目的特性, 没有之一。

但是后面带了Experimental,说明这还不建议用到生产环境。

ZGC是一个并发, 基于region, 压缩型的垃圾收集器, 只有root扫描阶段会STW(stop the world), 因此GC停顿时间不会随着堆的增长和存活对象的增长而变长。

优势:

GC暂停时间不会超过10ms

既能处理几百兆的小堆, 也能处理几个T的大堆(OMG)

和G1相比, 应用吞吐能力不会下降超过15%

为未来的GC功能和利用colord指针以及Load barriers优化奠定基础

初始只支持64位系统

ZGC的设计目标是:

支持TB级内存容量, 暂停时间低(<10ms) , 对整个程序吞吐量的影响小于15%。

将来还可以扩展实现机制, 以支持不少令人兴奋的功能, 例如多层堆(即热对象置于DRAM和冷对象置于NVMe闪存) ,
或压缩堆。

其他新特性:

Unicode 10
Deprecate the Pack200 Tools and API
新的Epsilon垃圾收集器
完全支持Linux容器(包括Docker)
支持G1上的并行完全垃圾收集
最新的HTTPS安全协议TLS 1.3
Java Flight Recorder

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值