Java7~Java17 新特性

Java7~Java17 新特性

 

Java7

2011-07-28

长期支持版本,支持到2020年6月

类型推断 (钻石操作符Diamond Operator )

// 之前版本
Map<String,List<String>> anagrams = new HashMap<String,List<String>>();
// jdk7
Map<String,List<String>> anagrams = new HashMap<>();
 

注:这个<>被叫做diamond(钻石)运算符,Java 7后这个运算符从引用的声明中推断类型。

在switch语句中使用字符串

public voidprocessTrade(Trade t) {
    String status = t.getStatus();
    switch(status) {
        caseNEW:
            newTrade(t);
            break;
        caseEXECUTE:
            executeTrade(t);
            break;
        casePENDING:
            pendingTrade(t);
            break;
         default:
            break;
    }
}

自动资源管理 try-with-resources

带下划线的数字文本

int thousand =  1_000;
int million  =  1_000_000
 

注:这个版本中也引入了二进制文字-例如“0b1”,因此不必再将它们转换为十六进制。

改进的异常处理

public voidnewMultiCatch() {
  try{
    methodThatThrowsThreeExceptions();
  } catch(ExceptionOne | ExceptionTwo | ExceptionThree e) {
    // log and deal with all Exceptions
  }
}

New file system API(NIO 2.0)

新的 java.nio.file 由包和接口组成例如:Path,Paths,FileSystem,FileSystems等等。

文件更改通知:当文件发生更改的时候,能及时作出反馈,WatchService API 允许您在对主题(目录或文件)进行更改时接收通知事件。

Fork/Join框架

Fork/Join并行算法是我们所熟悉的分治算法的并行版本,典型的用法如下:

// 伪代码
Result solve(Problem problem) {
  if (problem is small) {
    directly solve problem
  } else {
    split problem into independent parts
      fork new subtasks to solve each part
      join all subtasks
      compose result from subresults
  }
}
 


Java8

2014-03-18

长期支持版本,支持到2030年12月

Lambda 表达式

Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)

// 1. 不需要参数,返回值为 5  
() -> 5  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)
 

方法引用

方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码

final Car police = Car.create( Car::new );
cars.forEach( police::follow );
 

默认方法

默认方法就是一个在接口里面有了一个实现的方法。

首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8 之前的集合框架没有 foreach 方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题。

 
public interface Vehicle {
   default void print(){
      System.out.println("我是一辆车!");
   }
}
 

Stream API

新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。

+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+
List<Integer> transactionsIds = 
widgets.stream()
             .filter(b -> b.getColor() == RED)
             .sorted((x,y) -> x.getWeight() - y.getWeight())
             .mapToInt(Widget::getWeight)
             .sum();
 

Date Time API

加强对日期与时间的处理,新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。

// 获取当前的日期时间
LocalDateTime currentTime = LocalDateTime.now();
System.out.println("当前时间: " + currentTime);
LocalDate date1 = currentTime.toLocalDate();
System.out.println("date1: " + date1);

Month month = currentTime.getMonth();
int day = currentTime.getDayOfMonth();
int seconds = currentTime.getSecond();

System.out.println("月: " + month +", 日: " + day +", 秒: " + seconds);

LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
System.out.println("date2: " + date2);

// 12 december 2014
LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);
System.out.println("date3: " + date3);

// 22 小时 15 分钟
LocalTime date4 = LocalTime.of(22, 15);
System.out.println("date4: " + date4);

// 解析字符串
LocalTime date5 = LocalTime.parse("20:15:30");
System.out.println("date5: " + date5);
 

Optional 类

Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。

String username = Optional.ofNullable(user).map(x->x.getUsername).orElse('clive');
 

Nashorn, JavaScript 引擎

Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。

 jjs sample.js
 

Base64

  • 基本:输出被映射到一组字符A-Za-z0-9+/,编码不添加任何行标,输出的解码仅支持A-Za-z0-9+/
  • URL:输出映射到一组字符A-Za-z0-9+_,输出是URL和文件。
  • MIME:输出隐射到MIME友好格式。输出每行不超过76字符,并且使用'\r'并跟随'\n'作为分割。编码输出最后没有行分割。
           
// 编码
String base64encodedString = Base64.getEncoder().encodeToString("java8".getBytes("utf-8"));
// 解码
byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);
 


Java9

2017-09

模块系统

模块是一个包的容器,Java 9 最大的变化之一是引入了模块系统(Jigsaw 项目)。块就是代码和数据的封装体。模块的代码被组织成多个包,每个包中包含Java类和接口;模块的数据则包括资源文件和其他静态信息。

module-info.java

           
module cn.cliveyuan.mymodule {
}
 

REPL (JShell)

交互式编程环境。JShell 是 Java 9 新增的一个交互式的编程环境工具。它允许你无需使用类或者方法包装来执行 Java 语句。它与 Python 的解释器类似,可以直接 输入表达式并查看其执行结果。

           
jshell> int doubled(int i){ return i*2;}
|  created method doubled(int)
jshell> doubled(6)
$3 ==> 12
jshell>
 

HTTP 2 客户端

HTTP/2标准是HTTP协议的最新版本,新的 HTTPClient API 支持 WebSocket 和 HTTP2 流以及服务器推送特性。

改进的 Javadoc

Javadoc 现在支持在 API 文档中的进行搜索。另外,Javadoc 的输出现在符合兼容 HTML5 标准。

多版本兼容 JAR 包

多版本兼容 JAR 功能能让你创建仅在特定版本的 Java 环境中运行库程序时选择使用的 class 版本。

然后 META-INF 目录下还新增了一个 versions 目录,如果是要支持 java9,则在 versions 目录下有 9 的目录。

           
multirelease.jar
├── META-INF
│   └── versions
│       └── 9
│           └── multirelease
│               └── Helper.class
├── multirelease
    ├── Helper.class
    └── Main.class
 

集合工厂方法

List,Set 和 Map 接口中,新的静态工厂方法可以创建这些集合的不可变实例。

           
static <E> List<E> of(E e1, E e2, E e3);
static <E> Set<E>  of(E e1, E e2, E e3);
static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, K k3, V v3);
static <K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>... entries)
 

私有接口方法

在接口中使用private私有方法。我们可以使用 private 访问修饰符在接口中编写私有方法。

接口中可定义:

  • 常量
  • 抽象方法
  • 默认方法
  • 静态方法
  • 私有方法
  • 私有静态方法
           
interface Logging {
   String ORACLE = "Oracle_Database";
   String MYSQL = "MySql_Database";
   private void log(String message, String prefix) {
      System.out.println("Log Message : " + prefix);
   }
   default void logInfo(String message) {
      log(message, "INFO");
   }
}
 

进程 API

改进的 API 来控制和管理操作系统进程。引进 java.lang.ProcessHandle 及其嵌套接口 Info ### 来让开发者逃离时常因为要获取一个本地进程的 PID 而不得不使用本地代码的窘境。

           
ProcessBuilder pb = new ProcessBuilder("notepad.exe");
String np = "Not Present";
Process p = pb.start();
ProcessHandle.Info info = p.info();
System.out.printf("Process ID : %s%n", p.pid());
System.out.printf("Command name : %s%n", info.command().orElse(np));
System.out.printf("Command line : %s%n", info.commandLine().orElse(np));

System.out.printf("Start time: %s%n",
                  info.startInstant().map(i -> i.atZone(ZoneId.systemDefault())
                                          .toLocalDateTime().toString()).orElse(np));
System.out.printf("Arguments : %s%n",
                  info.arguments().map(a -> Stream.of(a).collect(
                    Collectors.joining(" "))).orElse(np));
System.out.printf("User : %s%n", info.user().orElse(np));
 

改进的 Stream API

改进的 Stream API 添加了一些便利的方法,使流处理更容易,并使用收集器编写复杂的查询。

Java 9 为 Stream 新增了几个方法:dropWhile、takeWhile、ofNullable,为 iterate 方法新增了一个重载方法。

 

改进 try-with-resources

如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources ### 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。

           
Stream.of("a","b","c","","e","f").takeWhile(s->!s.isEmpty())
         .forEach(System.out::print);
// output: abc
Stream.of("a","b","c","","e","f").dropWhile(s-> !s.isEmpty())
         .forEach(System.out::print);
// output: ef
IntStream.iterate(3, x -> x < 10, x -> x+ 3).forEach(System.out::println);
// output: 3 \n 6 \n 9
// aka: for(int i = 3; i < 10; i +=3) {}
Stream.ofNullable(null).count()
 

改进的弃用注解 @Deprecated

注解 @Deprecated 可以标记 Java API 状态,可以表示被标记的 API 将会被移除,或者已经破坏。

Java 9 中注解增加了两个新元素:since 和 forRemoval

  • since: 元素指定已注解的API元素已被弃用的版本。
  • forRemoval: 元素表示注解的 API 元素在将来的版本中被删除,应该迁移 API。

改进钻石操作符(Diamond Operator)

匿名类可以使用钻石操作符(Diamond Operator)。

           
// before java 9
List<Integer> list = new ArrayList<Integer>(){{
            add(1);
        }};
// java 9
List<Integer> list = new ArrayList<>(){{
            add(1);
        }};
 

改进 Optional 类

java.util.Optional 添加了很多新的有用方法,Optional 可以直接转为 stream。

  • stream() 将 Optional 转为一个 Stream,如果该 Optional 中包含值,那么就返回包含这个值的 Stream,否则返回一个空的 Stream(Stream.empty())。
  • ifPresentOrElse() 如果一个 Optional 包含值,则对其包含的值调用函数 action,如果 Optional 不包含值,那么 ifPresentOrElse 便会调用 emptyAction,即 emptyAction.run()。
  • or() 如果值存在,返回 Optional 指定的值,否则返回一个预设的值。

多分辨率图像 API

定义多分辨率图像API,开发者可以很容易的操作和展示不同分辨率的图像了。

改进的 CompletableFuture API

CompletableFuture 类的异步机制可以在 ProcessHandle.onExit 方法退出时执行操作。

  • 支持 delays 和 timeouts
  • 提升了对子类化的支持
  • 新的工厂方法
           
public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)
public <U> CompletableFuture<U> newIncompleteFuture()
 

响应式流(Reactive Streams) API

Java 9中引入了新的响应式流 API 来支持 Java 9 中的响应式编程。

  • Publisher 提供无边界的数据序列,可以依据订阅者要求发布给订阅者。
  • Subscriber 订阅数据和获得消息,需要实现订阅通知,数据通知,出错处理,完成处理。
  • Subscription 代表一个订阅,绑定订阅者和发布者,订阅者可以对订阅做控制(请求发送和取消)。
  • Processor 处理器,即是个订阅者又是个发布者,内部对数据进行处理后再次发布。
           
CompletableFuture<Void> subTask;
try (SubmissionPublisher<Integer> publisher = new SubmissionPublisher<>()) {
  subTask = publisher.consume(System.out::print);
  IntStream.rangeClosed(1, 3).forEach(publisher::submit);
}
subTask.join();
 


Java10

2018-03-21

局部变量的类型推断

 Java开始引用像脚本语言JavaScript中的var类型(弱类型),允许你通过var定义任何类型的变量。

           
var varList = new ArrayList<String>();
// aka
ArrayList<String> varList = new ArrayList<String>(); 
 

应用类数据共享(CDS)

 CDS 在 JDK5 时被引进以改善 JVM 启动的表现,同时减少当多个虚拟机在同一个物理或虚拟的机器上运行时的资源占用。 JDK10 将扩展 CDS 到允许内部系统的类加载器、内部平台的类加载器和自定义类加载器来加载获得的类。之前,CDS 的使用仅仅限制在了 bootstrap 的类加载器。

额外的 Unicode 语言标签扩展

这将改善 java.util.Locale 类和相关的 API 以实现额外 BCP47 语言标签的 Unicode 扩展。尤其是,货币类型,一周的第一天,区域覆盖和时区等标签现在将被支持。

基于时间的版本控制

从Java 10开始,采用了一种新的严格的基于时间的发布模式。 在这个新模型中,Java平台的主要版本(现称为功能版本)将每6个月(3月和9月)发布一次。

根证书

在 JDK 中将提供一套默认的 CA 根证书。关键的安全部件,如 TLS ,在 OpenJDK 构建中将默认有效。这是 Oracle 正在努力确保 OpenJDK 二进制和 Oracle JDK 二进制功能上一样的工作的一部分,是一项有用的补充内容。

并行全垃圾回收器 G1

G1 是设计来作为一种低延时的垃圾回收器(但是如果它跟不上旧的堆碎片产生的提升速率的话,将仍然采用完整压缩集合)。在 JDK9 之前,默认的收集器是并行,吞吐,收集器。为了减少在使用默认的收集器的应用性能配置文件的差异,G1 现在有一个并行完整收集机制。

垃圾回收器接口

这不是让开发者用来控制垃圾回收的接口;而是一个在 JVM 源代码中的允许另外的垃圾回收器快速方便的集成的接口。

移除 Native-Header 自动生成工具 (javah)

当编译 JNI 代码时,已不再需要单独的工具来生成头文件,因为这可以通过 javac 完成。

           
javac -h xxx
 

线程-局部变量管控

这是在 JVM 内部相当低级别的更改,现在将允许在不运行全局虚拟机安全点的情况下实现线程回调。这将使得停止单个线程变得可能和便宜,而不是只能启用或停止所有线程。

在备用存储装置上的堆分配

硬件技术在持续进化,现在可以使用与传统 DRAM 具有相同接口和类似性能特点的非易失性 RAM 。这项 JEP 将使得 JVM 能够使用适用于不同类型的存储机制的堆。

试验性的基于 Java 的 JIT 编译器

最近宣布的 Metropolis 项目,提议用 Java 重写大部分 JVM 。乍一想,觉得很奇怪。如果 JVM 是用 Java 编写的,那么是否需要一个 JVM 来运行 JVM ? 相应的,这导致了一个很好的镜像类比。 现实情况是,使用 Java 编写 JVM 并不意味着必须将其编译为字节码,你可以使用 AOT 编译,然后在运行时编译代码以提高性能。

这项 JEP 将 Graal 编译器研究项目引入到 JDK 中。并给将 Metropolis 项目成为现实,使 JVM 性能与当前 C++ 所写版本匹敌(或有幸超越)提供基础。

合并 JDK 多个代码仓库到一个单独的储存库中

在 JDK9 中,有 8 个仓库: root、corba、hotspot、jaxp、jaxws、jdk、langtools 和 nashorn 。在 JDK10 中这些将被合并为一个,使得跨相互依赖的变更集的存储库运行 atomic commit (原子提交)成为可能。


Java11

2018-09-25

长期支持版本,支持到2026年9月

字符串增强

Java 11 增加了一系列的字符串处理方法

           
// 判断字符串是否为空白
" ".isBlank(); // true
// 去除首尾空格
" Javastack ".strip(); // "Javastack", 原来的trim()不能去除Unicode格式的空白
// 去除尾部空格
" Javastack ".stripTrailing(); // " Javastack"
// 去除首部空格
" Javastack ".stripLeading(); // "Javastack "
// 复制字符串
"Java".repeat(3);// "JavaJavaJava"
// 行数统计
"A\nB\nC".lines().count(); // 3  根据回车符分隔
 

集合增强

           
var list = List.of("Java", "Python", "C");
var copy = List.copyOf(list);
 

Optional增强

           
Optional.of("javastack").orElseThrow(); // javastack
Optional.of("javastack").stream().count(); // 1
Optional.ofNullable(null)
.or(() -> Optional.of("javastack"))
.get(); // javastack
 

HTTP Client API

           
var request = HttpRequest.newBuilder()
.uri(URI.create("https://javastack.cn"))
.GET()
.build();
var client = HttpClient.newHttpClient();
// 同步
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
// 异步
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
 

一个命令编译运行源代码

           
java Javastack.java
 

垃圾收集器GC

  • 新增Epsilon
  • 新增ZGC
  • G1增强


Java12

2019-03-19

String API 更改

           
// 缩进:字符串前增加空格
String result = "foo\nbar\nbar2".indent(4);
// 转换:Function类型作为入参时,内部的「处理逻辑」将增加更多灵活性
String transformedName = name.transform(String::strip);
// 比较文件内容: 如果内容相同返回-1,否则返回第一处不匹配的字节位置
long mismatch = Files.mismatch(Path, Path);
 

紧凑的数据格式

紧凑的数字表示更易于阅读,并且在不丢失原始含义的情况下,在屏幕上需要更少的空间。

           
NumberFormat formatter = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
String formattedString = formatter.format(25000L);
System.out.println(formattedString);
// output: 25K
 

Switch表达式(预览)

注意:要使用此预览特性,请记住,我们必须在应用程序启动期间使用-enable-preview标志显式地指示JVM。

           
boolean isWeekend = switch (day) {
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> false;
    case SATURDAY, SUNDAY -> true;
    default -> throw new IllegalStateException("Illegal day entry :: " + day);
};
System.out.println(isWeekend);
 

低暂停时间的GC (Shenandoah GC)

Shenandoah是一种垃圾收集(GC)算法,旨在保证低延迟(10 - 500 ms的下限)。 它通过在运行Java工作线程的同时执行GC操作减少GC暂停时间。 使用Shenandoah,暂停时间不依赖于堆的大小。 这意味着无论堆的大小如何,暂停时间都是差不多的。

这是一个实验性功能,不包含在默认(Oracle)的OpenJDK版本中。

微基准测试套件 (JMH)

此功能为JDK源代码添加了一套微基准测试(大约100个),简化了现有微基准测试的运行和新基准测试的创建过程。 它基于Java Microbenchmark Harness(JMH)并支持JMH更新。

此功能使开发人员可以轻松运行当前的微基准测试并为JDK源代码添加新的微基准测试。 可以基于Java Microbenchmark Harness(JMH)轻松测试JDK性能。 它将支持JMH更新,并在套件中包含一组(约100个)基准测试。

JVM常量API

JEP 334引入了一个API,用于建模关键类文件和运行时artifacts,例如常量池。 此API将包括ClassDesc,MethodTypeDesc,MethodHandleDesc和DynamicConstantDesc等类。此 API 对于操作类和方法的工具很有帮助。

只保留一个AArch64实现

Java 12将只有一个ARM 64位实现(aarch64)。 目标是删除所有与arm64实现相关的代码,同时保留32位ARM端口和64位aarch64实现。这将把重点转移到单个64位ARM实现,并消除维护两个实现所需的重复工作。 当前的JDK 11实现中有两个64位ARM实现。

默认类数据共享归档文件

通过在64位平台上的默认类列表的帮助下生成CDS归档来改进JDK构建过程,从而有效地消除了运行java -Xshare:dump

此功能的目标包括:1.改进开箱即用的启动时间; 2. 摆脱使用-Xshare:dump

可中止的G1 Mixed GC

此功能通过将Mixed GC集拆分为强制部分和可选部分,使G1垃圾收集器更有效地中止垃圾收集过程。通过允许垃圾收集过程优先处理强制集,g1可以更多满足满足暂停时间目标。

G1及时返回未使用的已分配内存

此功能的主要目标是改进G1垃圾收集器,以便在不活动时将Java堆内存归还给操作系统。 为实现此目标,G1将在低应用程序活动期间定期生成或持续循环检查完整的Java堆使用情况。这将立即归还未使用的部分Java堆内存给操作系统。 用户可以选择执行FULL GC以最大化返回的内存量。

Support for Unicode 11

Unicode 11增加了684个字符,共137,374个字符,增加了7个新脚本,共146个脚本。


Java13

2019-09-17

Switch表达式 (Beta版)

           
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);
}
 

文字块 Text Blocks(预览版)

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

Dynamic CDS Archives

扩展CDS,从而允许在Java应用执行后进行动态类归档,归档的类将包括当前默认基础CDS归档中不存在的应用类和库中的类。

主要目标有:

  1. 提高CDS的可用性,消除了用户使用时为每个应用程序创建类列表(class list)的需要;
  2. 通过-Xshare:dump参数开启静态归档,包括内建的类加载器和用户自定义的类加载器。

ZGC: Uncommit Unused Memory

增强ZGC特性,将没有使用的堆内存归还给操作系统。ZGC当前不能把内存归还给操作系统,即使是那些很久都没有使用的内存,有点像貔貅一样,只进不出,哈哈。这种行为并不是对任何应用和环境都是友好的,尤其是那些内存占用敏感的服务。

Reimplement the Legacy Socket API

用一个易于维护和Debug的,更简单、更现代的实现来取代java.net.Socket和java.net.ServerSocket。Socket和ServerSocket可以追溯到JDK1.0,它们的实现混合了Java和C代码,维护和调试都非常痛苦。而且其实现用线程栈来进行IO buffer,导致某些场景需要调大Xss。

全新实现的NioSocketImpl,用来取代PlainSocketImpl,它的优点如下:

  1. 非常容易维护和Debug;
  2. 直接使用JDK的NIO实现,不需要自己的本地代码;
  3. 结合了buffer cache机制,所以不需要用线程栈来进行IO操作;
  4. 用JUC的锁取代synchronized修饰的方法;


Java14

2020-03-17

instanceof模式匹配(预览版)

instanceof进行改进,由原来的检查对象类型变成了先对对象进行类型匹配,校验成功之后转换成对应类型,然后再复制给局部变量,并且只有当模式匹配表达式匹配成功才会生效和复制,局部变量只能在当前代码块使用。

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

Record类型(预览版)

Java14引入了record类型支持更加紧凑的方式去声明一个类,而这些类能够作为不可变数据类型的封装持有者。

           
public class TestPros {
    public static void main(String[] args) {
    }
    public record person(String name, int age) {
        public String getName() {
            return this.name;
        }
        public int getAge() {
            return age;
        }
    }
}
 

Java14引入了record类,所以在java.lang.Class引入了2个新方法

           
RecordComponent[] getRecordComponents()
boolean isRecord()
 

Switch表达式 (正式版)

  1. 需要保持与之前switch语句同样的case分支情况
  2. 使用yield关键字来返回case分支需在Java14表达式中,表达式默认执行完之后自动跳出,不会继续往后执行要返回的结果
  3. switch表达式中不再需要显式地使用return,break或者continue来跳出当前分支
  4. Java14表达式中,表达式默认执行完之后自动跳出,不会继续往后执行
  5. 相同的case方法块,可以将case条件并列
           
int number = switch (day) {
  case 1, 2, 3 -> 10;
  case 5 -> 5;
  default -> 0;
};
 

改进NullPointExceptions提示信息

改进空指针提示信息 帮助我们更加直观找到 Null变量

           
  public static void main(String[] args) {
        String str = null;
        System.out.println(str.length());
    }
    
    //Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "str" is null
   at cn.cliveyuan.TestPros.main(TestPros.java:7)






 


G1的NUMA可识别内存分配

  1. 改进非一致性系统内存访问的G1垃圾收集器整体性能,主要针对年轻代内存分配优化.
  2. 创建新对象->分配内存->存放内存(region)->(支持NUMA)分配当前线程NUMA节点空闲内存区。基于同一个对象创建调用频率较高,存活时间短(能够提高一些大型计算机的G1内存分配回收性能)
  3. 启动可识别内存分配-XX:+UseNUMA

删除CMS垃圾回收器

Java14 正式移除了CMS垃圾回收器

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

Java14在之前的Linux/x64增加了MacOS和windows系统,解决了开发人员你需要在桌面操作系统中使用ZGC问题。在MacOS和Windows下面开启ZGC的方式需要使用vm参数

           
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
 

启用ParallelScavenge和SeialOld GC的组合使用

年轻代当中使用并行算法、老年代使用串行算法,混搭使用,太过冒险。所以Java14考虑将这两GC的组合启用 采用如下参数 去弃用该组合参数

           
-XX:+UseParallelGC -XX:-UseParallelOldGC
 

文本块 (第二预览版本)

  1. Java14 在13的基础上新增了 两个转义符 “\”和“\s"
           
\行终止符
\s 表示一个空格
 
  1. stripIndent() :用于从文本块中去除空白字符
  2. translateEscapes():用于翻译转义字符
  3. formatted(Object... args):用于格式化


Java15

2020-09-15

EdDSA 数字签名算法

新加入 Edwards-Curve 数字签名算法(EdDSA)实现加密签名。在许多其它加密库(如 OpenSSL 和 BoringSSL)中得到支持。与 JDK 中的现有签名方案相比,EdDSA 具有更高的安全性和性能。

           
// example: generate a key pair and sign
KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
KeyPair kp = kpg.generateKeyPair();
// algorithm is pure Ed25519
Signature sig = Signature.getInstance("Ed25519");
sig.initSign(kp.getPrivate());
sig.update(msg);
byte[] s = sig.sign();

// example: use KeyFactory to contruct a public key
KeyFactory kf = KeyFactory.getInstance("EdDSA");
boolean xOdd = ...
BigInteger y = ...
NamedParameterSpec paramSpec = new NamedParameterSpec("Ed25519");
EdECPublicKeySpec pubSpec = new EdECPublicKeySpec(paramSpec, new EdPoint(xOdd, y));
PublicKey pubKey = kf.generatePublic(pubSpec);
 

封闭类(预览版)

可以是封闭类和或者封闭接口,用来增强 Java 编程语言,防止其他类或接口扩展或实现它们。 有了这个特性,意味着以后不是你想继承就继承,想实现就实现了,你得经过允许才行。

           
public abstract sealed class Student
    permits ZhangSan, LiSi, ZhaoLiu {
    ...
}
// 类 Student 被 sealed 修饰,说明它是一个封闭类,并且只允许指定的 3 个子类继承。
 

隐藏类

此功能可帮助需要在运行时生成类的框架。框架生成类需要动态扩展其行为,但是又希望限制对这些类的访问。隐藏类很有用,因为它们只能通过反射访问,而不能从普通字节码访问。此外,隐藏类可以独立于其他类加载,这可以减少框架的内存占用。这是一个新的功能。

移除了 Nashorn JavaScript 脚本引擎

移除了 Nashorn JavaScript 脚本引擎、APIs,以及 jjs 工具。这些早在 JDK 11 中就已经被标记为 deprecated 了,JDK 15 被移除就很正常了。Nashorn 是 JDK 1.8 引入的一个 JavaScript 脚本引擎,用来取代 Rhino 脚本引擎。Nashorn 是 ECMAScript-262 5.1 的完整实现,增强了 Java 和 JavaScript 的兼容性,并且大大提升了性能。 那么为什么要移除? 官方的解释是主要的:随着 ECMAScript 脚本语言的结构、API 的改编速度越来越快,维护 Nashorn 太有挑战性了,所以移除。

重新实现 DatagramSocket API

重新实现旧版 DatagramSocket API,更简单、更现代的实现来代替java.net.DatagramSocket和java.net.MulticastSocketAPI 的基础实现,提高了 JDK 的可维护性和稳定性。 新的底层实现将很容易使用虚拟线程,目前正在 Loom 项目中进行探索。这也是 JEP 353 的后续更新版本,JEP 353 已经重新实现了 Socket API。

Java7~Java17 新特性

准备禁用和废除偏向锁

在 JDK 15 中,默认情况下禁用偏向锁(Biased Locking),并弃用所有相关的命令行选项。 后面再确定是否需要继续支持偏向锁,因为维护这种锁同步优化的成本太高了。

模式匹配(第二次预览)

第一次预览是 JDK 14 中提出来的

           
// before
if (obj instanceof String) {
    String s = (String) obj;
    // 使用s
}

// now
if (obj instanceof String s) {
    // 使用s
}
 

ZGC 功能转正

ZGC是一个可伸缩、低延迟的垃圾回收器。 ZGC 已由JEP 333集成到JDK 11 中,其目标是通过减少 GC 停顿时间来提高性能。借助 JEP 377,JDK 15 将 ZGC 垃圾收集器从预览特性变更为正式特性而已,没错,转正了。 这个 JEP 不会更改默认的 GC,默认仍然是 G1。

文本块 (正式版)

文本块,是一个多行字符串,它可以避免使用大多数转义符号,自动以可预测的方式格式化字符串,并让开发人员在需要时可以控制格式。文本块最早准备在 JDK 12 添加的,但最终撤消了,然后在 JDK 13 中作为预览特性进行了添加,然后又在 JDK 14 中再次预览,在 JDK 15 中,文本块终于转正,暂不再做进一步的更改。

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

Shenandoah 垃圾回收算法 (正式版)

Shenandoah 垃圾回收从实验特性变为产品特性。这是一个从 JDK 12 引入的回收算法,该算法通过与正在运行的 Java 线程同时进行疏散工作来减少 GC 暂停时间。Shenandoah 的暂停时间与堆大小无关,无论堆栈是 200 MB 还是 200 GB,都具有相同的一致暂停时间。JDK 15 Shenandoah垃圾收集器从预览特性变更为正式特性而已。

移除了 Solaris 和 SPARC 端口

移除了 Solaris/SPARC、Solaris/x64 和 Linux/SPARC 端口的源代码及构建支持。这些端口在 JDK 14 中就已经被标记为 deprecated 了。

外部存储器访问 API(二次孵化)

这个最早在 JDK 14 中成为孵化特性,JDK 15 继续二次孵化并对其 API 有了一些更新。目的是引入一个 API,以允许 Java 程序安全有效地访问 Java 堆之外的外部内存。这同样是 Java 14 的一个预览特性。

Records Class(二次预览)

Records Class 也是第二次出现的预览功能,它在 JDK 14 中也出现过一次了,使用 Record 可以更方便的创建一个常量类,使用的前后代码对比如下。

           
// before
class Point {
    private final int x;
    private final int y;

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

    int x() { return x; }
    int y() { return y; }

    public boolean equals(Object o) {
        if (!(o instanceof Point)) return false;
        Point other = (Point) o;
        return other.x == x && other.y = y;
    }

    public int hashCode() {
        return Objects.hash(x, y);
    }

    public String toString() {
        return String.format("Point[x=%d, y=%d]", x, y);
    }
}

// now 
record Point(int x, int y) { }
 

废除 RMI 激活

废除 RMI 激活,以便在将来进行删除。需要说明的是,RMI 激活是 RMI 中一个过时的组件,自 Java 8 以来一直是可选的。


Java16

2021-03-16

模式匹配(正式版)

第一次预览是 JDK 14 中提出来的

           
// before
if (obj instanceof String) {
    String s = (String) obj;
    // 使用s
}

// now
if (obj instanceof String s) {
    // 使用s
}
 

Record类型(正式版)

Java14引入了record类型支持更加紧凑的方式去声明一个类,而这些类能够作为不可变数据类型的封装持有者。

           
public class TestPros {
    public static void main(String[] args) {
    }
    public record person(String name, int age) {
        public String getName() {
            return this.name;
        }
        public int getAge() {
            return age;
        }
    }
}
 

打包工具Packaging Tool

提供了一个新的打包工具jpackage,用来打包独立的Java应用程序。这个工具可以生成windows上的exe和msi,MacOS上的pkg和dmg,以及linux上的deb和rpm。它很好的给用户提供了一键式安装Java程序的好方法。

           
// jar
jpackage --name myapp --input lib --main-jar main.jar 
// main class 
jpackage --name myapp --input lib --main-jar main.jar --main-class myapp.Main

// module
jpackage --name myapp --module-path lib -m myapp 
// main class in module
jpackage --name myapp --module-path lib -m myapp/myapp.Main
 

Elastic Metaspace

弹性的元空间,可以帮助 HotSpot 虚拟机,将元空间中未使用的 class 元数据内存更及时地返回给操作系统,以减少元空间的内存占用空间。另外,还简化了元空间的代码,以降低维护成本。

ZGC并发线程处理

ZGC 是一种较新的垃圾回收器,指在解决 HotSpot 虚拟机中的 GC 停顿及可伸缩问题。

ZGC是The Z Garbage Collector,是JDK 11中推出的一款低延迟垃圾回收器,它尝试解决GC之痛,也就是停顿。 同时,它也将面向以TB为单位的超大规模的内存。在Java 16中,ZGC的线程栈处理的众多操作,从检查点移动到了并发阶段,这样意味着停顿更小了。

Unix Domain套接字

Unix Domain套接字本身提供给了一套兼容于网络编程,但是更加可靠、高效、安全的进程间通信方式,它不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。

JDK 内部默认强封装

JDK 16 开始对 JDK 内部大部分元素默认进行强封装,sun.misc.Unsafe 之类的关键内部 API 除外,从而限制对它们的访问。 此外,用户仍然可以选择自 JDK 9 以来的默认的宽松的强封装,这样可以帮助用户毫不费力地升级到未来的 Java 版本。

基于值的类的警告

将基础类型包装类指定为基于值的类,废除其构造函数以进行删除,从而提示新的弃用警告。并且提供了在任何基于值的类的实例上不正常进行同步的警告。

向量API (孵化版)

Vector API 这是一个新的初始迭代孵化器模块,模块包:jdk.incubator.vector,用于表示在运行时可靠地编译到支持的 CPU 架构上的最佳矢量硬件指令的矢量计算。

外部链接API (孵化版)

Foreign Linker API 提供了一个静态的,纯Java的访问本地native 代码的方法,它将极大简化我们调用本地代码的过程,是JNI的进化版。

外部内存访问 API(孵化版)

引入了一个新的 API,可以帮助 Java 应用程序更安全、有效地访问 Java 堆之外的外部内存。

封闭类 (第二次预览)

           
public abstract sealed class Student
    permits ZhangSan, LiSi, ZhaoLiu {
    ...
        
}
 

启用 C++14 语言特性

它允许在 JDK C++ 源代码中使用 C++14 语言特性,并提供在 HotSpot 代码中可以使用哪些特性的具体指导。在 JDK 15 中,JDK 中 C++ 代码使用的语言特性仅限于 C++98/03 语言标准。它要求更新各种平台编译器的最低可接受版本。

从 Mercurial 迁移到 Git,迁移到 GitHub

将 OpenJDK 社区的源代码存储库从 Mercurial(hg)迁移到 Git,并将它们托管在 GitHub 上以供 JDK 11 及更高版本使用,其中包括将 jcheck、webrev 和 defpath 工具等工具更新到 Git。Git 减小了元数据的大小(约 1/4),可节省本地磁盘空间并减少克隆时间。与 Mercurial 相比,现代工具链可以更好地与 Git 集成。

Windows/AArch64 移植

将 JDK 移植到 Windows/ AArch64 平台系列。


Java17

2021-09-14

长期支持版本,支持到2029年9月

密封类 Sealed Classes (正式版)

           
public abstract sealed class Student
    permits ZhangSan, LiSi, ZhaoLiu {
    ...
        
}
 

为 switch 支持模式匹配 (预览版)

           
// before
static String formatter(Object o) {
    String formatted = "unknown";
    if (o instanceof Integer i) {
        formatted = String.format("int %d", i);
    } else if (o instanceof Long l) {
        formatted = String.format("long %d", l);
    } else if (o instanceof Double d) {
        formatted = String.format("double %f", d);
    } else if (o instanceof String s) {
        formatted = String.format("String %s", s);
    }
    return formatted;
}

// now
static String formatterPatternSwitch(Object o) {
    return switch (o) {
        case Integer i -> String.format("int %d", i);
        case Long l    -> String.format("long %d", l);
        case Double d  -> String.format("double %f", d);
        case String s  -> String.format("String %s", s);
        default        -> o.toString();
    };
}
 

恢复始终执行严格模式的浮点定义

Java 最初只有严格的浮点语义,但从 JDK 1.2 开始,为了适应当时硬件架构的限制,默认情况下允许这些严格语义中的细微变化,而现在这些都没有必要了,已被 JEP 306 删除。

增强型伪随机数生成器

增强型伪随机数生成器,java.util.random 包更新了,提高了不同 PRNGs(伪随机数生成器)的互操作性,并使基于需求而不是硬编码特定实现的算法变得容易。

这次更改包括伪随机数生成器(PRNG)的新的接口类型和实现,包括可跳 PRNGs 和一个可拆分的 PRNG 算法(LXM),以及全新的 RandomGeneratorFactory 类。

新的 macOS 渲染管道

这个新管道通过使用新的 Apple Metal API 为 macOS 实现 Java 2D 渲染管道,减少了 JDK 对已弃用的 Apple OpenGL API 的依赖。

macOS AArch64 端口

macOS AArch64 端口,即提供可适用于 macOS 的 JDK 版本,该版本可在基于 Arm 64 的较新的 macOS 系统上本地化运行。

弃用 Applet API

Applet 是一种运行在 Web 浏览器内的 Java 程序,但 Applet 早就没什么实际用途了。

JDK 内部强封装

JDK 16 开始对 JDK 内部大部分元素默认进行强封装,sun.misc.Unsafe 之类的关键内部 API 除外,从而限制对它们的访问。 此外,用户仍然可以选择自 JDK 9 以来的默认的宽松的强封装,这样可以帮助用户毫不费力地升级到未来的 Java 版本。

移除 RMI 激活

RMI 激活机制已于 2020 年 9 月在 JDK 15 中移除了,远程方法调用 (RMI) 激活机制现也已被移除,需要说明的是,RMI 激活是 RMI 中一个过时的组件,自 Java 8 以来一直是可选的。

移除实验性的 AOT 和 JIT 编译器

AOT 和 JIT 这两个实验性的编译器,自从在 JDK 9 中引入以来几乎没有怎么使用,市面上也出现了更为广泛使用的替代方案,并且维护它们所需的工作量很大,所以在 JDK 16 中就已经删除了,本次从 OpenJDK 项目中删除了源代码。

弃用安全管理器

安全管理器从 Java 1.0 开始,这些年来它一直都不是保护 Java 应用程序代码的主要手段,也很少用于保护 Java 服务器端代码,所以这个版本标识为弃用状态了,未来的版本会进行移除。

外部函数和内存 API(孵化中)

改进了 JDK 14 和 JDK 15 引入的 API,通过有效调用外部函数(即 JVM 之外的代码),以及安全地访问外部内存(JVM 之外的内存),这些 API 可以调用本地库和处理本地数据,与 Java 运行环境之外的代码和数据进行交互。

矢量 API(二次孵化中)

Vector API 这是一个新的初始迭代孵化器模块,模块包:jdk.incubator.vector,用于表示在运行时可靠地编译到支持的 CPU 架构上的最佳矢量硬件指令的矢量计算,矢量运算可以提供优于等效标量计算的性能,并且在机器学习、人工智能和密码学等领域非常普遍。

本次增强的 API 允许以一种在运行时,可靠地编译为支持的 CPU 架构上的最佳向量指令的方式表达向量计算。

上下文特定反序列化过滤器

允许应用配置 context-specific 和 dynamically-selected 过滤器,通过一个 JVM 范围的过滤器工厂,用来为每个单独的反序列化操作选择一个过滤器。

JDK 17 免费

Oracle 宣布,从 JDK 17 开始,后面的 JDK 都全部免费提供

Oracle JDK17 与 OpenJDK 17 区别:

  1. Oracle JDK 提供了各种安装程序,还包含更新规则,而 OpenJDK 只提供了一个纯压缩包;
  2. Usage Logging 仅在 Oracle JDK 中可用;
  3. Oracle JDK 要求第三方加密提供程序使用 Java 加密扩展(JCE)进行签名,而 OpenJDK 继续允许使用未签名的第三方加密提供程序;
  4. java -version 的输出也是不同的,Oracle JDK 返回 java 并包含 Oracle 特定的标识符,OpenJDK 返回 OpenJDK 并且不包含特定于 Oracle 的标识符;
  5. 许可证不同,Oracle JDK 17+ 是根据 Oracle 免费条款和条件许可发布的,而 OpenJDK 在 GPLv2wCP 下发布的;
  6. Oracle JDK 源代码含有 "ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.",其使用受许可条款约束的,而 OpenJDK 源代码可参考 GPL 许可条款;

Oracle JDK 17 下载地址:

https://www.oracle.com/java/technologies/javase-downloads.html

OpenJDK 17 下载地址:

https://jdk.java.net/17/

 

上一篇:Java17--IO2


下一篇:oeasy教您玩转vim - 12 - # 词头词尾