Java 在过去 6 年中的进步(从 Java 8 到 Java 15)
Java 发布周期
Java 8 最重要的特性及示例
Java 9 最重要的特性及示例
Java 10 个最重要的特性及示例
Java 11 最重要的特性及示例
Java 12 最重要的特性及示例
Java 14 个最重要的特性及示例
Java 15 个最重要的特性及示例
结论
Java 发布周期
直到版本 8 之前,Java 版本发布频率都是每 3 年一次,因此版本数量少但功能丰富。
因此,由于包含大量更改,发布新版本的 Java 变得很复杂,开发人员升级其应用程序也变得很复杂。
这种节奏已经跟不上IT世界的现实了,一切都在加速发展!所以Java架构师决定每6个月发布一个版本(因此这是一个固定的时间表)。
在每个版本中,都包含所有准备好的功能,尚未准备好的功能将在下一个版本中提供(不再有后期版本)。
Java 8 最重要的特性及示例
1)Java 语言的新特性
● forEach() 方法
Java 8 在 java.lang.Iterable 接口中引入了 forEach 方法,以便在编写代码时我们只关注业务逻辑。
● Lambda 表达式
Java 8 最大的新特性就是在语言层面支持 Lambda 表达式(Project Lambda)。Lambda
表达式的语法是 (argument) -> (body)。
●接口的默认方法和静态方法
在java 8之前,java中的接口只能有抽象方法,接口的所有方法默认都是public&abstract的,java 8允许接口有默认方法和静态方法。
-默认方法:接口中存在默认方法的原因是允许开发人员向接口添加新方法,而不会影响实现这些接口的类。
静态方法:接口中的静态方法与默认方法类似,只是我们不能在实现这些接口的类中重写这些方法。
例如,新的 Stream 接口上就有很多静态方法。这使得“辅助”方法更容易找到,因为它们可以直接在接口上找到,而不是
像 StreamUtil 或 Streams 这样的其他类中。
●函数式接口:
在 Java 8 中,函数式接口被定义为只有一个抽象方法的接口。这甚至适用于 Java 早期版本创建的接口。Java
8 在 java.util.function 包中引入了几个新的函数式接口。
-Function - 接受一个 T 类型的对象并返回 R。
-Supplier - 只返回一个 T 类型的对象。
-Predicate - 根据 T 类型的输入返回布尔值。
-Consumer - 使用给定的 T 类型对象执行操作。
●方法引用
方法引用是一种特殊的 Lambda 表达式。它们通常用于通过引用现有方法来创建简单的 Lambda 表达式。
方法引用分为四种类型:
-静态方法
-特定对象的实例方法
-特定类型的任意对象的实例方法
-构造
函数 示例:
2)Java 库中的新特性
● Stream API
Stream 接口是 Java 8 的一个基础部分。
我们可以使用 Java Stream API 来实现内部迭代,这样更好,因为 Java 框架可以控制迭代。
Stream 接口支持 map/filter/reduce 模式并延迟执行,形成了
Java 8 中函数式编程的基础(与 lambda 一起)。
出于性能原因,还有相应的原始流(IntStream,DoubleStream和LongStream)。
在 Java 8 中,Collection 接口有两种方法来生成 Stream:
-stream():返回以集合为源的顺序流。
-parallelStream() :返回以集合为源的并行流。
● Optional
Java 8 在 java.util 包中附带了 Optional 类,用于避免返回空值(从而避免 NullPointerException)。
如果值存在,isPresent() 将返回 true,get() 将返回该值。流终端操作返回 Optional 对象。
其中一些方法包括:
-Optional reduce(BinaryOperator accumulator)
-Optional min(Comparator<? super T> comparator)
-Optional max(Comparator<? super T> comparator)
-Optional findFirst()
-Optional findAny()
●日期/时间 API
Java 8 引入了新的日期时间 API,以弥补旧日期时间 API 的以下缺点:
- 非线程安全
- 设计
不佳 - 时区处理困难
Java 8 日期时间 API 由以下包组成:
1.java.time 包:这是新 Java 日期时间 API 的基础包。例如 LocalDate、LocalTime、LocalDateTime、Instant、Period、Duration 等。所有这些类都是不可变的和线程安全的。
- java.time.chrono 包:此包定义了非 ISO 日历系统的通用 API。我们可以扩展 AbstractChronology 类来创建自己的日历系统。
- java.time.temporal 包:此包包含时间对象,我们可以使用它来查找与日期/时间对象相关的特定日期或时间。例如,我们可以用它们来找出月份的第一天或最后一天。您可以轻松识别这些方法,因为它们的格式始终为“withXXX”。
- java.time.zone 包:此包包含支持不同时区及其规则的类。
Java 9 最重要的特性及示例
Java 9 包括对多 GB 堆的更好支持、更好的本机代码集成、不同的默认垃圾收集器(G1,用于“更短的响应时间”)和自调整 JVM。
● Java 平台模块系统(Jigsaw 项目)
这是一种新型的 Java 编程组件,可用于收集 Java 代码(类和包)。该项目的主要目标是轻松地将应用程序缩减到适合小型设备。在 Java 9 中,JDK 本身被划分为多个模块,使其更加轻量级。这也使我们能够开发模块化应用程序。
● JShell:交互式 Java REPL
JShell 是一个 REPL(读取、求值、打印、循环)工具,可以从命令行运行。
它是一个交互式 Java Shell 工具,允许我们从 Shell 执行 Java 代码并立即显示输出。
●进程 API 改进
Java 在 Java 9 版本中改进了其进程 API,添加了几个新的类和方法来简化控制和管理。
进程 API 中有两个新接口:
- java.lang.ProcessHandle
- java.lang.ProcessHandle.Info
●接口私有方法
在 Java 9 中,我们可以在接口内部创建私有方法。接口允许我们声明私有方法,这有助于在非抽象方法之间共享公共代码。
● Java 集合工厂方法
工厂方法是一种特殊类型的静态方法,用于创建不可修改的集合实例。这意味着我们可以使用这些方法创建包含少量元素的列表、集合和映射。由于
它们是不可修改的,因此添加新元素将抛出 java.lang.UnsupportedOperationException。
● Stream API 改进
Streams API 可以说是 Java 标准库长期以来最出色的改进之一。
在 Java 9 中,Stream API 得到了改进,在 Stream 接口中添加了 4 个新方法:iterate()、dropWhile()、takeWhile()、ofNullable()。
●反应式流
Java SE 9 反应式流 API 是一个发布/订阅框架,用于实现异步、可扩展和并行应用程序。
反应式流涉及流的异步处理,因此应该有一个发布者和一个订阅者。发布者发布数据流,订阅者消费数据。
● HTTP 2 客户端
Java 9 引入了一种执行 HTTP 调用的新方式。这个姗姗来迟的旧 HttpURLConnection API 替代品也支持 WebSockets 和 HTTP/2 协议。
它同时支持同步(阻塞模式)和异步模式。
● G1 垃圾收集器
“垃圾优先”垃圾收集器(简称 G1)是一种并发多线程 GC。它主要与应用程序线程协同工作(类似于并发标记清除 GC),旨在提供更短、更可预测的暂停时间,同时仍保持高吞吐量。
●其他新功能
-Stack-Walking API
-过滤传入的序列化数据
-弃用 Applet API
-指定字符串连接
-增强方法句柄
-Java 平台日志 API 和服务
-紧凑字符串
-Nashorn 的解析器 API -Javadoc
搜索
-HTML5 Javadoc
Java 10 个最重要的特性及示例
Java 10 是 Java 23 年历史上发布速度最快的版本。Java 一直因其发展和演进缓慢而受到批评,但 Java 10 恰恰打破了这一观念。
●局部变量类型推断
局部变量类型推断是 Java 10 中对开发者来说最大的新功能。
与 Javascript、Kotlin 和 Scala 类似,现在 Java 也新增了一个 var 关键字,允许你在声明局部变量时不指定其类型。
●基于时间的版本控制
从 JDK 10 开始,Java 采用了每六个月发布一次新版本的计划。这种方法是否切实可行存在诸多争议,大型公司也对 Java 迄今为止的稳定性和较低的更新频率表示赞赏。
Oracle 已回应了这些问题,并将继续
定期提供长期版本,但
间隔时间也会更长。继 Java 8 之后,Java 11 将
再次获得长期支持。
事实上,由于
Java 11 已经发布,Java 9 和 Java 10 的支持刚刚结束。
●应用程序类数据共享
此功能扩展了现有的 CDS 功能,允许将应用程序类放置在共享档案中,以改善启动和占用空间。
总体思路是,当 JVM 首次启动时,所有加载的内容都会被序列化并存储在磁盘上的文件中,以便将来启动 JVM 时重新加载。
这意味着 JVM 的多个实例共享类元数据,因此不必每次都加载它们。
● G1 的并行完整 GC
G1 垃圾收集器在 JDK 9 中成为默认设置。但是,G1 的完整 GC 使用了单线程标记、清除和压缩算法。
在 Java 10 中,这已更改为并行标记-清除-压缩算法,
有效地减少了完整 GC 期间的停止时间。
这种变化不会对垃圾收集器的最佳性能时间产生帮助
,但它确实显著减少了最坏情况的
延迟。
●垃圾收集器接口
这是 Java 10 的另一个有趣且有用的功能,它通过引入通用垃圾收集器接口来改善不同垃圾收集器的代码隔离。
它将有助于将来在不改变现有代码库的情况下添加新的 GC,也有助于删除或管理以前的 GC。
●根证书
在 Java 10 中,Oracle 开源了
Oracle Java SE Root CA 程序中的根证书,以使 OpenJDK 构建
对开发人员更具吸引力,并减少
这些构建与 Oracle JDK 构建之间的差异。
●线程局部握手
这是 JVM 的一个内部特性,用于提升性能。
该特性提供了一种在线程上执行回调的方法,而无需执行全局 VM 安全点。这使得停止单个线程(而不是全部线程或全部不停止)变得可行且成本低廉。
●新增 API
- List、Map 和 Set 接口新增静态 copyOf(Collection) 方法。该方法返回一个包含指定条目的不可修改的 List、Map 或 Set。对于 List,如果给定的 List 随后被修改,则返回的 List 将不会反映此类修改。
-Optional 及其原始变体 get 一个方法 orElseThrow()。这与 get() 完全相同,然而 Java 文档指出,它是比 get() 更佳的替代方案。
-Collectors 类获得了用于收集不可修改集合(Set、List、Map)的各种方法。
Java 11 最重要的特性及示例
Java 11 是继 Java 8 之后的第二个 LTS 版本。从 Java 11 开始,Oracle JDK 将不再免费用于商业用途。
●运行 Java 文件
我们可以省去编译阶段。只需一条命令即可完成编译和执行。我们使用 java 命令。它会隐式地进行编译,而无需保存 .class 文件。
● Java 字符串方法
1) isBlank():如果字符串为空或仅包含空格代码点,则此方法返回 true。
2)lines():返回一个字符串流的引用,该字符串流是我们按行拆分后收到的子字符串。
3) strip()、stripLeading() 和 stripTrailing():从字符串的开头、结尾和末尾删除空格。它是 trim() 的“Unicode 感知”演变版本;
4) repeat():方法按照接收到的次数重复调用该字符串。
●在 Lambda 表达式中使用 var
从 Java 11 开始,我们可以在 lambda 表达式中使用 var 关键字。
在 lambda 表达式中使用 var 时,我们必须在所有参数上使用它,并且不能将它与使用特定类型混合使用。
●基于嵌套的访问控制
在 Java 11 之前,Java 允许类和接口相互嵌套。这些嵌套类型彼此之间具有不受限制的访问权,包括对私有字段、方法和构造函数的访问。
从 Java 11 开始,Class 类中新增了一些方法,可以帮助我们获取已创建嵌套对象的信息。这些方法包括:
getNestHost():返回此 Class 对象所属嵌套对象的宿主;
getNestMembers():返回一个包含 Class 对象的数组,这些 Class 对象表示此 Class 对象所属嵌套对象的所有成员;
isNestemateOf():确定给定的 Class 是否是此 Class 对象的嵌套对象
● Epsilon:无操作垃圾收集器
从 Java 11 开始,JVM 具有一项实验性功能,允许我们在没有任何实际内存回收的情况下运行 JVM。
目标是提供一个完全被动的垃圾收集器实现,具有有限的分配限制和尽可能低的延迟开销。
● ZGC 可扩展低延迟 GC
从 Java 11 开始,我们可以使用 ZGC。这个新的 GC 目前作为一项实验性功能提供。ZGC
是一个可扩展的低延迟垃圾收集器。它可以并发执行高开销的任务,而不会使应用程序线程的执行停止超过 10 毫秒。
● HTTP 客户端
从 Java 11 开始,HTTP 客户端 API 更加标准化。新的 API 同时支持 HTTP/1.1 和 HTTP/2。新的 API 还支持 HTML5 WebSockets。
●文件读写
Java 11 引入了两种新方法,可显著帮助从文件读取和写入字符串:readString()、writeString()
● Flight Recorder
Flight Recorder 以前是 Oracle JDK 中的商业附加组件,现在已开源,因为 Oracle JDK 本身不再免费。
JFR 是一种分析工具,用于从正在运行的 Java 应用程序收集诊断和分析数据。
它的性能开销可以忽略不计,通常低于 1%。因此,它完全可以用于生产环境。
Java 12 最重要的特性及示例
Java 12 于 2019 年 3 月 19 日发布,属于六个月发布周期的一部分。
它是一个非 LTS 版本。因此,它不会获得长期支持。
● JVM 变化
——Shenandoah 低暂停时间垃圾收集器:Java 12 添加了 Shenandoah,这是一种实验性的垃圾收集算法,通过在运行 Java 线程的同时执行疏散工作来减少垃圾收集暂停时间。
及时归还未使用的已提交内存:G1 在 Java 堆内存空闲时自动将其归还给操作系统。当应用程序活动非常少时,这些内存会在合理的时间内释放。
G1 的可中止混合收集:G1 效率的改进包括:当 G1 混合收集可能超出定义的暂停目标时,使其可中止。这是通过将混合收集集合拆分为强制收集和可选收集来实现的。
-默认 CDS 存档:最终目标是通过生成类数据共享 (CDS) 存档来改进 JDK 构建过程。此功能的目标包括:
1) 缩短开箱即用的启动时间。2
) 无需运行 -Xshare: dump 即可使用 CDS。
● Switch 表达式
此 JEP 对 Java 中的 switch 进行了两项主要更改:
1) 引入 case L -> 语法,从而无需 break 语句,因为只执行 -> 后面的语句。2
) switch 可以是表达式,因此它可以有一个值,也可以返回一个值。
● File.mismatch 方法
Java 12 添加了以下方法来比较两个文件:
此方法返回第一个不匹配的位置,如果没有不匹配则返回 -1L。
●紧凑数字格式
Java 12 扩展了现有的数字格式 API,以支持区域敏感的紧凑数字格式。
现在,例如 1000 这样的数字可以格式化为“1K”(短格式)或“1 千”(长格式)。
● Teeing Collectors
Teeing Collector 是 Streams API 中引入的全新收集器工具。
该收集器有三个参数——两个收集器和一个双函数。
所有输入值都会传递给每个收集器,并在双函数中获取结果。
● Java 字符串新方法
1)java.lang.String:
-indent(int n):根据 n 的值调整此字符串每行的缩进,并规范化行终止字符。
-如果 n > 0,则在每行开头插入 n 个空格(U+0020)。-
如果 n < 0,则从每行开头删除最多 n 个空格。如果某一行的空格不足,则所有前导空格都将被删除。制表符也被视为单个字符。-
如果 n = 0,则该行保持不变。但是,行终止符仍然会被规范化。
- R transform(Function<? super String,? extends R> f):此方法允许将函数应用于此字符串。
2)JVM常量API:
常量 API 方法对于正常的开发相关任务没有太多用处。
-Optional describeConstable():返回一个包含此实例的名义描述符的 Optional,即实例本身。
-String resolveConstantDesc(MethodHandles.Lookup lookup):将此实例解析为 ConstantDesc,其结果就是实例本身。
Java 13 于 2019 年 9 月 17 日发布用于生产用途。由于 6 个月的发布周期,Java 13 中没有很多特定于开发人员的功能。
● Switch 表达式
我们最初在 JDK 12 中看到了 switch 表达式。Java 13 的 switch 表达式在之前的版本的基础上添加了一个新的 yield 语句。
●文本块
用于多行字符串(例如嵌入式 JSON、XML、HTML 等)的文本块。它使我们能够轻松创建多行字符串。多行字符串必须写在一对三重双引号内。
之前,为了将 JSON 嵌入到我们的代码中,我们将其声明为字符串文字:
现在,它有助于在我们的 Java 程序中轻松创建 HTML 和 JSON 字符串:
此外,java.lang.String 现在增加了三种操作文本块的新方法:
1) formatted(Object…args):类似于 String 的 format() 方法。添加此方法是为了支持使用文本块进行格式化。
2) stripIndent():用于删除文本块中每行开头和结尾的空白字符。此方法由文本块使用,并保留内容的相对缩进。
3)translateEscapes():返回一个字符串,其值为该字符串,其中转义序列被翻译为字符串文字。
●动态 CDS 存档
类数据共享 (CDS) 一直是 Java HotSpot VM 的一项重要功能。它允许在不同的 JVM 之间共享类元数据,从而减少启动时间和内存占用。
现在,创建和使用 CDS 存档变得更加容易。
● ZGC:取消提交未使用的内存。Z
垃圾收集器是 Java 11 中引入的低延迟垃圾收集机制。它在堆内存清理之前增加了短暂的暂停时间。但是,未使用的内存并没有被归还给操作系统。
从 Java 13 开始,ZGC 现在默认将未提交的内存返回给操作系统。
● FileSystems.newFileSystem() 方法
FileSystems 类中添加了三种新方法,以便更轻松地使用文件系统提供程序,将文件的内容视为文件系统:
-newFileSystem(Path)
-newFileSystem(Path, Map)
-newFileSystem(Path, Map, ClassLoader)
●具有命名空间支持的 DOM 和 SAX 工厂
有新方法可以实例化具有命名空间支持的 DOM 和 SAX 工厂:
-newDefaultNSInstance()
-newNSInstance()
-newNSInstance(String factoryClassName, ClassLoader classLoader)
●其他变化
Java 13 为我们带来了一些更显著的变化:
-java.time – 添加了新的日本官方时代名称
-javax.crypto – 支持 MS Cryptography Next Generation (CNG)
-javax.security – 添加属性 jdk.sasl.disabledMechanisms 以禁用 SASL 机制
-javax.xml.crypto – 引入新的字符串常量来表示规范 XML 1.1 URI
-javax.xml.parsers – 添加了新方法来实例化具有命名空间支持的 DOM 和 SAX 工厂
-Unicode 支持升级到版本 12.1
- 添加了对 Kerberos 主体名称规范化和跨领域引用的支持
Java 14 个最重要的特性及示例
按照六个月周期的传统,另一个非 LTS 版本 Java 14 计划于 2020 年 3 月 17 日发布。
●切换表达式
切换表达式在过去两个版本(Java 12 和 Java 13)中作为预览功能存在后,终于在 Java 14 中获得了永久地位。
●针对instanceof 的模式匹配
将一个类型转换为另一个类型的旧方法是:
新方法是:
在上面的代码中,只有当 obj 的类型为 Journaldev 时,实例 jd 才会被赋值。该变量的作用范围仅限于条件块。
●有用的 NullPointerExceptions
改进了 JVM 生成的 NullPointerExceptions 异常消息。
Java 14 之前:
Java 14 引入了一项新的 JVM 功能,它通过更具描述性的堆栈提供更好的洞察力,如下所示:
●记录
我们需要编写大量低价值、重复的代码来负责任地编写一个简单的数据载体类:构造函数、访问器、equals()、hashCode()、toString() 等。为了避免这些重复的代码,Java 计划使用记录。
Java 14 之前:
Java 14 之后:
此外,我们可以通过以下方式向记录添加额外的字段、方法和构造函数:
关于记录,需要注意以下几点:
-记录既不能扩展类,也不能被其他类扩展。它是一个 final 类。-
记录可以实现接口。-
记录支持多个构造函数。-
记录允许修改访问器方法。-
记录不能是抽象的。-
记录不能扩展任何其他类,也不能在主体内定义实例字段。实例字段只能在状态描述中定义。-
声明的字段是私有的和 final 的。-
记录主体允许使用静态字段和方法。
●文本块
文本块是 Java 13 中作为预览功能引入的,旨在轻松创建多行字符串文字。它有助于轻松创建 HTML、JSON 或 SQL 查询字符串。
在 Java 14 中,文本块仍处于预览阶段,并新增了一些功能:
- 反斜杠用于显示美观的多行字符串块。-
\s 用于考虑编译器默认忽略的尾随空格。它会保留其前面的所有空格。
●外部内存访问 API
Java 14 JDK 中将引入一个高效的 Java API,使 Java 应用程序能够安全高效地访问 Java 堆外部的外部内存。该 API 引入了三个主要抽象:MemorySegment、MemoryAddress 和 MemoryLayout。
Java 15 个最重要的特性及示例
Java 15(Java SE 15)及其 Java 开发工具包 15(JDK 15)开源已于 2020 年 9 月 15 日发布。
●密封类
密封类在 Kotlin 中已经存在一段时间了,Java 15 终于引入了此功能,以便更好地控制继承。可以使用seal
修饰符 来密封一个类。
因此,上述代码的意思是,只有在关键字permits之后定义的类才被允许扩展 Vehicle 密封类。
每个允许的类都必须使用显式修饰符进行设置。它可以是 final 的、密封的或非密封的:
- 声明为 final 的允许子类无法进一步扩展。-
声明为 seal 的允许子类可以进一步扩展,但只能通过子类允许的类进行扩展。-
允许的子类可以声明为非密封的,并且可以通过任何类进行扩展。超类无法限制此类层次结构中更低级别的子类。
●隐藏类
虽然大多数开发人员不会从中直接受益,但使用动态字节码或 JVM 语言的任何人都可能会发现它们很有用。
隐藏类的目标是允许运行时创建不可发现的类。
此类类通常具有较短的生命周期,因此隐藏类被设计为能够高效地加载和卸载。
●外部内存 API
外部内存访问已经是 Java 14 的一个孵化功能。在 Java 15 中,目标是继续其孵化状态,同时添加几个新功能:
- 新的 VarHandle API,用于自定义内存访问 var 句柄
- 支持使用 Spliterator 接口并行处理内存段
- 增强对映射内存段的支持
- 能够操作和取消引用来自本机调用等的地址
●垃圾收集器
在 Java 15 中,ZGC 和 Shenandoah 将不再处于实验阶段。两者都将成为团队可以选择使用的受支持配置,而 G1 收集器仍将为默认收集器。
● Nashorn JavaScript 引擎
值得注意的是,最初在 Java 8 中引入的 Nashorn JavaScript 引擎现已被移除。随着最近 GraalVM 和其他 VM 技术的推出,很明显 Nashorn 在 JDK 生态系统中不再占有一席之地。
结论
本文介绍了 Java 从 Java 8 到 Java 15 的演变。
自六年前 Java 8 发布以来,Java 作为一种语言和生态系统已经发生了巨大的变化,它添加了许多新功能,使 Java 与其他基于 JVM 的竞争对手相比更具竞争力。
文章来源:https://dev.to/wejdi_gh/how-java-has-advanced-in-the-past-6-years-from-java-8-to-java-15-4gj3