一、JDK9 新特性
1.模块化系统
模块化系统是Java9中新增最大的特性,本质上就是用模块来管理各个package。
模块化系统主要是解决JVM需要加载的rt.jar越来越大的问题,减少内存的开销。并且模块化使得代码组织上更安全,因为它可以指定哪些部分可以暴露,哪些部分隐藏。
模块化系统的实现过程:通过在src目录下创建module-info.java文件,在其中requires(导入)需要的包,并把自己exports(暴露/导出)出去,不暴露默认是隐藏。
2.JShell命令
Jshell命令是一种交互式的编程方式,以交互式的方式对语句和表达式进行求值。
Jshell命令的设计理念是即写即得,开发者只需要输入一些代码,就可以在编译前获得对程序的反馈。而之前的Java版本要想执行代码,必须创建文件、声明类、提供测试方法方可实现。
3.接口私有方法
public interface JDK9Demo4 {
//接口默认都是公有静态常量
/*public static final*/ int NUM = 10;
//接口默认方法都是抽象方法
public abstract void method1();
//jdk8接口可以有静态方法
public static void method2(){
System.out.println("接口中的静态方法");
}
//jdk8接口可以有默认方法,默认方法不能用private修饰
public default void method3(){
System.out.println("接口中的默认方法");
}
//jdk9接口可以有私有方法
private void method4(){
System.out.println("接口中的私有方法");
}
}
在jdk8中,接口中默认都是公有静态常量;
接口中的默认方法都是抽象方法;
接口中可以有静态方法;
接口中可以有默认方法。
在jdk9中,接口可以有私有方法,此时方法将不会成为你对外暴露的API的一部分。
default方法不能用private修饰。
4.钻石操作符
在jdk8中,如下代码是报错的
Comparator<Object> com = new Comparator<>() {
@Override
public int compare(Object o1, Object o2) {
return 0;
}
};
<>必须写类型。
而在jdk9中,上述代码就不报错,这是对<>钻石运算符的一个升级。
5.try 语句
Java 8 中,可以实现资源的自动关闭,但是要求执行后必须关闭的所有资源必须在try子句中初始化,否则编译不通过。
try (InputStreamReader inputStreamReader = new InputStreamReader(System.in)) {
} catch (IOException e) {
e.printStackTrace();
}
这种方式使我们想要在其他地方使用inputStreamReader变得困难,Java 9 中,用资源语句编写try将更容易,我们可以在try子句中使用已经初始化过的资源,此时的资源是final的
InputStreamReader reader = new InputStreamReader(System.in);
OutputStreamWriter writer = new OutputStreamWriter(System.out);
try (reader; writer) {
} catch (IOException e) {
e.printStackTrace();
}
6.String 存储结构变更
String类的当前实现将字符存储在char中数组,每个字符使用两个字节(16位)。数据收集自的主要组成部分;而且,大多数String对象只包含Latin-1字符。这样的字符只需要一个字节的存储空间,有将近一半的内容被浪费了。
所以String类改成了 byte[] 加上编码标记,节约了一些空间。
StringBuffer 和 StringBuilder也更新为使用同样方式存储。
7.集合特性of()
List.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);
}
}
8.InputStream增强
InputStream多了一个transferTo方法,可以将数据直接传输到OutputStream里
FileInputStream fileInputStream = new FileInputStream("D:\\a.txt");
FileOutputStream fileOutputStream = new FileOutputStream("D:\\b.txt");
try (fileInputStream; fileOutputStream) {
fileInputStream.transferTo(fileOutputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
9.增强的 的 Stream API
在 Java 9 中,Stream 接口中添加了 4 个新的方法:takeWhile, dropWhile, ofNullable,还有个 iterate 方法的新重载方法,可以让你提供一个 Predicate (断言)来指定什么时候结束迭代。
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);
}
2.dropWhile()
dropWhile 的行为与 takeWhile 相反,返回剩余的元素。
public static void main(String[] args) throws Exception {
List<Integer> list = Arrays.asList(10,20,30,40,30,20,10);
list.stream().dropWhile(t->t<40).forEach(System.out::println);
List<Integer> list2 = Arrays.asList(1,2,3,4,5,6,7);
list2.stream().dropWhile(t->t<7).forEach(System.out::println);
}
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());
}
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.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);
}
二、JDK10 新特性
1.局部变量类型推断 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是一门静态类型语言的事实。编译器负责推断出类型,并把结果写入字节码文件。
2.新增不可变集合方法(只读)
自 Java 9 开始,Jdk 里面为集合(List / Set / Map)都添加了 of (jdk9新增)和copyOf (jdk10新增)方法,它们两个都用来创建不可变的集合。
of()与copyOf()方法的区别是:
- of()方法直接创建一个只读集合;
- 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 创建一个新的集合。
不可变集合指的是集合的长度不可变,即不能增加和删除,可以改变集合中元素。
三、JDK 11新特性
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加强
JDK11中主要添加了一个判断value是否为空的方法
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);
}
四、JDK 14 新特性
1.改进NullPointerExceptions
改进后的NullPointerExceptions可以更明确的指出是哪个变量为null。
五、JDK 16 新特性
1.Switch升级
1.步骤省略
public static void main(String[] args) {
//jdk16以前switch结构用法
int level = new Random().nextInt(4);
String strLevel;
switch (level){
case 1:
strLevel = "优秀";
break;
case 2:
strLevel = "良好";
break;
default:
strLevel = "一般";
break;
}
System.out.println(strLevel);
//jdk16对应用法
int level = new Random().nextInt(4);
String strLevel;
switch (level){
case 1 -> strLevel="优秀";
case 2 -> strLevel="良好";
default -> strLevel="一般";
}
System.out.println(strLevel);
//衍生的新用法
int level = new Random().nextInt(4);
String strLevel = switch (level){
//此处默认带有break
case 1-> "优秀";
case 2-> "良好";
default -> "一般";
};
System.out.println(strLevel);
}
2.case优化
public static void main(String[] args) {
//jdk16以前用法
int level = new Random().nextInt(12);
String jiJi = null;
switch (level){
case 3:
case 4:
case 5:
jiJi = "春天";
break;
case 6:
case 7:
case 8:
jiJi = "夏天";
break;
case 9:
case 10:
case 11:
jiJi = "秋天";
break;
case 12:
case 1:
case 2:
jiJi = "冬天";
break;
}
System.out.println(jiJi);
//jdk16对应用法
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);
}
3.赋值优化,使用yield快速对strLeave赋值并结束。
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);
}