Java9/Java10/Java11的新特性
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("我是接口中的私有方法"); } }
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(); } }
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); }
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不是一个关键字 你不需要担心变量名或方法名会与 var发生冲突,因为 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); }
当然还有很多新特性,这里就不细说了
20 - 展望未来
1 随着云计算和 AI 等技术浪潮,当前的计算模式和场景正在发生翻天覆地的变 化,不仅对 Java 的发展速度提出了更高要求,也深刻影响着 Java 技术的发展 方向。传统的大型企业或互联网应用,正在被云端、容器化应用、模块化的微 服务甚至是函数(FaaS, Function-as-a-Service)所替代。
2 Java虽然标榜面向对象编程,却毫不顾忌的加入面向接口编程思想,又扯出匿 名对象之概念,每增加一个新的东西,对Java的根本所在的面向对象思想的一 次冲击。反观Python,抓住面向对象的本质,又能在函数编程思想方面游刃有 余。Java对标C/C++,以抛掉内存管理为卖点,却又陷入了JVM优化的噩梦。选 择比努力更重要,选择Java的人更需要对它有更清晰的认识。
3 Java 需要在新的计算场景下,改进开发效率。这话说的有点笼统,我谈一些自 己的体会,Java 代码虽然进行了一些类型推断等改进,更易用的集合 API 等, 但仍然给开发者留下了过于刻板、形式主义的印象,这是一个长期的改进方向。