Java9&Java10& Java11新特性笔记

Java9&Java10&Java11新特性


自从 2017 年 9 月 21 日 Java 9 正式发布之时,Oracle 就宣布今后会按照每六个月一次的节奏进行更新。

17-1 Java 9 的新特性

一、JDK 9 的发布
 经过4次跳票,历经曲折的Java 9 终于终于在2017年9月21日发布。
 从Java 9 这个版本开始,Java 的计划发布周期是 6 个月,下一个 Java 的主版本将于 2018 年 3 月发布,命名为 Java 18.3,紧接着再过六个月将发布 Java 18.9。
 这意味着Java的更新从传统的以特性驱动的发布周期,转变为以时间驱动的(6 个月为周期)发布模式,并逐步的将 Oracle JDK 原商业特性进行开源。
 针对企业客户的需求,Oracle 将以三年为周期发布长期支持版本(long term support)。
 Java 9 提供了超过150项新功能特性,包括备受期待的模块化系统、可交互的 REPL 工具:jshell,JDK 编译工具,Java 公共 API 和私有代码,以及安全增强、扩展提升、性能管理改善等。可以说Java 9是一个庞大的系统工程,完全做了一个整体改变。
二、Java 9 中有哪些不得不说的新特性?
 模块化系统
 jShell命令
 多版本兼容jar包
 接口的私有方法
 钻石操作符的使用升级
 语法改进:try语句
 String存储结构变更
 便利的集合特性:of()
 增强的Stream API
 全新的HTTP客户端API
 Deprecated的相关API
 javadoc的HTML 5支持
 Javascript引擎升级:Nashorn
 java的动态编译器

 官方提供的新特性列表:
https://docs.oracle.com/javase/9/whatsnew/toc.htm#JSNEW-GUID-C23AFD78-C777-460B-8ACE-58BE5EA681F6
 或参考 Open JDK
http://openjdk.java.net/projects/jdk9/
 在线Oracle JDK 9 Documentation
https://docs.oracle.com/javase/9/

三、、JDK 和 JRE 目录结构的改变
JDK 8 的目录结构

在这里插入图片描述

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类和资源文件。

JDK 9 的目录结构(没有名为jre的子目录
)

在这里插入图片描述

bin 目录包含所有命令。 在Windows平台上,它继续包含系统的运行时动态链接库。
conf 目录包含用户可编辑的配置文件,例如以前位于jre\lib目录中的.properties和.policy文件
include 目录包含要在以前编译本地代码时使用的C/C++头文件。 它只存在于JDK中
jmods 目录包含JMOD格式的平台模块。 创建自定义运行时映像时需要它。 它只存在于JDK中
legal 目录包含法律声明
lib 目录包含非Windows平台上的动态链接本地库。 其子目录和文件不应由开发人员直接编辑或使用

四、模块化系统: Jigsaw --> Modularity
谈到 Java 9 大家往往第一个想到的就是 Jigsaw 项目。众所周知,Java 已经发展超过 20 年(95 年最初发布),Java 和相关生态在不断丰富的同时也越来越暴露出一些问题:
 Java 运行环境的膨胀和臃肿。每次JVM启动的时候,至少会有30~60MB的内存加载,主要原因是JVM需要加载rt.jar,不管其中的类是否被classloader加载,第一步整个jar都会被JVM加载到内存当中去(而模块化可以根据模块的需要加载程序运行需要的class)
 当代码库越来越大,创建复杂,盘根错节的“意大利面条式代码”的几率呈指数级的增长。不同版本的类库交叉依赖导致让人头疼的问题,这些都阻碍了 Java 开发和运行效率的提升。
 很难真正地对代码进行封装, 而系统并没有对不同部分(也就是 JAR 文件)之间的依赖关系有个明确的概念。每一个公共类都可以被类路径之下任何其它的公共类所访问到,这样就会导致无意中使用了并不想被公开访问的 API。
 本质上讲也就是说,用模块来管理各个package,通过声明某个package暴露,,模块(module)的概念,其实就是package外再裹一层,不声明默认就是隐藏。因此,模块化使得代码组织上更安全,因为它可以指定哪些部分可以暴露,哪些部分隐藏。
 实现目标

模块化的主要目的在于减少内存的开销
只须必要模块,而非全部jdk模块,可简化各种类库和大型应用的开发和维护
改进 Java SE 平台,使其可以适应不同大小的计算设备
改进其安全性,可维护性,提高性能

模块将由通常的类和新的模块声明文件(module-info.java)组成。该文件是位于
java代码结构的顶层,该模块描述符明确地定义了我们的模块需要什么依赖关系,以及哪些模块被外部使用。在exports子句中未提及的所有包默认情况下将封装在模块中,不能在外部使用。

在这里插入图片描述

要想在java9demo模块中调用java9test模块下包中的结构,需要在java9test的module-info.java中声明:

/**
*@author songhongkang
*@create 2019 下午 11:57
*/
module java9test {
//package we export
exports com.atguigui.bean;
}
exports:控制着哪些包可以被其它模块访问到。所有不被导出的包默认都被封装在模块里面。

对应在java 9demo 模块的src 下创建module-info.java文件:

/**
*@author songhongkang
*@create 2019 下午 11:51
*/
module java9demo {
requires java9test;
}
requires:指明对其它模块的依赖。

五、Java的REPL工具: jShell命令
 产生背景
像Python 和 Scala 之类的语言早就有交互式编程环境 REPL (read - evaluate - print -
loop)了,以交互式的方式对语句和表达式进行求值。开发者只需要输入一些代码,就可以在编译前获得对程序的反馈。而之前的Java版本要想执行代码,必须创建文件、声明类、提供测试方法方可实现。
 设计理念:即写即得、快速运行
 实现目标:
1)Java 9 中终于拥有了 REPL工具:jShell。让Java可以像脚本语言一样运行,从控制台启动jShell,利用jShell在没有创建类的情况下直接声明变量,计算表达式,执行语句。即开发时可以在命令行里直接运行Java的代码,而无需创建Java文件,无需跟人解释”public static void main(String[] args)”这句废话。
2)jShell也可以从文件中加载语句或者将语句保存到文件中。
3)jShell也可以是tab键进行自动补全和自动添加分号。
调出jShell

在这里插入图片描述

获取帮助

在这里插入图片描述

基本使用

在这里插入图片描述

导入指定的包

在这里插入图片描述

默认已经导入如下的所有包:(包含java.lang包)

在这里插入图片描述
Tips:在 JShell 环境下,语句末尾的“;” 是可
选的。但推荐还是最好加上。提高代码可读
性。

只需按下 Tab 键,就能自动补全代码

在这里插入图片描述

列出当前 session 里所有有效的代码片段

在这里插入图片描述

查看当前 session 下所有创建过的变量

在这里插入图片描述

查看当前 session 下所有创建过的方法

在这里插入图片描述
Tips:我们还可以重新定义相同方法名和参
数列表的方法,即为对现有方法的修改(或
覆盖)。

使用外部代码编辑器来编写 Java 代码

在这里插入图片描述

使用/open命令调用:

在这里插入图片描述

没有受检异常(编译时异常)

在这里插入图片描述
说明:本来应该强迫我们捕获一个IOException,但却没有出现。因为jShell在后台为我们隐藏了。

退出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 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 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存储结构变更
Motivation
The current implementation of the String class stores characters in a char array, using two bytes (sixteen bits) for each character. Data gathered from many different applications indicates that strings are a major component of heap usage and, moreover, that most String objects contain only Latin-1 characters. Such characters require only one byte of storage, hence half of the space in the internal char arrays of such String objects is going unused.
Description
We propose to change the internal representation of the String class from a
UTF-16 char array to a byte array plus an encoding-flag field. The new String class will store characters encoded either as ISO-8859-1/Latin-1 (one byte per character), or as UTF-16 (two bytes per character), based upon the contents of the string. The encoding flag will indicate which encoding is used.
结论:String 再也不用 char[] 来存储啦,改成了 byte[] 加上编码标记,节约了一些空间。

public final class String
implements java.io.Serializable, Comparable, CharSequence {
@Stable
private final byte[] value;
}

那StringBuffer 和 StringBuilder 是否仍无动于衷呢?

String-related classes such as AbstractStringBuilder, StringBuilder,
and StringBuffer will be updated to use the same representation, as will the HotSpot VM‘s intrinsic(固有的、内置的) string operations.

十、集合工厂方法:快速创建只读集合
要创建一个只读、不可改变的集合,必须构造和分配它,然后添加元素,最后包装成一个不可修改的集合。

List namesList = new ArrayList <>();
namesList.add(“Joe”);
namesList.add(“Bob”);
namesList.add(“Bill”);
namesList = Collections.unmodifiableList(namesList);
System.out.println(namesList);
缺点:我们一下写了五行。即:它不能表达为单个表达式。

List list = Collections.unmodifiableList(Arrays.asList(“a”, “b”, “c”));
Set 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因此引入了方便的方法,这使得类似的事情更容易表达。
在这里插入图片描述
List firsnamesList = List.of(“Joe”,”Bob”,”Bill”);
调用集合中静态方法of(),可以将不同数量的参数传输到此工厂方法中。此功能可用于Set和List,也可用于Map的类似形式。此时得到的集合,是不可变的:在创建后,继续添加元素到这些集合会导致“UnsupportedOperationException” 。
由于Java 8中接口方法的实现,可以直接在List,Set和Map的接口内定义这些方法,便于调用。

List<String> list = List.of(“a”, “b”, “c”);
Set<String> set = Set.of(“a”, “b”, “c”);
Map<String, Integer> map1 = Map.of(“Tom”, 12, “Jerry”, 21, “Lilei”, 33,
“HanMeimei”, 18);
Map<String, Integer> map2 = Map.ofEntries(Map.entry(“Tom”, 89),
Map.entry(“Jim”, 78), Map.entry(“Tim”, 98));

十一、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
 Java 的 Steam API 是java标准库最好的改进之一,让开发者能够快速运算,从而能够有效的利用数据并行计算。Java 8 提供的 Steam 能够利用多核架构实现声明式的数据处理。
 在 Java 9 中,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的方法
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 代码.

在这里插入图片描述

17-2 Java 10 新特性

一、Java 10 新特性
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/
二、JDK10的12个JEP
286: Local-Variable Type Inference 局部变量类型推断
296: Consolidate the JDK Forest into a Single Repository JDK库的合并
304: Garbage-Collector Interface 统一的垃圾回收接口
307: Parallel Full GC for G1 为G1提供并行的Full GC
310: Application Class-Data Sharing 应用程序类数据(AppCDS)共享
312: Thread-Local Handshakes ThreadLocal握手交互
313: Remove the Native-Header Generation Tool (javah) 移除JDK中附带的javah工具
314: Additional Unicode Language-Tag Extensions 使用附加的Unicode语言标记扩展
316: Heap Allocation on Alternative Memory Devices 能将堆内存占用分配给用户指定
的备用内存设备
317: Experimental Java-Based JIT Compiler 使用基于Java的JIT编译器
319: Root Certificates 根证书
322: Time-Based Release Versioning 基于时间的发布版本
三、局部变量类型推断
 产生背景
开发者经常抱怨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()));

尽管 IDE可以帮我们自动完成这些代码,但当变量总是跳来跳去的时候,可读性还是会受到影响,因为变量类型的名称由各种不同长度的字符组成。而且,有时候开发人员会尽力避免声明中间变量,因为太多的类型声明只会分散注意力,不会带来额外的好处。

适用于以下情况:

//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);
}

说明:以上内容整理自尚硅谷B站Java视频>>尚硅谷B站Java视频

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值