Java 版本和功能指南
您可以利用本指南获取有关如何查找和安装最新 Java 的实用信息,了解 Java 发行版(AdoptOpenJdk、OpenJDK、OracleJDK 等)之间的差异,以及 Java 语言特性的概述,包括 Java 版本 8-13。
实用信息
首先,让我们来看一些人们在为项目选择合适的 Java 版本时经常遇到的实际问题。
简而言之,我只想知道下载链接,其他信息一概不知。我应该去哪里找?
访问AdoptOpenJDK网站,选择最新的 Java 版本,下载并安装。然后回到本指南,或许还能学到一些关于 Java 版本的知识。
我应该使用哪个Java版本?
截至2019年9月,Java 13是最新发布的Java版本,之后每6个月发布一个新版本。因此,Java 14计划于2020年3月发布,Java 15计划于2020年9月发布,以此类推。过去,Java的发布周期要长得多,甚至长达3-5年!
随着这么多新版本的推出,基本上存在以下这些实际应用场景:
-
公司中的遗留项目通常仍使用 Java 8(参见“为什么公司仍然使用 Java 8? ”)。因此,您也将被迫使用 Java 8。
-
有些遗留项目甚至还停留在 Java 1.5(2004 年发布)或 1.6(2006 年发布)——抱歉了,朋友们!
-
如果您确保使用最新的 IDE、框架和构建工具,并且正在启动一个全新的项目,那么您可以毫不犹豫地使用 Java 11 (LTS) 甚至最新的 Java 13。
-
安卓开发领域比较特殊,Java 版本基本上停留在 Java 7,只有一部分 Java 8 特性可用。或者,你可以转而使用 Kotlin 编程语言。
为什么企业仍然坚持使用 Java 8?
企业仍然坚持使用 Java 8 的原因有很多,以下仅列举部分:
-
构建工具(例如 Maven、Gradle 等)和一些库最初在 Java 版本 8 以上时存在 bug,需要更新。即使在今天,例如 Java 版本 9 及更高版本,某些构建工具在构建 Java 项目时仍然会输出“反射访问”警告,提示项目“尚未准备就绪”,即使构建本身没有问题。
-
在 Java 8 之前,你基本上都是使用 Oracle 的 JDK 版本,无需担心许可问题。然而,Oracle在 2019 年更改了许可方案,这导致网络上充斥着大量文章,声称“Java 不再免费了”,并引发了不少混乱。但这其实并非什么大问题,你将在本指南的“Java 发行版”部分了解到相关内容。
-
有些公司制定了只使用 LTS 版本的政策,并依赖操作系统供应商提供这些版本,这需要时间。
总而言之:你面临着实际问题(升级工具、库、框架)和政治问题。
为什么有些 Java 版本,例如 8,也称为 1.8?
9 之前的 Java 版本只是采用了不同的命名规则。因此,Java 8 也可以称为1.8,Java 5 也可以称为1.5,以此类推。当你运行 `java -version` 命令时,对于这些版本,你会得到类似这样的输出:
c:\Program Files\Java\jdk1.8.0_191\bin>java -version
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)
这其实就是指 Java 8。随着 Java 9 开始采用基于时间的发布方式,命名规则也发生了变化,Java 版本不再以 1.x 为前缀。现在的版本号格式如下:
c:\Program Files\Java\jdk11\bin>java -version
openjdk version "11" 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
Java 不同版本之间有什么区别?我应该学习某个特定的版本吗?
如果你之前使用过其他编程语言,比如 Python 2 到 3,这些语言在版本更新之间会有很大的差异,你可能会想知道 Java 是否也存在同样的问题。
在这方面,Java 非常特殊,因为它具有极强的向下兼容性。这意味着你的 Java 5 或 8 程序几乎肯定能在 Java 8 到 13 的虚拟机上运行——只有少数例外情况,但你暂时无需担心。
显然反过来就行不通了,假设你的程序依赖于 Java 13 的特性,而这些特性在 Java 8 JVM 下根本无法使用。
这意味着两件事:
-
你不会仅仅“学习”某个特定的 Java 版本,比如 12。
-
相反,你将掌握 Java 8 之前所有语言特性的良好基础。这将为你打下良好的基础。
-
然后,通过像这样的指南,了解Java 9-13 中新增的功能,并尽可能地使用它们。
Java 版本之间的这些新特性有哪些例子?
请参阅Java 特性 8-13部分。
但一般来说:较早的、较长的发布周期(3-5 年,直到 Java 8)意味着每次发布都会有很多新功能。
6 个月的发布周期意味着每次发布的功能要少得多,因此您可以快速掌握 Java 9-13 的语言特性。
JRE 和 JDK 有什么区别?
到目前为止,我们一直在讨论“Java”。但Java究竟是什么呢?
首先,你需要区分JRE(Java 运行时环境)和JDK(Java 开发工具包)。
过去,如果您只想运行 Java 程序,只需下载JRE即可。JRE 包含 Java 虚拟机 (JVM) 和“java”命令行工具等。
要开发新的 Java 程序,你需要下载JDK。JDK包含了JRE 的所有内容,以及编译器javac和其他一些工具,例如javadoc(Java 文档生成器)和jdb(Java 调试器)。
为什么我说话用的是过去时?
在 Java 8 之前,Oracle 网站将 JRE 和 JDK 作为单独的下载提供——尽管 JDK 本身也始终包含一个单独的文件夹中的 JRE。从 Java 9 开始,这种区别基本消失,用户始终下载的是 JDK。JDK 的目录结构也发生了变化,不再包含单独的 JRE 文件夹。
因此,尽管某些发行版(参见“Java 发行版”部分)仍然提供单独的 JRE 下载,但目前似乎流行只提供 JDK。因此,从现在开始,我们将交替使用Java和JDK这两个术语。
那么我该如何安装Java或JDK呢?
暂时忽略 Java-Docker 镜像、.msi 封装包或平台特定的软件包。归根结底,Java 只是一个 .zip 文件,仅此而已。
因此,要将 Java 安装到您的计算机上,您只需解压缩 jdk-{5-13}.zip 文件即可。您甚至不需要管理员权限。
解压后的Java文件看起来会像这样:
Directory C:\dev\jdk-11
12.11.2019 19:24 <DIR> .
12.11.2019 19:24 <DIR> ..
12.11.2019 19:23 <DIR> bin
12.11.2019 19:23 <DIR> conf
12.11.2019 19:24 <DIR> include
12.11.2019 19:24 <DIR> jmods
22.08.2018 19:18 <DIR> legal
12.11.2019 19:24 <DIR> lib
12.11.2019 19:23 1.238 release
神奇的事情发生在 /bin 目录下,在 Windows 系统下,该目录看起来像这样:
Directory C:\dev\jdk-11\bin
...
12.11.2019 19:23 272.736 java.exe
...
12.11.2019 19:23 20.832 javac.exe
...
所以你只需要解压缩该文件,并将 /bin 目录添加到你的 PATH 变量中,这样你就可以从任何地方调用 'java' 命令了。
(如果您想知道的话,像 Oracle 或 AdoptOpenJDK 这样的图形界面安装程序会自动为您解压缩并修改 PATH 变量,仅此而已。)
要验证您是否正确安装了 Java,只需运行“java -version”命令即可。如果输出结果与下方所示类似,则说明安装成功。
openjdk version "11" 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
现在还剩下一个问题:从哪里获取 Java .zip 文件?这就引出了发行版的话题。
Java发行版
有很多网站提供 Java(即 JDK)下载,但“哪些网站提供哪些软件以及采用何种许可协议”并不明确。本节将对此进行阐述。
OpenJDK 项目
就 Java 源代码(即 JRE/JDK 的源代码)而言,只有一个,它位于OpenJDK 项目网站上。
这只是源代码,并非可分发的构建版本(例如:包含适用于您特定操作系统的已编译 Java 命令的 .zip 文件)。理论上,你我可以从该源代码构建一个版本,比如命名为MarcoJDK,然后开始分发。但我们的版本缺乏认证,因此无法合法地称自己为Java SE 兼容版本。
因此,实际上只有少数供应商会创建这些版本,获得认证(参见TCK),然后分发它们。
虽然供应商不能在生成新的 Java 版本之前从 String 类中移除某个方法,但他们可以添加品牌标识(太棒了!)或添加一些他们认为有用的其他实用程序(例如 CLI)。除此之外,所有Java 发行版的原始源代码都是相同的。
OpenJDK 构建(由 Oracle 提供)和 OracleJDK 构建
Oracle是众多从源代码构建Java的供应商之一。这就导致了两种不同的Java发行版,起初可能会让人非常困惑。
-
Oracle 提供的OpenJDK 版本(!)。这些版本免费且无品牌标识,但 Oracle 不会在 Java 14 发布后立即发布对旧版本(例如 Java 13)的更新。
-
OracleJDK是一个带有品牌标识的商业版本,自 2019 年许可协议变更后开始使用。这意味着在开发阶段可以免费使用,但如果用于生产环境则需要向 Oracle 付费。付费用户可获得更长时间的支持,例如版本更新以及 JVM 出现问题时可拨打的客服电话。
历史上(Java 8 之前),OpenJDK 和 OracleJDK 的源代码确实存在差异,当时可以说 OracleJDK “更好”。但如今,这两个版本本质上已经相同,只有一些细微差别。
归根结底,就是你想为已安装的 Java 版本获得付费的商业支持(电话号码)。
AdoptOpenJDK
2017 年,一群 Java 用户组成员、开发人员和供应商(亚马逊、微软、Pivotal、Redhat 等)创建了一个名为AdoptOpenJDK的社区。
他们提供免费、稳定可靠的 OpenJDK 版本,可用性/更新时间更长,甚至还提供两种不同的 Java 虚拟机供您选择:HotSpot和OpenJ9。
如果您想安装 Java,强烈推荐这款软件。
Azul Zulu、Amazon Corretto、SAPMachine
您可以在OpenJDK 维基百科页面上找到完整的 OpenJDK 版本列表。其中包括Azul Zulu、Amazon Corretto和SapMachine等。简单来说,区别在于您享有的不同支持选项/维护保障。
但务必查看各个发行版的网站,了解每种发行版的优势。
推荐
再次重申,在 2019 年,除非您有非常具体的需求,否则请从https://adoptopenjdk.net获取 jdk.zip (.tar.gz/.msi/.pkg) 文件,或者选择您的操作系统供应商提供的软件包。
Java 特性 8-13
正如本指南开头所述:基本上所有(现在不要太挑剔)Java 8 语言特性在 Java 13 中也同样适用。其他所有介于两者之间的 Java 版本也是如此。
这意味着 Java 8 的所有语言特性都可作为非常好的 Java 基础知识,而其他所有版本(Java 9-13)几乎都是在此基础上添加的特性。
以下是各版本功能的简要概述:
- Java 8 -
Java 8 是一个重大版本更新,您可以在Oracle 网站上找到所有功能的列表。不过,这里我想重点介绍两个主要功能:
语言特性:Lambda 等
在 Java 8 之前,每当你想要实例化一个新 Runnable 对象时,你都必须编写一个匿名内部类,如下所示:
Runnable runnable = new Runnable(){
@Override
public void run(){
System.out.println("Hello world !");
}
};
使用 lambda 表达式,相同的代码如下所示:
Runnable runnable = () -> System.out.println("Hello world two!");
你还可以使用方法引用、重复注解、接口的默认方法以及其他一些语言特性。
收藏与流媒体
Java 8 还为集合提供了函数式风格的操作,也称为 Stream API。一个简单的例子:
List<String> list = Arrays.asList("franz", "ferdinand", "fiel", "vom", "pferd");
在 Java 8 之前,你基本上需要编写 for 循环来处理这个列表。
使用 Streams API,您可以执行以下操作:
list.stream()
.filter(name -> name.startsWith("f"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
如果你想练习更多 Java 8 的相关知识
显然,在本指南的范围内,我只能对 Java 8 中新增的 Stream、Lambda 或 Optional 方法进行快速概述。
如果您想要更详细、更全面的概述(包括练习),您可以看看我的Java 8 核心功能课程。
- Java 9 -
Java 9 也是一个相当大的版本,新增了一些功能:
收藏
集合类新增了一些辅助方法,可以更轻松地构建列表、集合和映射。
List<String> list = List.of("one", "two", "three");
Set<String> set = Set.of("one", "two", "three");
Map<String, String> map = Map.of("foo", "one", "bar", "two");
流
Streams 新增了一些功能,包括 takeWhile、dropWhile 和 iterate 方法。
Stream<String> stream = Stream.iterate("", s -> s + "s")
.takeWhile(s -> s.length() < 10);
可选
可选类型终于获得了期待已久的 ifPresentOrElse 方法。
user.ifPresentOrElse(this::displayAccount, this::displayLogin);
接口
接口可以有私有方法:
public interface MyInterface {
private static void myPrivateMethod(){
System.out.println("Yay, I am private!");
}
}
其他语言特性
还有一些其他的改进,例如改进的 try-with-resources 语句或菱形运算符扩展。
JShell
最后,Java 有了一个 shell,你可以在其中尝试简单的命令并立即获得结果。
% jshell
| Welcome to JShell -- Version 9
| For an introduction type: /help intro
jshell> int x = 10
x ==> 10
HTTP客户端
Java 9 引入了新的 HttpClient 的初始预览版。在此之前,Java 内置的 Http 支持相当底层,用户不得不使用像 Apache HttpClient 或 OkHttp 这样的第三方库(顺便说一句,这些都是很棒的库!)。
Java 9 为 Java 带来了自己的现代化客户端——尽管目前处于预览模式,这意味着在以后的 Java 版本中可能会有所改变。
项目拼图:Java 模块和多版本 Jar 文件
Java 9 引入了Jigsaw 模块系统,它与经典的OSGi 规范有些类似。本指南篇幅有限,无法详细介绍 Jigsaw,但您可以参考前面的链接了解更多信息。
多版本 .jar 文件允许一个 .jar 文件包含针对不同 JVM 版本的不同类。因此,例如,您的程序在 Java 8 和 Java 10 上运行时,其行为可能有所不同,使用的类也可能不同。
如果你想练习更多 Java 9 的相关知识
再次强调,这只是对 Java 9 特性的快速概述,如果您想要更深入的解释和练习,请查看Java 9 核心特性课程。
- Java 10 -
Java 10 有一些变化,例如垃圾回收等。但作为开发人员,您可能看到的唯一真正变化是引入了“var”关键字,也称为局部变量类型推断。
局部变量类型推断:var-keyword
// Pre-Java 10
String myName = "Marco";
// With Java 10
var myName = "Marco"
感觉很像 JavaScript,对吧?不过它仍然是强类型的,并且只适用于方法内部的变量(感谢dpash再次指出这一点)。
- Java 11 -
从开发者的角度来看,Java 11 也是一个规模相对较小的版本。
字符串和文件
字符串和文件类新增了一些方法(此处并未列出全部方法):
"Marco".isBlank();
"Mar\nco".lines();
"Marco ".strip();
Path path = Files.writeString(Files.createTempFile("helloworld", ".txt"), "Hi, my name is!");
String s = Files.readString(path);
运行源文件
从 Java 10 开始,您可以直接运行 Java 源文件而无需事先编译。这是迈向脚本编写的一步。
ubuntu@DESKTOP-168M0IF:~$ java MyScript.java
lambda 参数的局部变量类型推断 (var)
标题已经说明了一切:
(var firstName, var lastName) -> firstName + lastName
HttpClient
Java 9 的 HttpClient 最终版,非预览版。
其他东西
飞行记录器、No-Op 垃圾回收器、Nashorn-Javascript-Engine 已弃用等。
- Java 12 -
Java 12 增加了一些新功能和改进,但这里只值得一提的是 Unicode 11 支持和新的 switch 表达式预览,您将在下一节中看到相关介绍。
- Java 13 -
您可以在这里找到完整的功能列表,但基本上您将获得 Unicode 12.1 支持,以及两个新的或改进的预览功能(未来可能会有所更改):
切换表达式(预览)
Switch 表达式现在可以返回一个值。而且,您可以使用 lambda 风格的语法来编写表达式,而不会出现 fall-through/break 问题:
旧的 switch 语句看起来像这样:
switch(status) {
case SUBSCRIBER:
// code block
break;
case FREE_TRIAL:
// code block
break;
default:
// code block
}
而在 Java 13 中,switch 语句可以像这样:
boolean result = switch (status) {
case SUBSCRIBER -> true;
case FREE_TRIAL -> false;
default -> throw new IllegalArgumentException("something is murky!");
};
多行字符串(预览)
你终于可以用Java实现这个功能了:
String htmlBeforeJava13 = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
String htmlWithJava13 = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
Java 14 及更高版本
一旦发布,我们将在此处进行报道。请稍后查看。
鳍
现在你应该对以下几件事有了比较清晰的了解:
-
如何安装 Java,应该选择哪个版本以及从哪里获取(提示:AdoptOpenJDK)。
-
什么是 Java 发行版?有哪些 Java 发行版?它们之间有什么区别?
-
不同Java版本之间有哪些区别?
欢迎提出反馈、更正和各种建议!只需在下方留言即可。
感谢阅读。
致谢
Stephen Colebourne 写了一篇关于各种可用 Java 发行版的精彩文章。
还有更多类似的内容。
我会在发布新指南时向您发送更新通知。绝无垃圾邮件。您可以随时取消订阅。点击此处注册新闻邮件:https: //bit.ly/2K0Ao4F
文章来源:https://dev.to/marcobehler/a-guide-to-java-versions-and-features-4m2m
