一、JDK9新特性
1. 概述
JDK9新特性主要包括:
- 模块化系统
- JShell
- 只读集合工厂方法
- 接口的私有方法
- String存储结构改变
- try...catch升级
- 平台日志API和服务
- 垃圾回收器
2. 模块化系统
没有使用模块化时存在的问题:
导入依赖时,需要加载全部的包,影响系统性能。
Java 运行环境的膨胀和臃肿。每次JVM启动的时候,至少会有30~60MB的内存加载,主要原因是JVM需要加载rt.jar,不管其中的类是否被classloader加载,第一步整个jar都会被JVM加载到内存当中去(而模块化可以根据模块的需要加载程序运行需要的class)
当代码库越来越大,创建复杂,盘根错节的“意大利面条式代码”的几率呈指数级的增长。不同版本的类库交叉依赖导致让人头疼的问题,这些都阻碍了 Java 开发和运行效率的提升。
很难真正地对代码进行封装, 而系统并没有对不同部分(也就是 JAR 文件)之间的依赖关系有个明确的概念。每一个公共类都可以被类路径之下任何其它的公共类所访问到,这样就会导致无意中使用了并不想被公开访问的 API。
本质上讲也就是说,用模块来管理各个package,通过声明某个package暴露,模块(module)的概念,其实就是package外再裹一层,不声明默认就是隐藏。因此,模块化使得代码组织上更安全,因为它可以指定哪些部分可以暴露,哪些部分隐藏。
使用模块化系统,可以按需导入对应的模块。
实现目标
-
模块化的主要目的在于减少内存的开销
-
只须必要模块,而非全部jdk模块,可简化各种类库和大型应用的开发和维护
-
改进 Java SE 平台,使其可以适应不同大小的计算设备
-
改进其安全性,可维护性,提高性能
使用
在src下创建module-info.java
导出:
module xxx{ exports 包名/模块; }
导入:
module xxx{ requires 包名/模块; }
3. JShell命令
像Python 和 Scala 之类的语言早就有交互式编程环境 REPL (read - evaluate - print - loop)了,以交互式的方式对语句和表达式进行求值。开发者只需要输入一些代码,就可以在编译前获得对程序的反馈。而之前的Java版本要想执行代码,必须创建文件、声明类、提供测试方法方可实现。
4. 接口的私有方法
public interface JDK9Demo4 { //接口默认都是共有静态常量 public static final int NUM = 10; //接口默认方法都是抽象方法 public abstract void method1(); //jdk8接口可以有静态方法 public static void method2(){ System.out.println("接口中的静态方法"); } //jdk8接口可以有默认方法 public default void method3(){ System.out.println("接口中的默认方法"); } //jdk9接口可以有私有方法 private void method4(){ System.out.println("接口中的私有方法"); } }
5. 钻石操作符升级
Comparator<Object> com = new Comparator<>() { @Override public int compare(Object o1, Object o2) { return 0; } };
在jdk8中 上面的代码会报错:<>必须写明类型,jdk9对<>做了升级,不写也不报错。
6. try...catch
在jdk8中,可以自动关闭资源,但必须在try子句中初始化。
jdk9可以在外部初始化,try子句写对象名,也可以自动关闭。
try(inputStream;outputStream){ }
7. String存储结构变更
不再使用char[]存储,改为byte[],节省空间。
同样的,StringBuffer 和 StringBuilder也做了存储结构的变更。
8. of() 创建只读集合
jdk9引入了of()方法,可以方便的创建只读集合
public class Demo5 { public static final List<String> list = List.of("type_weixin","type_zhifubao","type_yinhangka"); public static void main(String[] args) { //jdk8以前创建只读集合 List<String> list = new ArrayList<>(); list.add("张三"); list.add("李四"); list.add("王五"); Collection<String> list2 = Collections.unmodifiableCollection(list); // list2.add("赵六"); // System.out.println(list2); //jdk9创建只读集合 List<String> list3 = List.of("张三", "李四", "王五"); System.out.println(list3); Set<String> set1 = Set.of("AA", "BB", "CC"); System.out.println(set1); Map<String, String> map = Map.of("k1", "v1", "k2", "v2"); System.out.println(map); } }
9. InputStream增强
使用 transferTo 可以将输入流中的内容直接交给输出流输出
10. stream API增强
-
在 Java 9 中,Stream API 变得更好,Stream 接口中添加了 4 个新的方法:takeWhile, dropWhile, ofNullable,还有个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。
-
除了对 Stream 本身的扩展,Optional 和 Stream 之间的结合也得到了改进。现在可以通过 Optional 的新方法 stream() 将一个 Optional 对象转换为一个(可能是空的) Stream 对象。
10.1 takeWhile()
用于从 Stream 中获取一部分数据,接收一个 Predicate 来进行选择。在有序的Stream 中,takeWhile 返回从开头开始的尽量多的元素。
public static void main(String[] args) throws Exception { List<Integer> list = Arrays.asList(10,20,30,40,30,20,10); list.stream().takeWhile(t->t<40).forEach(System.out::println); List<Integer> list2 = Arrays.asList(1,2,3,4,5,6,7); list2.stream().takeWhile(t->t<7).forEach(System.out::println); }
10.2 dropWhile()
dropWhile 的行为与 takeWhile 相反,返回剩余的元素。
10.3 ofNullable()
Java 8 中 Stream 不能完全为null,否则会报空指针异常。
而 Java 9 中的 ofNullable 方法允许我们创建一个单元素 Stream,可以包含一个非空元素,也可以创建一个空Stream。
public static void main(String[] args) throws Exception { //允许通过 Stream<String> streams = Stream.of("AA","BB",null); System.out.println(streams.count()); //不允许通过 /*Stream<Object> stream2 = Stream.of(null); System.out.println(stream2.count());*/ //允许通过 Stream<Object> stream2 = Stream.ofNullable(null); System.out.println(stream2.count()); }
10.4 iterate() 重载
这个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。
public static void main(String[] args) throws Exception { //原始方式 Stream.iterate(1,i->i+1).limit(50).forEach(System.out::println); //增强方式 Stream.iterate(1,i->i<60,i->i+1).forEach(System.out::println); }
10.5 Optional类中stream()使用
public static void main(String[] args) throws Exception { List<String> list = new ArrayList<>(); list.add("张三"); list.add("李四"); list.add("王五"); list.add("赵六"); Optional<List<String>> optional = Optional.ofNullable(list); optional.stream().flatMap(x->x.stream()).limit(2).forEach(System.out::println); list.stream().limit(2).forEach(System.out::println); }
Optional接收一个集合对象,底层也是用集合容器进行存储,所以使用一次流进行遍历得到的是集合对象,
调用flatMap方法 能获取到集合中的元素
二、JDK10新特性
1. 局部变量类型推断
使用var声明变量,var进行类型推断
public class Demo1 { public static void main(String[] args) { method1(); } public static void method1(){ var i = 1; var list = new ArrayList<String>(); list.add("张三"); list.add("李四"); System.out.println(list); } }
var不是一个关键字。
var没有改变java是强语言的本质,只是进行类型的推断。
以下情况不能推断:
public static void method2(){ //由于值是null,类型无法推断 // var i = null; //方法引用无法使用var //var a = System.out::println; //lamdba无法推断var的类型,故不能用 /* Function<Integer,String> fun = (Integer a)->{ return a+""; };*/ /* var fun2 = (Integer a)->{ return a+""; };*/ //静态数组后面不加类型的时候推断不出来var的类型,故不能用 int[] arr = new int[]{1,2,3}; int[] arr2 = {1,2,3}; //var arr3 = {1,3,4}; }
2. 新增只读集合方法 copyOf()
public static void main(String[] args) throws Exception { //示例1 var list1 = List.of("AA","BB","CC"); var list2 = List.copyOf(list1); System.out.println(list1==list2);//true //示例2 var list3 = new ArrayList<String>(); list3.add("AA"); list3.add("BB"); List<String> list4 = List.copyOf(list3); System.out.println(list3==list4); //false }
copyOf 方 法 会 先 判 断 来 源 集 合 是 不 是AbstractImmutableList 类型的,如果是,就直接返回,如果不是,则调用 of 创建一个新的集合。
示例2因为用的 new 创建的集合,不属于不可变 AbstractImmutableList 类的子类,所以 copyOf 方法又创建了一个新的实例,所以为false。
注意:使用of和copyOf创建的集合为不可变集合,不能进行添加、删除、替换、排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。
三、JDK11新特性
1. 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位系统
2. Optional加强
3. 新增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的支持
public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder(URI.create("http://www.baidu.com")).build(); HttpResponse.BodyHandler<String> responseBodyHandler = HttpResponse.BodyHandlers.ofString(); HttpResponse<String> response = client.send(request, responseBodyHandler); String body = response.body(); System.out.println(body); }
四、JDK14新特性
在NullPointerException时,指明为null的变量
之前:
jdk14:
五、JDK15新特性
新增 text blocks 文本块,解决多行字符串换行问题
public static void main(String[] args) { //jdk15增加文本块 String str = """ hello world hahaha """; }
六、JDK16新特性
在Java16中正式发布Switch升级,其目的是为了解决switch语句的一些不规则性成为障碍
-
比如case标签之间的默认控制行为
-
case块中的默认范围
-
无意义的break语句。
public static void main(String[] args) { int level = new Random().nextInt(4); String strLevel; switch (level){ case 1 -> strLevel="优秀"; case 2 -> strLevel="良好"; default -> strLevel="一般"; } System.out.println(strLevel); }
还可以写成:
public static void main(String[] args) { int level = new Random().nextInt(4); String strLevel = switch (level){ case 1-> "优秀"; case 2-> "良好"; default -> "一般"; }; System.out.println(strLevel); }
根据月份判断季节:
public static void main(String[] args) { int level = new Random().nextInt(12); String jiJi = null; switch (level){ case 3,4,5 -> jiJi = "春天"; case 6,7,8 -> jiJi = "夏天"; case 9,10,11 -> jiJi = "秋天"; case 12,1,2 -> jiJi = "冬天"; }; System.out.println(jiJi); }
还有:
public static void main(String[] args) { int level = new Random().nextInt(4); String strLeave = switch (level){ case 1 -> { System.out.println("优秀"); yield "优秀"; } default -> "进步空间很大"; }; System.out.println(strLeave); }
虽然写法更简单了,但是编译后的代码还是原本的格式,只是做了翻译。