JAVA8之后的版本履历(下)

简介: JAVA8之后的版本履历(下)

2.2 Java 9


参考资料

https://www.runoob.com/java/java9-new-features.html

https://www.twle.cn/c/yufei/java9/java9-basic-process-manage-api.html

https://docs.oracle.com/javase/9/whatsnew/toc.htm


2.2.1 Jigsaw 模块系统


在 Java 9 以前,打包和依赖都是基于 JAR 包进行的。JRE 中包含了 rt.jar,将近 63M,也就是说要运行一个简单的 Hello World,也需要依赖这么大的 jar 包。在 Java 9 中提出的模块化系统,对这点进行了改善。


关于模块化系统具体可以看看这篇文章。

https://zhuanlan.zhihu.com/p/24800180

2.2.2 JShell REPL

Java 9 提供了交互式解释器。有了 JShell 以后,Java 终于可以像 Python,Node.js 一样在 Shell 中运行一些代码并直接得出结果了。


2.2.3. 私有接口方法,接口中使用私有方法


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


public interface TestInterface {
    String test();
    // 接口默认方法
    default String defaultTest() {
        pmethod();
        return "default";
    }
    private String pmethod() {
        System.out.println("private method in interface");
        return "private";
    }
}


2.2.4. 集合不可变实例工厂方法


在以前,我们想要创建一个不可变的集合,需要先创建一个可变集合,然后使用 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");


2.2.5. 改进 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();
}


2.2.6. 多版本兼容 jar 包


Java 9 中支持在同一个 JAR 中维护不同版本的 Java 类和资源。


2.2.7. 增强了 Stream,Optional,Process API

2.2.8. 新增 HTTP2 Client

2.2.9. 增强 Javadoc,增加了 HTML 5 文档的输出,并且增加了搜索功能

2.2.10. 增强 @Deprecated

对 Deprecated 新增了 since 和 forRemoval 属性


2.2.11. 增强了钻石操作符 "<>",可以在 匿名内部类中使用了。


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


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


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

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


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


2.2.13. 改进的 CompletableFuture API


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

其他一些改进可参照:

https://docs.oracle.com/javase/9/whatsnew/toc.htm


2.3 Java 10

参考资料

https://baijiahao.baidu.com/s?id=1594437679552808575&wfr=spider&for=pc

https://blog.csdn.net/visant/article/details/79778967

https://www.oracle.com/technetwork/java/javase/10-relnote-issues-4108729.html


2.3.1. 局部变量类型推断


局部变量类型推断可以说是Java 10中最值得注意的特性,这是Java语言开发人员为了简化Java应用程序的编写而采取的又一步,如下图所示。


aHR0cHM6Ly9zczAuYmFpZHUuY29tLzZPTldzamlwMFFJWjh0eWhucS9pdC91PTg0NzQwNzIyOCwyNjM4MzEwNTI0JmZtPTE3MyZzPTNBOTE4MTRDQkZFNDlGNjA1RUQxNUMwRjAzMDA3MEMzJnc9NDY1Jmg9MTY5JmltZy5KUEc.png


这个新功能将为Java增加一些语法糖 - 简化它并改善开发者体验。新的语法将减少与编写Java相关的冗长度,同时保持对静态类型安全性的承诺。


局部变量类型推断将引入"var"关键字,也就是你可以随意定义变量而不必指定变量的类型,如:


将被下面这个新语法所取代:


看完是不是有点JS的即视感???越来越像JS了吗?!虽然类型推断在Java中不是一个新概念,但在局部变量中确是很大的一个改进。


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


局部变量类型推荐仅限于如下使用场景:

  • 局部变量初始化
  • for循环内部索引变量
  • 传统的for循环声明变量


Java官方表示,它不能用于以下几个地方:

  • 方法参数
  • 构造函数参数
  • 方法返回类型
  • 字段捕获表达式(或任何其他类型的变量声明)


2.3.2. GC改进和内存管理


JDK 10中有2个JEP专门用于改进当前的垃圾收集元素。

第一个垃圾收集器接口是(JEP 304),它将引入一个纯净的垃圾收集器接口,以帮助改进不同垃圾收集器的源代码隔离。


预定用于Java 10的第二个JEP是针对G1的并行完全GC(JEP 307),其重点在于通过完全GC并行来改善G1最坏情况的等待时间。G1是Java 9中的默认GC,并且此JEP的目标是使G1平行。


2.3.3. 线程本地握手(JEP 312)


JDK 10将引入一种在线程上执行回调的新方法,因此这将会很方便能停止单个线程而不是停止全部线程或者一个都不停。


2.3.4. 备用内存设备上的堆分配(JEP 316)


允许HotSpot VM在备用内存设备上分配Java对象堆内存,该内存设备将由用户指定。

2.3.5. 其他Unicode语言 - 标记扩展(JEP 314)


目标是增强java.util.Locale及其相关的API,以便实现语言标记语法的其他Unicode扩展(BCP 47)。


2.3.6. 基于Java的实验性JIT编译器

Oracle希望将其Java JIT编译器Graal用作Linux / x64平台上的实验性JIT编译器。

2.3.7. 根证书(JEP 319)

这个的目标是在Oracle的Java SE中开源根证书。

2.3.8. 根证书颁发认证

这将使OpenJDK对开发人员更具吸引力,它还旨在减少OpenJDK和Oracle JDK构建之间的差异。

2.3.9. 将JDK生态整合单个存储库(JEP 296)

此JEP的主要目标是执行一些内存管理,并将JDK生态的众多存储库组合到一个存储库中。

2.3.10. 删除工具javah(JEP 313)

从JDK中移除了javah工具,这个很简单并且很重要。


其他可参考:

https://www.oracle.com/technetwork/java/javase/10-relnote-issues-4108729.html#NewFeature


2.4 Java 11

参考资料

https://blog.csdn.net/weixin_38055381/article/details/82865385

https://openjdk.java.net/projects/jdk/11/


2.4.1 本地变量类型推断

什么是局部变量类型推断?

var javastack = "javastack";

System.out.println(javastack);


大家看出来了,局部变量类型推断就是左边的类型直接使用 var 定义,而不用写具体的类型,编译器能根据右边的表达式自动推断类型,如上面的 String 。


var javastack = "javastack";

就等于:

String javastack = "javastack";


2.4.2 字符串加强

Java 11 增加了一系列的字符串处理方法,如以下所示。

// 判断字符串是否为空白

" ".isBlank(); // true

// 去除首尾空格

" Javastack ".strip(); // "Javastack"

// 去除尾部空格

" Javastack ".stripTrailing(); // " Javastack"

// 去除首部空格

" Javastack ".stripLeading(); // "Javastack "

// 复制字符串

"Java".repeat(3);// "JavaJavaJava"

// 行数统计

"A\nB\nC".lines().count(); // 3


2.4.3 集合加强


自 Java 9 开始,Jdk 里面为集合(List/ Set/ Map)都添加了 of 和 copyOf 方法,它们两个都用来创建不可变的集合,来看下它们的使用和区别。

示例1:

var list = List.of("Java", "Python", "C");
var copy = List.copyOf(list);
System.out.println(list == copy); // true

示例2:

1. var list = new ArrayList<String>();
2. var copy = List.copyOf(list);
3. System.out.println(list == copy); // false


示例1和2代码差不多,为什么一个为true,一个为false?

来看下它们的源码:

static <E> List<E> of(E... elements) {
  switch (elements.length) { // implicit null check of elements
    case 0:
        return ImmutableCollections.emptyList();
    case 1:
        return new ImmutableCollections.List12<>(elements[0]);
    case 2:
        return new ImmutableCollections.List12<>(elements[0], elements[1]);
    default:
        return new ImmutableCollections.ListN<>(elements);
  }
}
static <E> List<E> copyOf(Collection<? extends E> coll) {
    return ImmutableCollections.listCopy(coll);
}
static <E> List<E> listCopy(Collection<? extends E> coll) {
    if (coll instanceof AbstractImmutableList && coll.getClass() != SubList.class) {
        return (List<E>)coll;
    } else {
        return (List<E>)List.of(coll.toArray());
    }
}



可以看出 copyOf 方法会先判断来源集合是不是 AbstractImmutableList 类型的,如果是,就直接返回,如果不是,则调用 of 创建一个新的集合。


示例2 因为用的 new 创建的集合,不属于不可变 AbstractImmutableList 类的子类,所以 copyOf 方法又创建了一个新的实例,所以为false.


注意:使用of和copyOf创建的集合为不可变集合,不能进行添加、删除、替换、排序等操作,不然会报 java.lang.UnsupportedOperationException 异常。


上面演示了 List 的 of 和 copyOf 方法,Set 和 Map 接口都有。


2.4.4 Stream 加强

Stream 是 Java 8 中的新特性,Java 9 开始对 Stream 增加了以下 4 个新方法。

1) 增加单个参数构造方法,可为null

Stream.ofNullable(null).count(); // 0


2) 增加 takeWhile 和 dropWhile 方法

1. Stream.of(1, 2, 3, 2, 1)
2. .takeWhile(n -> n < 3)
3. .collect(Collectors.toList()); // [1, 2]

从开始计算,当 n < 3 时就截止。

1. Stream.of(1, 2, 3, 2, 1)
2. .dropWhile(n -> n < 3)
3. .collect(Collectors.toList()); // [3, 2, 1]


这个和上面的相反,一旦 n < 3 不成立就开始计算。


3)iterate重载


这个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。

如果你对 JDK 8 中的 Stream 还不熟悉,可以看之前分享的这一系列教程。


2.4.5 Optional 加强


Opthonal 也增加了几个非常酷的方法,现在可以很方便的将一个 Optional 转换成一个 Stream, 或者当一个空 Optional 时给它一个替代的。

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


2.4.6 InputStream 加强


InputStream 终于有了一个非常有用的方法:transferTo,可以用来将数据直接传输到 OutputStream,这是在处理原始数据流时非常常见的一种用法,如下示例。

var classLoader = ClassLoader.getSystemClassLoader();
var inputStream = classLoader.getResourceAsStream("javastack.txt");
var javastack = File.createTempFile("javastack2", "txt");
try (var outputStream = new FileOutputStream(javastack)) {
    inputStream.transferTo(outputStream);
}

2.4.7 HTTP Client API


这是 Java 9 开始引入的一个处理 HTTP 请求的的孵化 HTTP Client API,该 API 支持同步和异步,而在 Java 11 中已经为正式可用状态,你可以在 java.net 包中找到这个 API。


来看一下 HTTP Client 的用法:

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


上面的 .GET() 可以省略,默认请求方式为 Get!


更多使用示例可以看这个 API,后续有机会再做演示。


现在 Java 自带了这个 HTTP Client API,我们以后还有必要用 Apache 的 HttpClient 工具包吗?


2.4.8 化繁为简,一个命令编译运行源代码

看下面的代码。

// 编译

javac Javastack.java

// 运行

java Javastack

在我们的认知里面,要运行一个 Java 源代码必须先编译,再运行,两步执行动作。而在未来的 Java 11 版本中,通过一个 java 命令就直接搞定了,如以下所示。

java Javastack.java


其他一些改进可以参照:

https://www.oracle.com/technetwork/java/javase/11-relnote-issues-5012449.html#NewFeature

2.5 Java 12


参考资料

https://zhuanlan.zhihu.com/p/59798800

2.5.1 switch 表达式

Java 12 以后,switch 不仅可以作为语句,也可以作为表达式。

private String switchTest(int i) {
    return switch (i) {
        case 1 -> "1";
        default -> "0";
    };
}


2.5.2 2 默认CDS归档

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

  1. 改进开箱即用的启动时间
  2. 摆脱使用-Xshare:dump。


2.5.3 Shenandoah GC

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


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


2.5.4 JMH 基准测试


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


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


2.5.5 JVM 常量 API


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


2.5.6 G1的可中断 mixed GC


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


G1是一个垃圾收集器,设计用于具有大量内存的多处理器机器。由于它提高了性能效率,g1垃圾收集器最终将取代cms垃圾收集器。


G1垃圾收集器的主要目标之一是满足用户设置的暂停时间。G1采用一个分析引擎来选择在收集期间要处理的工作量。此选择过程的结果是一组称为GC集的区域。一旦GC集建立并且GC已经开始,那么G1就无法停止。


如果G1发现GC集选择选择了错误的区域,它会将GC区域的拆分为两部分(强制部分和可选部分)来切换到处理Mix GC的增量模式。如果未达到暂停时间目标,则停止对可选部分的垃圾收集。


2.5.7 G1归还不使用的内存


此功能的主要目标是改进G1垃圾收集器,以便在不活动时将Java堆内存归还给操作系统。 为实现此目标,G1将在低应用程序活动期间定期生成或持续循环检查完整的Java堆使用情况。


这将立即归还未使用的部分Java堆内存给操作系统。 用户可以选择执行FULL GC以最大化返回的内存量。


2.5.8移除多余ARM64实现


Java 12将只有一个ARM 64位实现(aarch64)。 目标是删除所有与arm64实现相关的代码,同时保留32位ARM端口和64位aarch64实现。


这将把重点转移到单个64位ARM实现,并消除维护两个实现所需的重复工作。 当前的JDK 11实现中有两个64位ARM实现。


其他一些改进可以参照:


https://www.oracle.com/technetwork/java/javase/12-relnote-issues-5211422.html#NewFeature



三、其他参考资料


https://gudong.name/2019/04/05/android-why-java-harmony.html

https://juejin.im/post/5ca1c747e51d45761c7441fa

https://www.zhihu.com/question/19646618

www.zh.wikipedia.org/wiki/Java版本歷史

https://www.baeldung.com/oracle-jdk-vs-openjdk


目录
相关文章
|
5月前
|
Java 中间件 测试技术
java依赖冲突解决问题之jar包版本冲突无法通过升降级解决时如何解决
java依赖冲突解决问题之jar包版本冲突无法通过升降级解决时如何解决
|
5月前
|
Java 应用服务中间件 Windows
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
【应用服务 App Service】App Service 中部署Java项目,查看Tomcat配置及上传自定义版本
|
2月前
|
Java Linux Windows
如何查看已安装的 Java 版本
要查看已安装的 Java 版本,打开命令提示符或终端,输入 `java -version`,回车后即可显示当前系统中 Java 的版本信息。
998 1
|
2月前
|
Ubuntu Java Linux
如何检查 Java 版本是否兼容
要检查Java版本是否兼容,可在命令行输入“java -version”查看当前安装的Java版本,然后对比目标应用所需的Java版本,确保其满足要求。
90 1
|
3月前
|
缓存 Java Maven
java: 警告: 源发行版 11 需要目标发行版 11 无效的目标发行版: 11 jdk版本不符,项目jdk版本为其他版本
如何解决Java项目中因JDK版本不匹配导致的编译错误,包括修改`pom.xml`文件、调整项目结构、设置Maven和JDK版本,以及清理缓存和重启IDEA。
71 1
java: 警告: 源发行版 11 需要目标发行版 11 无效的目标发行版: 11 jdk版本不符,项目jdk版本为其他版本
|
3月前
|
Java Docker 容器
java版本学习网站又添加了一个libgdx模块
java版本学习网站之前添加了docker,想了想还是再把libgdx添加进去吧。
41 3
|
4月前
|
Java
java版本详解
java版本详解
|
3月前
|
Java Maven Spring
查看springboot版本支持最高的java版本
截至最近更新,Spring Boot 3.0及以上版本支持的最高Java版本为Java 17。鉴于技术的不断演进,建议直接参考Spring Boot的官方文档获取最准确的支持信息,因为这些版本兼容性可能会随着新版本的发布而有所变化。选择与你的Spring Boot版本相匹配的Java版本,可以确保充分利用框架特性,同时保证项目的稳定性和前瞻性。
122 0
|
3月前
|
Java Linux Maven
用sdkman在linux上管理多个java版本
本文介绍了如何在Linux上使用SDKMAN来管理多个Java版本,包括安装SDKMAN、验证安装、列出和安装不同版本的JDK、Maven和Gradle,以及如何切换使用不同版本。
95 0
|
4月前
|
Java API 开发工具
Java不同的版本
Java不同的版本Java不同的版本
46 4
下一篇
开通oss服务