1 - JDK 9 的发布
1 经过4次跳票,历经曲折的Java 9 终于终于在2017年9月21日发布。
2 从Java 9 这个版本开始,Java 的计划发布周期是 6 个月,下一个 Java 的主版 本将于 2018 年 3 月发布,命名为 Java 18.3,紧接着再过六个月将发布 Java 18.9。
3 这意味着Java的更新从传统的以特性驱动的发布周期,转变为以时间驱动的 (6 个月为周期)发布模式,并逐步的将 Oracle JDK 原商业特性进行开源。
4 针对企业客户的需求,Oracle 将以三年为周期发布长期支持版本(long term support)。
5 Java 9 提供了超过150项新功能特性,包括备受期待的模块化系统、可交互 的 REPL 工具:jshell,JDK 编译工具,Java 公共 API 和私有代码,以及安 全增强、扩展提升、性能管理改善等。可以说Java 9是一个庞大的系统工程, 完全做了一个整体改变。
2 - JDK 9 主要新特性一览
1 模块化系统(重点)
2 jShell命令(重点)
3 多版本兼容jar包
4 接口的私有方法
5 钻石操作符的使用升级
6 语法改进:try语句
7 String存储结构变更
8 便利的集合特性:of()
9 增强的Stream API
10 全新的HTTP客户端API
11 Deprecated的相关API
12 javadoc的HTML 5支持
13 Javascript引擎升级:Nashorn
14 java的动态编译器
✔ 官方提供的新特性列表: https://docs.oracle.com/javase/9/whatsnew/toc.htm#JSNEW-GUIDC23AFD78-C777-460B-8ACE-58BE5EA681F6
✔ 或参考 Open JDK http://openjdk.java.net/projects/jdk9/
✔ 在线Oracle JDK 9 Documentation https://docs.oracle.com/javase/9/
3 - JDK9模块化系统: Jigsaw → Modularity
✔ 谈到 Java 9 大家往往第一个想到的就是 Jigsaw 项目。众所周知,Java 已经 发展超过 20 年(95 年最初发布),Java 和相关生态在不断丰富的同时也越 来越暴露出一些问题:
1 Java 运行环境的膨胀和臃肿。每次JVM启动的时候,至少会有30~60MB的内存 加载,主要原因是JVM需要加载rt.jar,不管其中的类是否被classloader加载,第 一步整个jar都会被JVM加载到内存当中去(而模块化可以根据模块的需要加载程 序运行需要的class)
2 当代码库越来越大,创建复杂,盘根错节的“意大利面条式代码”的几率呈指数级的 增长。不同版本的类库交叉依赖导致让人头疼的问题,这些都阻碍了 Java 开发和 运行效率的提升。
3 很难真正地对代码进行封装, 而系统并没有对不同部分(也就是 JAR 文件)之间 的依赖关系有个明确的概念。每一个公共类都可以被类路径之下任何其它的公共 类所访问到,这样就会导致无意中使用了并不想被公开访问的 API。
✔ 本质上讲也就是说,用模块来管理各个package,通过声明某个package 暴露,模块(module)的概念,其实就是package外再裹一层,不声明默 认就是隐藏。因此,模块化使得代码组织上更安全,因为它可以指定哪 些部分可以暴露,哪些部分隐藏。
✔ 实现目标
1 模块化的主要目的在于减少内存的开销
2 只须必要模块,而非全部jdk模块,可简化各种类库和大型应用的开 发和维护
3 改进 Java SE 平台,使其可以适应不同大小的计算设备
4 改进其安全性,可维护性,提高性能
✔ 模块将由通常的类和新的模块声明文件(module-info.java)组成。
该文件是位于 java代码结构的顶层,该模块描述符明确地定义了我们的模块需要什么依赖关系, 以及哪些模块被外部使用。在exports子句中未提及的所有包默认情况下将封装在 模块中,不能在外部使用
✔ 实现步骤
① 如果我们想要在模块Day13下调用模块Java9Test下的结构,就需要在模块 Day13 和 模块 Java9Test下的src文件下有以下操作
② 在Day13 的module-info.java中声明:
module Day13 {
requires Java9test;
requires junit;
//requires 指明对其它模块的依赖。
}
③在Java9Test 的module-info.java中声明:
module Java9test {
exports com.lzh.bean;
// exports 控制着哪些包可以被其它模块访问到。所有不被导出的包默认 都被封装在模块里面。(通俗的讲就是对外暴露其结构)
}
4 - JDK9的REPL工具: jShell命令
1 产生背景 像Python 和 Scala 之类的语言早就有交互式编程环境 REPL (read - evaluate - print loop)了,以交互式的方式对语句和表达式进行求值。开发者只需要输入一些代码, 就可以在编译前获得对程序的反馈。而之前的Java版本要想执行代码,必须创建文 件、声明类、提供测试方法方可实现。
2 设计理念:即写即得、快速运行
3 实现目标
4 Java 9 中终于拥有了 REPL工具:jShell。让Java可以像脚本语言一样运行,从 控制台启动jShell,利用jShell在没有创建类的情况下直接声明变量,计算表达式, 执行语句。即开发时可以在命令行里直接运行Java的代码,而无需创建Java文 件,无需跟人解释”public static void main(String[] args)”这句废话。
① jShell也可以从文件中加载语句或者将语句保存到文件中。
② jShell也可以是tab键进行自动补全和自动添加分号。
5 jShell
调出 jShell
获取帮助 /help
基本使用(可自由写Java代码)
Tips:在 JShell 环境下,语句末尾的“;” 是可 选的。但推荐还是最好加上。提高代码可读 性。
Tips:我们还可以重新定义相同方法名和参 数列表的方法,即为对现有方法的修改(或 覆盖)。
这里还有许多用法,就不介绍了
5 - JDK9语法改进:接口的私有方法
1 Java 8中规定接口中的方法除了抽象方法之外,还可以定义静态方法 和默认的方法。一定程度上,扩展了接口的功能,此时的接口更像是 一个抽象类。
2 在Java 9中,接口更加的灵活和强大,连方法的访问权限修饰符都可 以声明为private的了,此时方法将不会成为你对外暴露的API的一部分。
package com.lzh.java;
public interface MyInterface {
//如下的三个方法的权限修饰符都是public
void methodAbstract();
static void methodStatic(){
System.out.println("我是接口中的静态方法");
}
default void methodDefault(){
System.out.println("我是接口中的默认方法");
methodPrivate();
}
//jdk 9中允许接口中定义私有的方法
private void methodPrivate(){
System.out.println("我是接口中的私有方法");
}
}
MyInterface.java
package com.lzh.java;
public class MyInterfaceImpl implements MyInterface {
@Override
public void methodAbstract() {
}
// @Override
public void methodDefault() {
System.out.println("实现类重写了接口中的默认方法");
}
public static void main(String[] args) {
//接口中的静态方法只能由接口自己调用
MyInterface.methodStatic();
//接口的实现类不能调用接口的静态方法
// MyInterfaceImpl.methodStatic();
MyInterfaceImpl impl = new MyInterfaceImpl();
impl.methodDefault();
//接口的私有方法,不能在接口外部调用
// impl.methodPrivate();
}
}
MyInterfaceImpl.java
6 - JDK9语法改进:钻石操作符使用升级
1 我们将能够与匿名实现类共同使用钻石操作符(diamond operator)在Java 8 中如下的操作是会报错的:
Comparator<Object> comparator = new Comparator<>() {
@Override
public int compare(Object o1, Object o2) {
return 0;
}
};
// 编译报错信息:Cannot use “<>” with anonymous inner classes
2 Java 9中如下操作可以正常执行通过:
//java9特性五:钻石操作符的升级
@Test
public void test2() {
//钻石操作符与匿名内部类在java 8中不能共存。在java9可以。
Comparator<Object> com = new Comparator<>() {
@Override
public int compare(Object o1, Object o2) {
return 0;
}
};
//jdk7中的新特性:类型推断
ArrayList<String> list = new ArrayList<>();
}
7 - JDK9语法改进:try语句
1 Java 8 中,可以实现资源的自动关闭,但是要求执行后必须关闭的所有资源必 须在try子句中初始化,否则编译不通过。
try(InputStreamReader reader = new InputStreamReader(System.in)){
//读取数据细节省略
}catch (IOException e){
e.printStackTrace();
}
2 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 特性六:try操作的升级
public static void main(String[] args) {
//java 8之前的资源关闭的操作
// InputStreamReader reader = null;
// try {
// reader = new InputStreamReader(System.in);
// char[] cbuf = new char[20];
// int len;
// if((len = reader.read(cbuf) )!= -1){
// String str = new String(cbuf,0,len);
// System.out.println(str);
// }
// } catch (IOException e) {
// e.printStackTrace();
// } finally {
// if(reader != null){
// try {
// reader.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
//
// }
// }
//java 8中资源关闭操作: Java 8 中,可以实现资源的自动关闭
//要求自动关闭的资源的实例化必须放在try的一对小括号中
// try(InputStreamReader reader = new InputStreamReader(System.in)){
// char[] cbuf = new char[20];
// int len;
// if((len = reader.read(cbuf) )!= -1){
// String str = new String(cbuf,0,len);
// System.out.println(str);
// }
// } catch (IOException e) {
// e.printStackTrace();
// }
//java9中资源关闭操作:需要自动关闭的资源的实例化可以放在try的一对小括号外。
//此时的资源属性是常量,声明为final的,不可修改
InputStreamReader reader = new InputStreamReader(System.in);
try (reader) {
char[] cbuf = new char[20];
int len;
if((len = reader.read(cbuf) )!= -1){
String str = new String(cbuf,0,len);
System.out.println(str);
}
// reader = null;
} catch (IOException e) {
e.printStackTrace();
}
}
代码举例
8 - JDK9 String存储结构变更
1 在以前的版本中,String一直是用char[]存储,但是在Java9中,String 再也不用 char[] 来存储啦,改成了 byte[] 加上编码标记,节约 了一些空间
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
@Stable
private final byte[] value;
}
2 那StringBuffer 和 StringBuilder 是否仍无动于衷呢?
AbstractStringBuilder StringBuilder, StringBuffer将更新使用相同的表示,将HotSpot VM的内在(固有的,内置的)字符串操作
9 - JDK9 集合工厂方法:快速创建只读集合
1 要创建一个只读、不可改变的集合,必须构造和分配它,然后添加元素,最后 包装成一个不可修改的集合。
//java8中的写法:
@Test
public void test1() {
List<String> namesList = new ArrayList<>();
namesList.add("Joe");
namesList.add("Bob");
namesList.add("Bill");
//返回的namesList是一个只读的集合
namesList = Collections.unmodifiableList(namesList);
namesList.add("Tom");
System.out.println(namesList);
}
// 缺点:我们一下写了五行。即:它不能表达为单个表达式。
2 Java9 快速创建 只读集合 代码举例
@Test
public void test2() {
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));
}
@Test
public void test3() {
//此时得到的集合list也是一个只读集合。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
//报异常
list.add(6);
}
//java9新特性八:集合工厂方法:创建只读集合
@Test
public void test4() {
List<Integer> list1 = List.of(1, 2, 3, 4, 5);
//不能添加
// list1.add(6);
System.out.println(list1);
Set<Integer> set1 = Set.of(23, 3, 54, 65, 43, 76, 87, 34, 46);
//不能添加
// set1.add(4);
System.out.println(set1);
Map<String, Integer> map1 = Map.of("Tom", 23, "Jerry", 54, "HanMeimei", 12);
//不能添加
//map1.put("Lilei",34);
System.out.println(map1);
Map<String, Integer> map2 = Map.ofEntries(Map.entry("Tom", 34), Map.entry("Jerry", 21));
// map2.put("Lilei",34);
System.out.println(map2);
}
View Code
10 - JDK9 InputStream的新方法:tranferTo()
1 InputStream 终于有了一个非常有用的方法:transferTo,可以用来将数据直接 传输到 OutputStream,这是在处理原始数据流时非常常见的一种用法,如下示例
//java9新特性九:InputStream的新方法:tranferTo()
@Test
public void test5() {
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();
}
}
11 - JDK9 Stream API的加强
1 Java 的 Steam API 是java标准库最好的改进之一,让开发者能够快速运算, 从而能够有效的利用数据并行计算。Java 8 提供的 Steam 能够利用多核架构 实现声明式的数据处理。
2 在 Java 9 中,Stream API 变得更好,Stream 接口中添加了 4 个新的方法: takeWhile, dropWhile, ofNullable,还有个 iterate 方法的新重载方法,可以 让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。
3 除了对 Stream 本身的扩展,Optional 和 Stream 之间的结合也得到了改进。 现在可以通过 Optional 的新方法 stream() 将一个 Optional 对象转换为一个 (可能是空的) Stream 对象。
4 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);
//takeWhile 返回从开头开始的按照指定规则尽量多的元素
System.out.println();
list=Arrays.asList(1,2,3,4,5,6,7,8);
list.stream().takeWhile(x->x< 5).forEach(System.out::println);
5 dropWhile()的使用
dropWhile 的行为与 takeWhile 相反,返回剩余的元素。
List<Integer> list = Arrays.asList(23, 43, 45, 55, 61, 54, 32, 2, 45, 89, 7);
//dropWhile():与 takeWhile 相反,返回剩余的元素。
list.stream().dropWhile(x -> x < 60).forEach(System.out::println);
6 ofNullable()的使用
Java 8 中 Stream 不能完全为null,否则会报空指针异常。而 Java 9 中的 ofNullable 方 法允许我们创建一个单元素 Stream,可以包含一个非空元素,也可以创建一个空 Stream。
@Test
public void test2(){
//of()参数中的多个元素,可以包含null值
Stream<Integer> stream1 = Stream.of(1, 2, 3,null);
stream1.forEach(System.out::println);
//of()参数不能存储单个null值。否则,报异常
// Stream<Object> stream2 = Stream.of(null);
// stream2.forEach(System.out::println);
Integer i = 10;
i = null;
//ofNullable():形参变量是可以为null值的单个元素
Stream<Integer> stream3 = Stream.ofNullable(i);
long count = stream3.count();
System.out.println(count);
}
7 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);
8 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);
12 - JDK9 Javascript引擎升级:Nashorn
1 Nashorn 项目在 JDK 9 中得到改进,它为 Java 提供轻量级的 Javascript 运行时。 Nashorn 项目跟随 Netscape 的 Rhino 项目,目的是为了在 Java 中实现一个高 性能但轻量级的 Javascript 运行时。Nashorn 项目使得 Java 应用能够嵌入 Javascript。它在 JDK 8 中为 Java 提供一个 Javascript 引擎。
2 JDK 9 包含一个用来解析 Nashorn 的 ECMAScript 语法树的 API。这个 API 使得 IDE 和服务端框架不需要依赖 Nashorn 项目的内部实现类,就能够分析 ECMAScript 代码。
13 - JDK 10 新特性之 局部变量类型推断
1 2018年3月21日,Oracle官方宣布Java10正式发布。
2 需要注意的是 Java 9 和 Java 10 都不是 LTS (Long-Term-Support) 版本。和 过去的 Java 大版本升级不同,这两个只有半年左右的开发和维护期。而未 来的 Java 11,也就是 18.9 LTS,才是 Java 8 之后第一个 LTS 版本。
3 JDK10一共定义了109个新特性,其中包含12个JEP(对于程序员来讲,真 正的新特性其实就一个[局部变量类型推断]),还有一些新API和JVM规范以及JAVA语言规范上 的改动。
4 JDK10的12个JEP(JDK Enhancement Proposal特性加强提议)参阅官方 文档:http://openjdk.java.net/projects/jdk/10/
局部变量类型推断:
1 产生背景
开发者经常抱怨Java中引用代码的程度。局部变量的显示类型声明,常常被认为 是不必须的,给一个好听的名字经常可以很清楚的表达出下面应该怎样继续。
2 好处
减少了啰嗦和形式的代码,避免了信息冗余,而且对齐了变量名,更容易阅读!
3 举例如下
✔ 场景一:类实例化时
作为 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()));
4 尽管 IDE可以帮我们自动完成这些代码,但当变量总是跳来跳去的时候,可读 性还是会受到影响,因为变量类型的名称由各种不同长度的字符组成。而且, 有时候开发人员会尽力避免声明中间变量,因为太多的类型声明只会分散注意 力,不会带来额外的好处
类型推断详情,如下代码
/*
java10新特性一:局部变量的类型推断
*/
@Test
public void test1() {
//1.声明变量时,根据所附的值,推断变量的类型
var num = 10;
var list = new ArrayList<Integer>();
list.add(123);
//2.遍历操作
for (var i : list) {
System.out.println(i);
System.out.println(i.getClass());
}
//3.普通的遍历操作
for (var i = 0; i < 100; i++) {
System.out.println(i);
}
}
@Test
public void test2() {
//1.局部变量不赋值,就不能实现类型推断
// var num ;
//2.lambda表示式中,左边的函数式接口不能声明为var
// Supplier<Double> sup = () -> Math.random();
// var sup = () -> Math.random();
//3.方法引用中,左边的函数式接口不能声明为var
// Consumer<String> con = System.out::println;
// var con = System.out::println;
//4.数组的静态初始化中,注意如下的情况也不可以
int[] arr = {1, 2, 3, 4};
// var arr = {1,2,3,4};
}
@Test
public void test3() {
// 情况1:没有初始化的局部变量声明
// var s = null;
// 情况6:catch块
// try{
//
// }catch(var e){
// e.printStackTrace();
// }
}
//情况2:方法的返回类型
// public var method1(){
//
//// return 0;
// }
// 情况3:方法的参数类型
// public void method2(var num){
//
// }
//情况4:构造器的参数类型
// public Java10Test(var i){
//
// }
//情况5:属性
// var num;
@Test
public void test4() {
try {
var url = new URL("http://www.atguigu.com");
var connection = url.openConnection();
var reader = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
适用情况与不适用情况代码举例
5 总结
1 适用于以下情况
//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);
}
2 不适用以下情况
// 1 初始值为null
var num = null;
// 2 Lambda表达式
var r = () -> Math.random();
// 3 方法引用
var str = System.out :: println;
// 4 为数组静态初始化
var array = {1,2,3,4,5,6};
// 可自行测试
3 不适用以下结构
/*
情况1:没有初始化的局部变量声明
情况2:方法的返回类型
情况3:方法的参数类型
情况4:构造器的参数类型
情况5:属性
情况6:catch块
*/
最后注意点
1 在处理 var时,编译器先是查看表达式右边部分,并根据右边变量值的类型进行推断(var 工作原理),作为左边变量的类型,然后将该类型写入字节码当中(字节码文件中数据类型还是会显示出来)。
2 var不是一个关键字
3 这不是JavaScript 首先我要说明的是,var并不会改变Java是一门静态类型语言的事实。编译器负责推 断出类型,并把结果写入字节码文件,就好像是开发人员自己敲入类型一样。 下面是使用 IntelliJ(实际上是 Fernflower的反编译器)反编译器反编译出的代码
14 - JDK 10 新特性之 集合新增创建不可变集合的方法
1 自 Java 9 开始,Jdk 里面为集合(List / Set / Map)都添加了 of (jdk9新增)和 copyOf (jdk10新增)方法,它们两个都用来创建不可变的集合,来看下它们的 使用和区别如下:
//java10的新特性二:集合中新增的copyOf(),用于创建一个只读的集合
@Test
public void test5(){
//示例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>();
list2.add("aaa");
var copy2 = List.copyOf(list2);
System.out.println(list2 == copy2); // false
//示例1和2代码基本一致,为什么一个为true,一个为false?
//结论:copyOf(Xxx coll):如果参数coll本身就是一个只读集合,则copyOf()返回值即为当前的coll
//如果参数coll不是一个只读集合,则copyOf()返回一个新的集合,这个集合是只读的。
}
2 从 源 码 分 析 , 可以看出 copyOf 方 法 会 先 判 断 来 源 集 合 是 不 是 AbstractImmutableList 类型的,如果是,就直接返回,如果不是,则调用 of 创 建一个新的集合。
3 示例2因为用的 new 创建的集合,不属于不可变 AbstractImmutableList 类的子类, 所以 copyOf 方法又创建了一个新的实例,所以为false。
4 注意:使用of和copyOf创建的集合为不可变集合,不能进行添加、删除、替换、 排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。 上面演示了 List 的 of 和 copyOf 方法,Set 和 Map 接口都有
15 - JDK11 新特性
1 北京时间 2018年9 月 26 日, Oracle 官方宣布 Java 11 正式发 布。这是 Java 大版本周期变化 后的第一个长期支持版本,非 常值得关注。从官网即可下载, 最新发布的 Java11 将带来 ZGC、 Http Client 等重要特性,一共包 含 17 个 JEP(JDK Enhancement Proposals,JDK 增强提案)。
2 JDK 11 将是一个 企业不可忽视的版本。从时间节点来看,JDK 11 的发布正 好处在 JDK 8 免费更新到期的前夕,同时 JDK 9、10 也陆续成为“历史版 本”
3 对于企业来说,选择 11 将意味着长期的、可靠的、可预测的技术路线图。 其中免费的OpenJDK11 确定将得到 OpenJDK 社区的长期支持, LTS 版本将 是可以放心选择的版本。
4 从 JVM GC 的角度,JDK11 引入了两种新的 GC,其中包括也许是划时代意义 的 ZGC,虽然其目前还是实验特性,但是从能力上来看,这是 JDK 的一个巨 大突破,为特定生产环境的苛刻需求提供了一个可能的选择。例如,对部 分企业核心存储等产品,如果能够保证不超过 10ms 的 GC 暂停,可靠性会 上一个大的台阶,这是过去我们进行 GC 调优几乎做不到的,是能与不能的 问题。
5 JDK 11 是一个长期支持版本(LTS, Long-Term-Support)
16 - JDK11 新增了一系列字符串处理方法
//java 11新特性一:String中新增的方法
@Test
public void test1(){
// isBlank():判断字符串是否为空白
System.out.println(" \t \t \n ".isBlank());
// strip():去除首尾空白
System.out.println("-----" + " \t abc \t \n ".strip() + "-------");
System.out.println("-----" + " \t abc \t \n ".trim() + "-------");
// stripTrailing():去除尾部空格
System.out.println("-----" + " \t abc \t \n ".stripTrailing() + "-------");
// stripLeading():去除首部空格
System.out.println("-----" + " \t abc \t \n ".stripLeading() + "-------");
// repeat(int count):复制字符串
String str1 = "abc";
String str2 = str1.repeat(5);
System.out.println(str2);
// lines().count():行数统计
String str3 = "abc\ndef\ng";
System.out.println(str3.lines().count());
}
代码举例
17 - JDK11 Optional 加强
Optional 也增加了几个非常酷的方法,现在可以很方便的将一个 Optional 转换 成一个 Stream, 或者当一个空 Optional 时给它一个替代的
//java11新特性二:Optional新增的方法
@Test
public void test2(){
var op = Optional.empty();
System.out.println(op.isPresent());//判断内部的value是否存在
System.out.println(op.isEmpty());//判断内部的value是否为空
op = Optional.of("abc");
//orElseThrow():value非空,返回value;否则抛异常NoSuchElementException
var obj = op.orElseThrow();
System.out.println(obj);
Optional<String> op1 = Optional.of("hello");
// op = Optional.empty();
//or:value非空,返回对应的Optional;value为空,返回形参封装的Optional
Optional<Object> op2 = op.or(() -> op1);
System.out.println(op2);//
}
代码举例
18 - JDK11 局部变量类型推断升级
在var上添加注解的语法格式,在jdk10中是不能实现的。在JDK11中加入了这样 的语法
//java11新特性三:局部变量类型推断的升级
@Test
public void test3(){
//错误的形式: 必须要有类型, 可以加上var
// Consumer<String> con1 = (@Deprecated t) -> System.out.println(t.toUpperCase());
// 正确的形式:
// 使用var的好处是在使用lambda表达式时给参数加上注解。
Consumer<String> con2 = (@Deprecated var t) -> System.out.println(t.toUpperCase());
}
19 - JDK11 HttpClient替换原有的HttpURLConnection
//java11新特性四:HttpClient替换原有的HttpURLConnection。
@Test
public void test4(){
try {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/")).build();
HttpResponse.BodyHandler<String> responseBodyHandler = HttpResponse.BodyHandlers.ofString();
HttpResponse<String> response = client.send(request, responseBodyHandler);
String body = response.body();
System.out.println(body);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Test
public void test5(){
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/")).build();
HttpResponse.BodyHandler<String> responseBodyHandler = HttpResponse.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);
}
全新的HTTP 客户端API
当然还有很多新特性,这里就不细说了
20 - 展望未来
1 随着云计算和 AI 等技术浪潮,当前的计算模式和场景正在发生翻天覆地的变 化,不仅对 Java 的发展速度提出了更高要求,也深刻影响着 Java 技术的发展 方向。传统的大型企业或互联网应用,正在被云端、容器化应用、模块化的微 服务甚至是函数(FaaS, Function-as-a-Service)所替代。
2 Java虽然标榜面向对象编程,却毫不顾忌的加入面向接口编程思想,又扯出匿 名对象之概念,每增加一个新的东西,对Java的根本所在的面向对象思想的一 次冲击。反观Python,抓住面向对象的本质,又能在函数编程思想方面游刃有 余。Java对标C/C++,以抛掉内存管理为卖点,却又陷入了JVM优化的噩梦。选 择比努力更重要,选择Java的人更需要对它有更清晰的认识。
3 Java 需要在新的计算场景下,改进开发效率。这话说的有点笼统,我谈一些自 己的体会,Java 代码虽然进行了一些类型推断等改进,更易用的集合 API 等, 但仍然给开发者留下了过于刻板、形式主义的印象,这是一个长期的改进方向。
学习没有捷径,需要日积月累的积淀及对技术的热爱。