大话java近代版本特性

我们都知道,在 Java 9 之后,每六个月就会发布一次新版本。

下面的 Java 发布周期可以看到,从 95 年发布的 JDK Beta 至今的 25 年时间,已经发布了 16 个版本。然而从 17 年开始,短短 3 年时间就发布了 6 个版本,占比 37.5% 。因此更多、更新鲜的特性也更集中在最近几年:

一、Java 的发布周期

1995 年 alpha 和 beta Java 公开版本发布,取名为 WebRunner。

1996.1.23 Java 第一个版本发布,取名叫 Oak。

在 Java 9 之后,每六个月发布一次新版本。但是不是每个版本都是 LTS(Long-Term-Support)。按照 Oracle 的计划,每三年会有一个 LTS 版本。

那么每个新版 Java 都会给我们带来哪些便利之处呢?下面我们来体验一下。

二、各版本特性介绍

Java 9

功能增强

1 模块化系统

Java 9 中最主要的变化是模块化系统(Jigsaw 项目)。采用模块化系统的应用程序只需要这些应用程序所需的那部分 JDK 模块,而非是整个 JDK 框架了。

模块化系统有以下几个优点:

  1. 让 Java 程序更加容易轻量级部署

  2. 改进组件间的依赖管理,引入比 Jar 粒度更细的 Module

  3. 改进性能和安全性

JDK 8 的 JRE 的部署是一个单体模式,一个超大的 rt.jar (大约60多兆),tools.jar 也有几十兆,即使使用一个Hello World,也需要一整套上百兆的 JRE 环境。

JAVA 9 引入模块后,将所有的类组织成模块形式,模块之间有着优美的依赖关系。

所有的模块将需要在 module-info.java 文件中进行描述,该文件位于Java代码结构的顶层。

 

/**
* 我们的模块 car(汽车)需要依赖模块 engine(引擎), 需要导出 handling(操作)包
**/
module me.aboullaite.java9.modules.car {
requires me.aboullaite.java9.modules.engines; // 依赖的模块
exports me.aboullaite.java9.modules.car.handling; // 在模块中导出的包
}

2 JShell REPL

REPL 是一种快速运行语句的命令行工具。

在 Java 中,如果你想执行一个简单的语句,我们要么创建一个带 main 方法的类,要么创建一个可以执行的 Test 类。当你正在启动 Java 程序的时候,如果你想执行某些语句并且想立刻看见执行结果,上面的做法看起来不是那么有用了。

JShell 试图去解决这个问题。Java 开发者可以利用 JShell 在没有创建类的情况下直接声明变量,计算表达式,执行语句。

JShell 也可以从文件中加载语句或者将语句保存到文件中。JShell 也可以使用 tab 键进行自动补全。

 

jshell> 2 + 2
$3 ==> 4
| created scratch variable $3 : int

jshell> String twice(String s) {
...> return s + s;
...> }
| created method twice(String)

jshell> twice("Ocean")
$5 ==> "OceanOcean"
| created scratch variable $5 : String

语法/方法增强

1 接口中使用私有方法

Java 9 中可以在接口中定义私有方法。示例代码如下:

 

public interface TestInterface {
String test();

// 接口默认方法
default String defaultTest() {
privateMethod();
return "default";
}

private String privateMethod() {
System.out.println("private method in interface");
return "private";
}
}

2 集合不可变实例工厂方法

在以前,我们想要创建一个不可变的集合,需要先创建一个可变集合,然后使用 unmodifiableSet 创建不可变集合。代码如下:

 

Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
set.add("C");

set = Collections.unmodifiableSet(set);
System.out.println(set);

Java 9 中提供了新的 API 用来创建不可变集合。

 

List<String> list = List.of("A", "B", "C");
Set<String> set = Set.of("A", "B", "C");
Map<String, String> map = Map.of("KA", "VA", "KB", "VB");

3 改进 try-with-resources

Java 9 中不需要在 try 中额外定义一个变量。Java 9 之前需要这样使用 try-with-resources:

 

InputStream inputStream = new StringBufferInputStream("a");
try (InputStream in = inputStream) {
in.read();
} catch (IOException e) {
e.printStackTrace();
}

在 Java 9 中可以直接使用 inputStream 变量,不需要再额外定义新的变量了。

 

InputStream inputStream = new StringBufferInputStream("a");
try (inputStream) {
inputStream.read();
} catch (IOException e) {
e.printStackTrace();
}

4 响应式流

Java 9 中的 Flow 类定义了响应式编程的 API。实际上就是拷贝了 Reactive Stream 的四个接口定义,然后放在 java.util.concurrent.Flow 类中。Java 9 提供了 SubmissionPublisher 和 ConsumerSubscriber 两个默认实现。

Java 8 引入了 Stream 用于流的操作,Java 9 引入的 Flow 也是数据流的操作。相比之下,Stream 更侧重于流的过滤、映射、整合、收集,而 Flow 更侧重于流的产生与消费。

java.util.concurrent.Flow 包含以下4个接口:

  • Flow.Processor(处理器)

  • Flow.Publisher(发布者)

  • Flow.Subscriber(订阅者)

  • Flow.Subscription(订阅管理器)

这些接口都支持响应式流发布-订阅框架。Java 9也提供了实用类 SubmissionPublisher。一个发布者产生一个或多个物品,这些物品由一个或多个消费者消耗。并且订阅者由订阅管理器管理。订阅管理器连接发布者和订阅者。

5 diamond 操作符范围的延伸

在 Java 9 之前,内部匿名类需要指定泛型类型,如下:

 

Handler<? extends Number> intHandler1 = new Handler<Number>() {
}

而在 Java 9 中,可以自动做类型推导,如下:

 

Handler<? extends Number> intHandler1 = new Handler<>() {
}

6 新增 HTTP 2 客户端

使用示例:

 

URI testPageURI = new URI("http://127.0.0.1:8080/testPage");
CompletableFuture<HttpResponse> nonBlockingResponse = HttpRequest
.create(testPageURI)
.GET().responseAsync();

int tries = 0;
while(!nonBlockingResponse.isDone() && tries++ < 5){
Thread.sleep(5);
}
if(nonBlockingResponse.isDone()){
HttpResponse response = nonBlockingResponse.get();
System.out.println("status code :"+response.statusCode()+"-->"+response.body(HttpResponse.asString()));
}else{
nonBlockingResponse.cancel(true);
System.out.println("cancelling, could not get response");
}

7 CompletableFuture 的改进

  1. 支持 delays 和 timeouts

 

public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)

在 timeout 前以给定的 value 完成这个 CompletableFutrue。返回这个 CompletableFutrue。

 

public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit)

如果没有在给定的 timeout 内完成,就以 java.util.concurrent.TimeoutException 完成这个 CompletableFutrue,并返回这个 CompletableFutrue。

  1. 新的工厂方法

Java 8 引入了 <U> CompletableFuture<U> completedFuture(U value) 工厂方法来返回一个已经以给定 value 完成了的 CompletableFuture。Java 9 以一个新的 CompletableFuture<U> failedFuture(Throwable ex) 来补充了这个方法,可以返回一个以给定异常完成的 CompletableFuture。

以外,Java 9 引入了下面这对 stage-oriented 工厂方法,返回完成的或异常完成的 completion stages:

<U> CompletionStage<U> completedStage(U value): 返回一个新的以指定 value 完成的 CompletionStage,并且只支持 CompletionStage 里的接口。

<U> CompletionStage<U> failedStage(Throwable ex): 返回一个新的以指定异常完成的 CompletionStage,并且只支持 CompletionStage里的接口。

其他更新

  1. 增强 Javadoc,增加了 HTML 5 文档的输出

  2. 保留下划线字符。变量不能被命名为 _

  3. 废弃 Applet API

  4. javac 不再支持 Java1.4 以及之前的版本

  5. 废弃 Java 浏览器插件

  6. 增强 @Deprecated,新增了 since 和 forRemoval 属性

Java 9 总结

Java 9 最大的特点是引入了模块化,对于一些小容量硬件设备,模块化可以提高空间利用率。此外模块化的依赖相比于以前的依赖关系更加清晰,相信未来会有更多模块化相关的迭代发展。

Java 9 也对语法和方法进行了升级,这让开发人员可以减少外部的依赖,更多的使用 JDK 自带的方法,降低依赖复杂度。

Java 10

语法增强

1 新增局部类型推断 var

 

var a = "aa";
System.out.println(a);

var 关键字目前只能用于局部变量以及 for 循环变量声明中。

2 不可修改集合的改进

  1. 增加 copyOf() 方法,返回给定 Collection 的不可修改的副本。

 

var list = new ArrayList<String>();
list.add("a");

var list2 = List.copyOf(list);

  1. toUnmodifiable():将 Stream 收集到不可修改的 List、Map 或 Set 中。

 

list.stream().collect(Collectors.toUnmodifiableList());

3 Optinal 新增方法 orElseThrow()

如果不存在任何值,则抛出 NoSuchElementException

以前的 orElseThrow:

 

Integer firstEven = someIntList.stream()
.filter(i -> i % 2 == 0)
.findFirst()
.orElseThrow(() -> new NoSuchElementException());

Java 10 可以这样写:

 

Integer firstEven = someIntList.stream()
.filter(i -> i % 2 == 0)
.findFirst()
.orElseThrow();

GC 增强

1 用于 G1 的并行 Full GC

G1 垃圾收集器是自 JDK 9 以来的默认垃圾收集器。但是,G1 的 Full GC 使用了单线程的 mark-sweep-compact 算法。

它已 更改为 Java 10 中的并行 mark-sweep-compact 算法 ,有效地减少了 Full GC 期间的停滞时间。

其他升级

1 统一的垃圾回收接口

在当前的 Java 结构中,组成垃圾回收器(GC)实现的组件分散在代码库的各个部分。尽管这些惯例对于使用 GC 计划的 JDK 开发者来说比较熟悉,但对新的开发人员来说,对于在哪里查找特定 GC 的源代码,或者实现一个新的垃圾收集器常常会感到困惑。更重要的是,随着 Java modules 的出现,我们希望在构建过程中排除不需要的 GC,但是当前 GC 接口的横向结构会给排除、定位问题带来困难。

为解决此问题,需要整合并清理 GC 接口,以便更容易地实现新的 GC,并更好地维护现有的 GC。Java 10 中,hotspot/gc 代码实现方面,引入一个干净的 GC 接口,改进不同 GC 源代码的隔离性,多个 GC 之间共享的实现细节代码应该存在于辅助类中。这种方式提供了足够的灵活性来实现全新 GC 接口,同时允许以混合搭配方式重复使用现有代码,并且能够保持代码更加干净、整洁,便于排查收集器问题。

2 试验性 JIT 编译器

Graal 是用Java编写的,与 HotSpot JVM 集成的动态编译器。它专注于高性能和可扩展性。它也是 JDK 9 中引入的实验性 Ahead-of-Time(AOT)编译器的基础。

JDK 10 使 Graal 编译器可以用作 Linux / x64 平台上的实验性 JIT 编译器。

Java 10 总结

Java 10 带来的更新并不算多,但是 var 关键字的引入仿佛把 Java 和动态语言在使用上的边界变得模糊了许多。

G1 的升级,也可以在 full gc 时带来更好的表现。

Java 11

语法/工具 增强

1 标准 HTTP Client 升级

Java 11 对 Java 9 中引入并在 Java 10 中进行了更新的 Http Client API 进行了标准化,在前两个版本中进行孵化的同时,Http Client 几乎被完全重写,并且现在完全支持异步非阻塞。

使用示例:

 

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://openjdk.java.net/"))
.build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();

2 在 Lambda 表达式中使用局部变量类型推断

Java 11 中将局部变量和 Lambda 表达式的用法进行了统一,并且可以将注解应用于局部变量和 Lambda 表达式。

 

@Nonnull var x = new Foo();
(@Nonnull var x, @Nullable var y) -> x.process(y)

GC 增强

1 ZGC:可伸缩低延迟垃圾收集器

ZGC 是一个可伸缩的、低延迟的垃圾收集器,主要为了满足如下目标进行设计:

  • GC 停顿时间不超过 10ms

  • 即能处理几百 MB 的小堆,也能处理几个 TB 的大堆

  • 应用吞吐能力不会下降超过 15%(与 G1 回收算法相比)

  • 方便在此基础上引入新的 GC 特性和利用 colord

  • 针以及 Load barriers 优化奠定基础

  • 当前只支持 Linux/x64 位平台

回收算法停顿时间对比:

2 Epsilon:低开销垃圾回收器

Epsilon 垃圾回收器的目标是开发一个控制内存分配,但是不执行任何实际的垃圾回收工作。它提供一个完全消极的 GC 实现,分配有限的内存资源,最大限度的降低内存占用和内存吞吐延迟时间。

使用场景:

  1. 性能测试:什么都不执行的 GC 非常适合用于 GC 的差异性分析。no-op (无操作)GC 可以用于过滤掉 GC 诱发的性能损耗,比如 GC 线程的调度,GC 屏障的消耗,GC 周期的不合适触发,内存位置变化等

  2. 内存压力测试

其他增强

1 简化启动单个源代码文件的方法

Java 11 版本中,能够运行单一文件的 Java 源代码。此功能允许使用 Java 解释器直接执行 Java 源代码。源代码在内存中编译,然后由解释器执行。

 

$ java HelloWorld.java

等同于

 

$ javac HelloWorld.java
$ java -cp . hello.World

2 低开销的 Heap Profiling

Java 11 中提供一种低开销的 Java 堆分配采样方法,能够得到堆分配的 Java 对象信息,并且能够通过 JVMTI 访问堆信息。

优点:

  • 足够低的开销,可以默认且一直开启

  • 能通过定义好的程序接口访问

  • 能够对所有堆分配区域进行采样

  • 能给出正在和未被使用的 Java 对象信息

3 飞行记录器

飞行记录器之前是商业版 JDK 的一项分析工具,但在 Java 11 中,其代码被包含到公开代码库中,这样所有人都能使用该功能了。

Java 语言中的飞行记录器类似飞机上的黑盒子,是一种低开销的事件信息收集框架,主要用于对应用程序和 JVM 进行故障检查、分析。飞行记录器记录的主要数据源于应用程序、JVM 和 OS,这些事件信息保存在单独的事件记录文件中,故障发生后,能够从事件记录文件中提取出有用信息对故障进行分析。

启用飞行记录器参数如下:

-XX:StartFlightRecording

Java 11 总结

Java 11 是 Java 8 之后的 LTS 版本,无论是稳定性还是后续支持力度都会更强。

最大的特性是 ZGC 的引入,如果想体验最新的垃圾回收器,同时拥有 Java 9 ~ 10 的语法特性的话,不妨升级使用。

Java 12

语法增强

1 Switch 表达式扩展(预览功能)

目前的 switch 语句,会在多处出现 break 语句,显得代码比较冗余,同时如果某处漏写一段 break 语句,将导致程序一直向下穿透执行的逻辑错误,出现异常结果,同时这种写法比较繁琐,也容易出问题

新的 switch 语句示例:

 

switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}

同时支持在表达式返回值:

 

int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};

GC 增强

1 Shenandoah:一个低停顿垃圾收集器(实验阶段)

Shenandoah 是作为一种低停顿时间的垃圾收集器而引入到 Java 12 中的,其工作原理是通过与 Java 应用程序中的执行线程同时运行,用以执行其垃圾收集、内存回收任务,通过这种运行方式,给虚拟机带来短暂的停顿时间。

Shenandoah 垃圾回收器的暂停时间与堆大小无关,这意味着无论将堆设置为 200 MB 还是 200 GB,都将拥有一致的系统暂停时间,不过实际使用性能将取决于实际工作堆的大小和工作负载。

shenandoah 和 G1、CMS 的对比:

2 改善 G1 垃圾收集器

G1 在 garbage collection 的时候,一旦确定了 collection set(CSet) 开始垃圾收集这个过程是 without stopping 的,当 collection set 过大的时候,此时的 STW 时间会过长超出目标 pause time,这种情况在 mixed collections 时候比较明显。这个特性启动了一个机制,当选择了一个比较大的 collection set,允许将其分为 mandatory 及 optional 两部分(当完成 mandatory 的部分,如果还有剩余时间则会去处理 optional 部分)来将 mixed collections 从 without stopping 变为 abortable,以更好满足指定 pause time 的目标。

3 增强 G1 垃圾收集器,使其能自动返回未用堆内存给操作系统

G1 目前只有在 full GC 或者 concurrent cycle 的时候才会归还内存,由于这两个场景都是 G1 极力避免的,因此在大多数场景下可能不会及时会还 committed Java heap memory 给操作系统。JDK12 的这个特性新增了两个参数分别是 G1PeriodicGCInterval 及 G1PeriodicGCSystemLoadThreshold,设置为 0 的话,表示禁用。当上一次 garbage collection pause 过去 G1PeriodicGCInterval(milliseconds) 时间之后,如果 getloadavg()(one-minute) 低于 G1PeriodicGCSystemLoadThreshold 指定的阈值,则触发 full GC 或者 concurrent GC(如果开启G1PeriodicGCInvokesConcurrent),GC 之后 Java heap size 会被调整,然后多余的内存将会归还给操作系统。

Java 12 总结

如果使用 Java 12,那么 switch 语句可以省略 break,变得更加整洁。

在 GC 方面,对于 G1 回收器有一定的升级,另外也可以体验新的垃圾回收器 Shenandoah。

Java 13

语法增强

1 Switch 表达式扩展(预览功能)

在 Java 13 中对 Switch 表达式做了增强改进,在块中引入了 yield 语句来返回值,而不是使用 break。这意味着,Switch 表达式(返回值)应该使用 yield,而 Switch 语句(不返回值)应该使用 break。

yield 返回值形式:

 

private static String getText(int number) {
return switch (number) {
case 1, 2:
yield "one or two";
case 3:
yield "three";
case 4, 5, 6:
yield "four or five or six";
default:
yield "unknown";
};
}

2 文本块(预览功能)

text block,文本块,是一个多行字符串文字,它避免了对大多数转义序列的需要,以可预测的方式自动格式化字符串,并在需要时让开发人员控制格式。

文本块以三重双引号开头,并以同样的以三重双引号结尾终止,它们之间的任何内容都被解释为字符串的一部分,包括换行符。

 

String html = """
<html>
<body>
<p>Hello, World</p>
</body>
</html>
""";

String json = """
{
"name":"mkyong",
"age":38
}
""";

GC 增强

1 增强 ZGC, 释放未使用内存

Java 13 中对 ZGC 的改进,主要体现在下面几点:

  1. 释放未使用内存给操作系统

  2. 支持最大堆大小为 16TB

  3. 添加参数:-XX:SoftMaxHeapSize 来软限制堆大小

2 Dynamic CDS (Class-Data Sharing) Archives

引入了 CDS 的概念,通过把一些核心类在每个 JVM 间共享,每个 JVM 只需要装载自己的应用类,启动时间减少了,另外核心类是共享的,所以JVM的内存占用也减少了。
CDS 只能作用于 Boot Class Loader 加载的类,不能作用于 App Class Loader 或者自定义的 Class Loader 加载的类。

其他

1 Socket API 重构

在 Java 13 之前,通过使用 PlainSocketImpl 作为 SocketImpl 的具体实现。

Java 13 中的新底层实现,引入 NioSocketImpl 的实现用以替换 SocketImpl 的 PlainSocketImpl 实现

Java 13 总结

文本块功能在赋值长字符串时会有帮助,比如 Json、Html 字符串等。

Java 12 中对 G1 做了归还内存的优化,到了 13 对 ZGC 也做了相同的优化。

Java 14

语法增强

1 instanceof 模式匹配(预览阶段)

instanceof 传统使用方式:

 

if (person instanceof Student) {
Student student = (Student) person;
student.say();
// other student operations
} else if (person instanceof Teacher) {
Teacher teacher = (Teacher) person;
teacher.say();
// other teacher operations
}

Java 14 中,对 instanceof 进行模式匹配改进之后,上面示例代码可以改写成:

 

if (person instanceof Student student) {
student.say();
// other student operations
} else if (person instanceof Teacher teacher) {
teacher.say();
// other teacher operations
}

2 改进 NullPointerExceptions 提示信息

NullPointerException 传统的信息如下:

 

Exception in thread "main" java.lang.NullPointerException
at Book.main(Book.java:5)

如果对应的代码是:

 

shoopingcart.buy.book.id = 99;

这样的话,仅仅单根据异常信息中打印的行号,则比较难判断出现 NullPointerException 的原因。

Java 14 中的 NullPointerException 信息如下:

 

Exception in thread "main" java.lang.NullPointerException:
Cannot assign field "book" because "shoopingcart.buy" is null
at Book.main(Book.java:5)

能够准确打印出具体哪个变量导致的 NullPointerException。

3 Record 类型(预览功能)

传统的定义 Model 类的方式:

 

public class Point {
private final double x;
private final double y;

public Point(double x, double y) {
this.x = x;
this.y = y;
}

public double getX() {
return x;
}

public double getY() {
return y;
}
}

Java 14 中,可以使用 Records 进行定义:

 

public record Point(double x, double y) { }

当用 Record 来声明一个类时,该类将自动拥有下面特征:

  1. 拥有一个构造方法

  2. 获取成员属性值的方法

  3. hashCode() 方法和 euqals() 方法

  4. toString() 方法

  5. 类对象和属性被 final 关键字修饰,不能被继承,属性也都被 final 修饰

  6. 还可以在 Record 声明的类中定义静态属性、方法。注意,不能在 Record 声明的类中定义实例字段,类也不能声明为抽象类

4 Switch 表达式(正式版)

switch 表达式在之前的 Java 12 和 Java 13 中都是处于预览阶段,而在这次更新的 Java 14 中,终于成为稳定版本,能够正式可用。

5 文本块(第二预览版本)

Java 14 在 Java 13 引入的文本块的基础之上,新加入了两个转义符,分别是:\ 和 \s,这两个转义符分别表达涵义如下:

  • \:行终止符,主要用于阻止插入换行符。

  • \s:表示一个空格。可以用来避免末尾的白字符被去掉。

GC 相关

1 删除 CMS 垃圾回收器

2 ZGC 支持 MacOS 和 Windows 系统(实验阶段)

Java 14 总结

NPE 异常信息的完善,让错误排查变得更容易。

Records 类型可以让代码更简化。

CMS 正式退出舞台。在 Java 9 中,G1 成为了默认的垃圾回收器,同时 CMS 被标记为 deprecated,到了 14 被正式移除。未来 G1、ZGC、Shenandoah 将成为垃圾回收器的首选。

Java 15

2020 年 9 月将推出 Java 15。可以点此链接,查看 Java 15 的预览功能。

JDK 15 JAVA 15的新特性展望

伴随着2020的寒冬和新冠病毒的肆虐,JAVA迎来了久未已久的JAVA 14。自从2017年JAVA 9发布之后,JAVA的发布版本跟上了敏捷开发的步伐,小步快跑,Java平台发布节奏已从每3年以上的主要版本转变为每6个月发布一次功能。现在,每年的3月和9月都会发布新的版本功能。

三月已过,九月还远吗?

在JAVA 14中,推出了swith的最终版本,并且支持了NVM。

今天本文将会展望一下JAVA 15中会带给我们的新特性。

总体来说有5个JEP将会提交到JAVA 15。

什么?你问我JEP是什么?

JEP的全称就是JDK Enhancement Proposals,简单点讲就像是一个个对JAVA进行改进提案,这些提案会在合适的时间合适的地点被加入JDK的特定版本。

下面看下5大提案都有些什么内容:

JEP 371: Hidden Classes

通常我们在使用大型的框架或者lambda表达式的时候,会动态生成很多类。但是不幸的是标准的定义类的API:ClassLoader::defineClass 和 Lookup::defineClass不能够区分出这些类是动态生成(运行时生成)的还是静态
生成(编译生成)的。

一般来说动态生成的类生命周期更短,并且其可见性要更低。但是现有的JDK并没有这个功能。

所有有了Hidden Classes的提案,通过Hidden Classes,不管是JDK还是JDK外部的框架,在生成动态类的时候都可以定义为Hidden Classes,这样可以更加有效的控制这些动态生成类的生命周期和可见性。

JEP 372: 删除 Nashorn JavaScript Engine

实际上jdk.scripting.nashorn和jdk.scripting.nashorn.shell这两个在JDK11的时候已经被标记为deprecated。在JDK15中只是把他们删除而已。

JEP 377: 新的垃圾回收器ZGC正式上线了

Z Garbage Collector(ZGC)是在JAVA 11中引入的垃圾回收器,但一直都是实验版本,在JDK 15中,终于要上线了。

ZGC是一个重新设计的并发的垃圾回收器,可以极大的提升GC的性能。

JEP 378: Text Blocks 标准化

Text Blocks第一次是在JDK 13中以预览功能出现的JEP 355。然后在JDK 14中又出现了第二个版本JEP 368。终于在JDK 15中可以有最终版本了。

文本块是一种多行字符串文字,它避免了大多数转义序列的需要,以一种可预测的方式自动设置字符串的格式。

HTML example

传统方式:

String html = "<html>\n" +
              "    <body>\n" +
              "        <p>Hello, world</p>\n" +
              "    </body>\n" +
              "</html>\n";

文本块方式:

String html = """
              <html>
                  <body>
                      <p>Hello, world</p>
                  </body>
              </html>
              """;

SQL example

传统方式:

String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
               "WHERE `CITY` = 'INDIANAPOLIS'\n" +
               "ORDER BY `EMP_ID`, `LAST_NAME`;\n";

文本块方式:

String query = """
               SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
               WHERE `CITY` = 'INDIANAPOLIS'
               ORDER BY `EMP_ID`, `LAST_NAME`;
               """;

JEP 379: 新的垃圾回收器Shenandoah上线

Shenandoah和ZGC一样,是以实验特性在JAVA 12中引入的JEP 189。现在终于要在JAVA 15中转正了。

总结

上述就是5大很可能在JAVA 15中实现的新特性,希望大家能够喜欢。

三、升级思考

目前国内互联网公司多数采用 Java 8 版本,而一些历史较长的公司为了稳定考量仍然在使用更低的版本。升级成本、升级风险、学习成本是目前阻碍多数团队 Java 版本升级的主要原因。

但是使用新版本 Java 仍然有一些优点:

1 代码整洁

  1. 新版本的 JDK 经常会引入新的语法,而新的语法通常会是代码变得更加整洁简单

  2. 完善的方法、工具引入也会减轻代码量,降低外部依赖复杂度,提升代码质量

各版本语法改进:

版本 语法改进
9 1. 接口增加私有方法
2. 新的创建不可变集合 API
3. 改进 try-with-resources
4. 响应式流 Flow
5. diamond 操作符在匿名类的简化
6. 新增 HTTP 2 客户端
10 1. 局部类型推断 var
2. 不可修改集合增加 copyOf、toUnmodifiable 方法
3. Optinal 新增方法 orElseThrow()
11 1. 可以在 Lambda 表达式中使用局部变量类型推断
12 1. 简化了 Switch 表达式
13 1. Switch 表达式支持 yield 关键字
2. 增加文本块语法
14 1. instanceof 模式匹配 2. 增加 Record 类型

2 便利和提效

通常 Java 给人的印象是严谨而庞大,进而导致了一定程度的效率低下。

然而新版本 Java 正在努力提升自己的简洁程度和使用效率。

比如:

  1. JShell

  2. 直接执行 java 命令运行单个文件

  3. 模块化,精简包大小

  4. 内置的 HttpClient

  5. 不断完善的集合方法

3 成本的降低

Java 最近版本的改善可能带来成本的削减。尤其是像 JLink 这样的工具能够减少部署制件的大小,再加上 GC、内存使用方面的改善,这都会降低云计算的成本。

4 性能提升

通常来讲,新版本都要比之前的版本表现更好。“更好”会有多种表现形式,但是在最近的释放版本中,我们看到了启动时间的改善、内存消耗的减少,以及使用特定的 CPU 指令从而让代码使用更少的 CPU 周期。Java 9、10、11 和 12 都对垃圾收集功能进行了重大的变更和改进,包括将默认的垃圾收集器改为 G1 、对 G1 的改进以及三个实验性的垃圾收集器(Java 11 中的 Epsilon 和 ZGC,Java 12 中的 Shenandoah)。三个收集器看起来可能有些多,但是每个收集器都针对不同的使用场景进行了优化,所以现在你可以从中选择一个最适合你的应用程序的现代垃圾收集器。

各版本 GC 改进:

版本 GC 改进
10 1. 用于 G1 的并行 Full GC
11 1. 新增 Epsilon 低开销“no-op”垃圾回收器
2. 新增 ZGC 垃圾回收器
12 1. 新增 Shenandoah 垃圾回收器
2. 优化 G1,更易满足目标 pause time
3. 增强 G1 垃圾收集器,使其能自动返回未用堆内存给操作系统
13 1. 增强 ZGC, 释放未使用内存
14 1. ZGC 支持 MacOS 和 Windows 系统

5 团队氛围和成长

通常使用新技术会带给团队成员更多的兴奋感和成就感。

同时会推动成员更多的学习和分享新技术和技术趋势,提高团队的技术水平。

6 总结

就如本节开始所说,升级成本、升级风险、学习成本是阻碍版本升级的主要原因,升级固然有很多好处,但同时要考虑成本和风险,因此不同的团队、开发者需要在决定是否升级前做好考量。不过技术永远在发展,Java 也会不断推出更新的版本,对于一些创造性的新项目,使用新的 LTS 版本是值得鼓励的。

四、JDK 发展趋势展望

从 JDK 5 引进泛型,到 JDK 7 的 "<>" 操作符允许不绑定类型而初始化 List,再到JDK 8 的 Lambda 表达式,再到现在 JDK 10 的局部变量类型推断,Java 正大刀阔斧的向前发展。

Java 版本迭代和发表的节奏自从 Java 9 开始,从每 3 年以上的主要版本转变为每 6 个月发布一次功能。现在,每年的 3 月和 9 月都会发布新的版本功能。这样一来,新特性的发布会变得更加频繁。

对于未来 Java 的新特性,会在语法、方法和工具完善、编译器、垃圾回收、模块化等方向上会有更进一步的优化。

1 语法精简

随着语言的发展,原本的编程语言分类方式也要有所改变了。以前我们经常说面向对象语言,动态语言或是函数式语言。但是我们现在发现,这些边界变得越来越模糊,经常会互相学习各自的范式。

在 Java 之后发布的,或者相对较新的语言,比如 go、kotlin 等的语法相对更精简。同时 Java 从 1.7 版本开始,就呈现出了语法逐渐精简化的趋势。

接下来的新版本,将会对语法继续精简优化。

以下是笔者猜测可能会有的优化:

  1. null check 的语法精简:比如 var a = obj ? "null"

  2. for 语句的语法精简: 比如引入 for in range 语法

  3. 多线程的语法简化:在这方面 go 做得相对较好,可能会给 Java 带来启发

2 方法、工具完善

目前我们在使用 Java 的时候,几乎无可避免的引入 Guava、Apache Utils 等外部依赖。

在 Java 8、9 中,引入了 Objects.isNull、新的时间日期工具、List.of 等方法、在 Java 11 中,字符串 API 增加了 isBlank、stripTrailing 方法,简化了开发人员的工作,不难推断,未来会继续完善更多的方法和工具,更加简化代码量,提升代码的可读性。

以下是笔者猜测可能会有的优化:

  1. 内置的 CollectionUtils、MapUtils

  2. 更加完善的 Bean Constraint Checker

  3. 更完善的进程内事件驱动工具支持

3 编译器优化

在类型推断方面,Java 7 简化了泛型的钻石符号;Java 8 引入的 lambda 中支持了类型推断;Java 10 更是新增了 var 关键字支持类型推断,未来的编译器只会更加智能。

以下是笔者猜测可能会有的优化:

  1. var 关键字更广泛的使用范围

  2. JIT 的持续演进。比如 Java 10 引入的 Graal,目前还在实验阶段

4 垃圾回收

高吞吐和低卡顿一直是垃圾回收的主要目标,无论是 G1、ZGC 还是 Shenandoah 都在朝类似的目标前进。所以未来会不断有新的垃圾回收器供我们使用。

另外值得注意的是,未来的 GC 会更加的自动化、智能化,需要手动调整参数的场景会变得更少。

5 模块化

Java 9 的 Jigsaw 开启了 Java 模块化的第一步,未来会更加的标准化和规范化。

以下是笔者猜测可能会有的优化:

  1. 更加完善和清晰的 Java 内置模块

  2. 更丰富的外部模块生态

五、总结

Java 是一项二十多年前被发明出来的技术,经历了多样的发展和变化,至今仍然活力四射,拥有的庞大的使用人数。最近几年尤其是 Java 7 之后,迭代的速度变得更快,至今很多人、团队仍然在使用 Java 8 甚至是 Java 7。本文对 Java 9 至 Java 14 的各个版本主要特性进行了说明,并给出了升级 Java 带来的好处以及后续 Java 特性的发展猜测。希望能给 Java 开发人员带来新的认知和思考。

猜你喜欢

转载自blog.csdn.net/qq_31905135/article/details/108866252