文章目录
Java9的新特性
JDK 9 的发布
- 经过4次跳票,历经曲折的Java 9 终于终于在2017年9月21日发布。
- 从Java 9 这个版本开始,Java 的计划发布周期是 6 个月,下一个 Java 的主版本将于 2018 年 3 月发布,命名为 Java 18.3,紧接着再过六个月将发布 Java18.9。
- 这意味着Java的更新从传统的以特性驱动的发布周期,转变为以时间驱动的(6 个月为周期)发布模式,并逐步的将 Oracle JDK 原商业特性进行开源。
- 针对企业客户的需求,Oracle 将以三年为周期发布长期支持版本(long termsupport)。
- Java 9 提供了超过150项新功能特性,包括备受期待的模块化系统、可交互的 REPL 工具:jshell,JDK 编译工具,Java 公共 API 和私有代码,以及安全增强、扩展提升、性能管理改善等。可以说Java 9是一个庞大的系统工程,完全做了一个整体改变。
- 模块化系统
- jShell命令
- 多版本兼容jar包
- 接口的私有方法
- 语法改进:钻石操作符的使用升级
- 语法改进:try语句
- String存储结构变更
- 集合工厂方法:快速创建只读集合-便利的集合特性:of()
- 增强的Stream API
- 全新的HTTP客户端API
- Deprecated的相关API
- javadoc的HTML 5支持
- Javascript引擎升级:Nashorn
- java的动态编译器
JDK 和 JRE 目录结构的改变
JDK8的目录结构
JDK 9 的目录结构
模块化系统: Jigsaw -> Modularity
-
谈到 Java 9 大家往往第一个想到的就是 Jigsaw 项目。众所周知,Java 已经
发展超过 20 年(95 年最初发布),Java 和相关生态在不断丰富的同时也越
来越暴露出一些问题:- Java 运行环境的膨胀和臃肿。每次JVM启动的时候,至少会有30~60MB的内存
加载,主要原因是JVM需要加载rt.jar,不管其中的类是否被classloader加载,第
一步整个jar都会被JVM加载到内存当中去(而模块化可以根据模块的需要加载程
序运行需要的class) - **当代码库越来越大,创建复杂,盘根错节的“意大利面条式代码”的几率呈指数级的
增长。**不同版本的类库交叉依赖导致让人头疼的问题,这些都阻碍了 Java 开发和
运行效率的提升。 - 很难真正地对代码进行封装, 而系统并没有对不同部分(也就是 JAR 文件)之间
的依赖关系有个明确的概念。每一个公共类都可以被类路径之下任何其它的公共
类所访问到,这样就会导致无意中使用了并不想被公开访问的 API。
- Java 运行环境的膨胀和臃肿。每次JVM启动的时候,至少会有30~60MB的内存
-
本质上讲也就是说,用模块来管理各个package,通过声明某个package暴露,模块(module)的概念,其实就是package外再裹一层,不声明默认就是隐藏。因此,模块化使得代码组织上更安全,因为它可以指定哪些部分可以暴露,哪些部分隐藏。
-
实现目标
- 模块化的主要目的在于减少内存的开销
- 只须必要模块,而非全部jdk模块,可简化各种类库和大型应用的开发和维护
- 改进 Java SE 平台,使其可以适应不同大小的计算设备
- 改进其安全性,可维护性,提高性能
模块将由通常的类和新的模块声明文件(module-info.java)组成。该文件是位于java代码结构的顶层,该模块描述符明确地定义了我们的模块需要什么依赖关系,以及哪些模块被外部使用。在exports子句中未提及的所有包默认情况下将封装在模块中,不能在外部使用。
要想在java9demo模块中调用java9test模块下包中的结构,需要在java9test的module-info.java中声明:
module java9test {
//package we export
exports com.atguigui.bean;
}
exports:控制着哪些包可以被其它模块访问到。所有不被导出的包默认都被封装在模块里面。
对应在java 9demo 模块的src 下创建module-info.java文件:
module java9demo {
requires java9test;
}
requires:指明对其它模块的依赖。
Java的REPL工具: jShell命令
接口的私有方法
Java 8中规定接口中的方法除了抽象方法之外,还可以定义静态方法和默认的方法。一定程度上,扩展了接口的功能,此时的接口更像是一个抽象类。
在Java 9中,接口更加的灵活和强大,连方法的访问权限修饰符都可以声明为private的了,此时方法将不会成为你对外暴露的API的一部分。
interface MyInterface{
void normalInterfaceMethod();
default void methodDefault1(){
init();
}
public default void methodDefault2(){
init();
}
// This method is not part of the public API exposed by MyInterface
private void init(){
System.out.println("默认方法中的通用操作");
}
}
class MyInterfaceImpl implements MyInterface {
@Override
public void normalInterfaceMethod() {
System.out.println("实现接口的方法");
}
}
public class MyInterfaceTest {
public static void main(String[] args) {
MyInterfaceImpl impl = new MyInterfaceImpl();
impl.methodDefault1();
// impl.init();//不能调用
}
}
语法改进:钻石操作符使用升级
我们将能够与匿名实现类共同使用钻石操作符(diamond operator)在Java 8中如下的操作是会报错的:
Comparator<Object> com = new Comparator<>(){
@Override
public int compare(Object o1, Object o2) {
return 0;
}
};
编译报错信息:Cannot use “<>” with anonymous inner classes.
Java 9中如下操作可以正常执行通过:
// anonymous classes can now use type inference
Comparator<Object> com = new Comparator<>(){
@Override
public int compare(Object o1, Object o2) {
return 0;
}
};
语法改进:try语句
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();
}
String存储结构变更
集合工厂方法:快速创建只读集合-便利的集合特性:of()
要创建一个只读、不可改变的集合,必须构造和分配它,然后添加元素,最后包装成一个不可修改的集合。
List<String> namesList = new ArrayList <>();
namesList.add("Joe");
namesList.add("Bob");
namesList.add("Bill");
namesList = Collections.unmodifiableList(namesList);
System.out.println(namesList);
缺点:我们一下写了五行。即:它不能表达为单个表达式。
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));
Java 9因此引入了方便的方法,这使得类似的事情更容易表达。
增强的Stream API
Java10的新特性
- 2018年3月21日,Oracle官方宣布Java10正式发布。
- 需要注意的是 Java 9 和 Java 10 都不是 LTS (Long-Term-Support) 版本。和过去的 Java 大版本升级不同,这两个只有半年左右的开发和维护期。而未来的 Java 11,也就是 18.9 LTS,才是 Java 8 之后第一个 LTS 版本。
- JDK10一共定义了109个新特性,其中包含12个JEP(对于程序员来讲,真正的新特性其实就一个),还有一些新API和JVM规范以及JAVA语言规范上的改动。
- JDK10的12个JEP(JDK Enhancement Proposal特性加强提议)参阅官方文档:http://openjdk.java.net/projects/jdk/10/
局部变量类型推断
- 产生背景
开发者经常抱怨Java中引用代码的程度。局部变量的显示类型声明,常常被认为是不必须的,给一个好听的名字经常可以很清楚的表达出下面应该怎样继续。 - 好处:
减少了啰嗦和形式的代码,避免了信息冗余,而且对齐了变量名,更容易阅读! - 举例如下:
-
场景一:类实例化时
作为 Java开发者,在声明一个变量时,我们总是习惯了敲打两次变量类型,第一次用于声明变量类型,第二次用于构造器。
LinkedHashSet<Integer> set = new LinkedHashSet<>();
-
场景二:返回值类型含复杂泛型结构
变量的声明类型书写复杂且较长,尤其是加上泛型的使用
Iterator<Map.Entry<Integer, Student>> iterator = set.iterator();
-
场景三:
我们也经常声明一种变量,它只会被使用一次,而且是用在下一行代码中,比如:
-
URL url = new URL("http://www.atguigu.com");
URLConnection connection = url.openConnection();
Reader reader = new BufferedReader(new
InputStreamReader(connection.getInputStream()));
适用于以下情况:
//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块
集合新增创建不可变集合的方法
自 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
//示例1和2代码基本一致,为什么一个为true,一个为false?
从 源 码 分 析 , 可 以 看 出 copyOf方 法 会 先 判 断 来 源 集 合 是 不 是AbstractImmutableList 类型的,如果是,就直接返回,如果不是,则调用 of 创建一个新的集合。
示例2因为用的 new 创建的集合,不属于不可变 AbstractImmutableList 类的子类,所以 copyOf 方法又创建了一个新的实例,所以为false。
注意:使用of和copyOf创建的集合为不可变集合,不能进行添加、删除、替换、排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。
上面演示了 List 的 of 和 copyOf 方法,Set 和 Map 接口都有。
Java11的新特性
北京时间 2018年9 月 26 日,Oracle 官方宣布 Java 11 正式发布。这是 Java 大版本周期变化后的第一个长期支持版本,非常值得关注。从官网即可下载,最新发布的 Java11 将带来 ZGC、Http Client 等重要特性,一共包含 17 个 JEP(JDK Enhancement Proposals,JDK 增强提案)。其实,总共更新不止17个,只是我们更关注如下的17个JEP更新。
JDK 11 是一个长期支持版本(LTS, Long-Term-Support)
- 对于企业来说,选择 11 将意味着长期的、可靠的、可预测的技术路线图。其中免费的OpenJDK11 确定将得到 OpenJDK 社区的长期支持, LTS 版本将是可以放心选择的版本。
- 从 JVM GC 的角度,JDK11 引入了两种新的 GC,其中包括也许是划时代意义的 ZGC,虽然其目前还是实验特性,但是从能力上来看,这是 JDK 的一个巨大突破,为特定生产环境的苛刻需求提供了一个可能的选择。例如,对部分企业核心存储等产品,如果能够保证不超过 10ms 的 GC 暂停,可靠性会上一个大的台阶,这是过去我们进行 GC 调优几乎做不到的,是能与不能的问题。
官网公开的 17 个 JEP(JDK Enhancement Proposal 特性增强提议)
181: Nest-Based Access Control(基于嵌套的访问控制)
309: Dynamic Class-File Constants(动态的类文件常量)
315: Improve Aarch64 Intrinsics(改进 Aarch64 Intrinsics)
318: Epsilon: A No-Op Garbage Collector(Epsilon 垃圾回收器,又被称为"No-Op(无操作)"回收器)
320: Remove the Java EE and CORBA Modules(移除 Java EE 和 CORBA 模块,JavaFX也已被移除)
321: HTTP Client (Standard)
323: Local-Variable Syntax for Lambda Parameters(用于 Lambda 参数的局部变量语法)
324: Key Agreement with Curve25519 and Curve448(采用 Curve25519 和 Curve448 算法实现的密钥协议)
327: Unicode 10
328: Flight Recorder(飞行记录仪)
329: ChaCha20 and Poly1305 Cryptographic Algorithms(实现 ChaCha20 和 Poly1305 加密算法)
330: Launch Single-File Source-Code Programs(启动单个 Java 源代码文件的程序)
331: Low-Overhead Heap Profiling(低开销的堆分配采样方法)
332: Transport Layer Security (TLS) 1.3(对 TLS 1.3 的支持)
333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental)(ZGC:可伸缩的低延迟垃圾回收器,处于实验性阶段)
335: Deprecate the Nashorn JavaScript Engine(弃用 Nashorn JavaScript 引擎)
336: Deprecate the Pack200 Tools and API(弃用 Pack200 工具及其 API)
新增了一系列字符串处理方法
Optional 加强
Optional 也增加了几个非常酷的方法,现在可以很方便的将一个 Optional 转换
成一个 Stream, 或者当一个空 Optional 时给它一个替代的。
局部变量类型推断升级
在var上添加注解的语法格式,在jdk10中是不能实现的。在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
更简化的编译运行程序
废弃Nashorn引擎
废除Nashorn javascript引擎,在后续版本准备移除掉,有需要的
可以考虑使用GraalVM。
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