JDK 8迁移到JDK 11版本指南

Posted Tank的技术博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK 8迁移到JDK 11版本指南相关的知识,希望对你有一定的参考价值。

Java平台,标准版

Oracle JDK迁移指南,官方https://docs.oracle.com/en/java/javase/11/migrate/index.html

第11版

E94894-01

2018年9月

入门

本指南的目的是帮助您识别潜在问题,并在将现有Java应用程序迁移到最新JDK版本时为您提供有关如何继续的建议。该指南还强调了对最新版本所做的重大更改和增强。

本指南包含以下部分:

JDK 11发布的重大变化

在将应用程序迁移到JDK 11之前,您应该了解它与JDK 10版本之间的更新和更改。如果要从JDK 8迁移,则还应熟悉从JDK 8迁移到以后的JDK版本中描述的JDK 8和更高版本之间的差异。

以下是JDK 11中的一些重要更改:

  • Oracle不再提供JRE和Server JRE下载; 因此,自动更新不再可用。

  • Oracle不再提供32位Windows下载。

  • JDK中不提供Java Web Start,Java插件和Java控制面板。请参阅删除部署堆栈

  • JDK中不再包含JavaFX。它现在可以从https://openjfx.io/单独下载。

  • JAXB和JAX-WS不再与JDK捆绑在一起。请参阅删除Java EE和CORBA模块

此外,还需要了解与安全相关的更新以及很少删除的工具和组件。看到:

删除部署堆栈

Java部署技术在JDK 9中已弃用,在JDK 11中已删除。

Java applet和Web Start功能,包括Java插件,Java Applet Viewer,Java控制面板和Java Web Start,以及javaws工具,已在JDK 11中删除。

请参阅 删除Java部署技术

删除Java EE和CORBA模块

在JDK 11中,删除了Java EE和CORBA模块。不推荐在JDK 9中删除这些模块。

删除的模块是:

  • java.xml.ws:用于XML Web服务的Java API(JAX-WS),用于Java平台的Web服务元数据以及用于Java的附件的SOAP(SAAJ)
  • java.xml.bind:用于XML绑定的Java体系结构(JAXB)
  • java.xml.ws.annotation:Java SE定义的JSR-250 Common Annotations的子集,用于支持Web服务
  • java.corba:CORBA
  • java.transaction:Java SE定义的Java Transaction API的子集,用于支持CORBA对象事务服务
  • java.activation:JavaBeans Activation Framework
  • java.se.ee:上面六个模块的聚合器模块
  • jdk.xml.ws:JAX-WS的工具
  • jdk.xml.bind:JAXB的工具

如果不更改构建,则不会编译引用这些API中的类的现有代码。同样,在这些API类的引用的类路径上的代码将失败,NoDefClassFoundError或者ClassNotFoundException,除非改变了应用程序的部署制成。

请参阅JEP 320:删除Java EE和CORBA模块以获取有关模块可能替换的更多信息。

注意:

您可以从Maven下载JAXB和JAX-WS。

安全更新

JDK 11版本包括传输层安全性(TLS)1.3规范(RFC 8446)的实现。

TLS 1.3是传输层安全性(TLS)协议的最新版本(2018年8月),默认情况下在JDK 11中启用。此版本不仅关注速度改进,还通过强调现代加密技术来更新协议的整体安全性。实践,并禁止过时或弱的加密算法。(例如,不再允许RSA密钥交换和普通DSA签名。)

TLS 1.3协议中添加了一些功能以提高向后兼容性,但有几个问题需要注意。有关详细信息,请参阅JEP 332

删除安全证书

已从JDK 11中的信任库中删除以下根证书:

使用已删除证书的产品可能不再有效。如果需要这些证书,则必须使用缺少的证书配置和填充cacerts。为了证书添加到信任,看到密钥工具在Java平台,标准版工具参考指南。

删除了API,工具和组件

本节提供有关在JDK 11中删除的API,工具和组件的详细信息。

在JDK 11中删除了API

在JDK 11中删除了以下API。许多这些API在以前的版本中已被弃用,并且已被更新的API替换。有关可能的替代方案的信息,请参阅JDK 11 API规范

javax.security.auth.Policy 
java.lang.Runtime.runFinalizersOnExit(boolean)
java.lang.SecurityManager.checkAwtEventQueueAccess() 
java.lang.SecurityManager.checkMemberAccess(java.lang.Class,int)
java.lang.SecurityManager.checkSystemClipboardAccess()
java.lang.SecurityManager.checkTopLevelWindow(java.lang.Object)
java.lang.System.runFinalizersOnExit(boolean)
java.lang.Thread.destroy()
java.lang.Thread.stop(java.lang.Throwable)

  

JDK 11未提供的工具和组件

以下是JDK 11未附带的工具和组件列表。

主要工具

  • appletviewer

请参阅JDK-8200146:删除appletviewer启动器

CORBA工具

  • idlj
  • orbd
  • servertool
  • tnamesrv

此外,rmic(RMI编译器)将不再支持-idl-iiop选项。请参阅 JDK 11发行说明

Java Web服务工具

  • schemagen
  • wsgen
  • wsimport
  • xjc

请参阅JEP 320:删除Java EE和CORBA模块

Java部署工具

  • javapackager
  • javaws

注意:

pack 200并且unpack200已被弃用,可能会在将来的JDK版本中删除。

请参阅从JDKJEP中删除JavaFX 336:弃用Pack200工具和API

监控工具

  • jmc:在JDK 11中,JMC作为独立程序包提供,而不是捆绑在JDK中。

请参阅从JDKJava Mission Control中删除JMC

JVM管理-MIB.mib中

JVM-MANAGEMENT-MIB.mib已删除通过SNMP进行JVM监视和管理的规范。请参阅删除JVM-MANAGEMENT-MIB.mib

SNMP代理

jdk.snmp模块已被删除。请参阅删除SNMP代理

Oracle桌面特定删除

  • Oracle JDK T2K字体光栅器已被删除。
  • Lucida字体:Oracle JDK不再提供任何字体,完全依赖于操作系统上安装的字体。请参阅从Oracle JDK中删除Lucida字体

准备迁移

以下部分将帮助您成功迁移您的应用程序:

下载最新的JDK

下载并安装最新的JDK版本

在重新编译之前运行程序

尝试在最新的JDK版本(JDK 11)上运行您的应用程序。大多数代码和库应该在JDK 11上运行而不做任何更改,但可能有一些库需要升级。

注意:

迁移是一个迭代过程。您可能会发现最好首先尝试运行您的程序(此任务),然后或多或少地并行完成这三项任务:

运行应用程序时,请从JVM中查找有关过时VM选项的警告。如果VM无法启动,请查找已删除的GC选项

如果您的应用程序成功启动,请仔细查看您的测试并确保其行为与您使用的JDK版本相同。例如,一些早期采用者注意到他们的日期和货币格式不同。请参阅默认使用CLDR区域设置数据

要使代码适用于最新的JDK版本,请了解每个JDK版本中的新功能和更改。

即使您的程序似乎成功运行,您也应该完成本指南中的其余步骤并查看问题列表。

更新第三方库

对于您使用的每个工具和第三方库,您可能需要具有支持最新JDK版本的更新版本。

检查第三方库和工具供应商的网站,以获取适用于最新JDK的每个库或工具的版本。如果存在,则下载并安装新版本。

如果使用Maven或Gradle构建应用程序,请确保升级到支持最新JDK版本的更新版本。

如果使用IDE开发应用程序,则可能有助于迁移现有代码。NetBeans,Eclipse和IntelliJ IDE都有可用的版本,包括对最新JDK的支持。

您可以在OpenJDK wiki上的Quality Outreach上看到OpenJDK 构建的许多免费开源软件(FOSS)项目的测试状态。

如果需要,编译您的应用程序

使用最新的JDK编译器编译代码将简化向未来版本的迁移,因为代码可能依赖于已被确定为有问题的API和功能。但是,并非绝对必要。

如果需要使用JDK 11编译器编译代码,请注意以下事项:

  • 如果在源代码中使用下划线字符(“_”)作为单字符标识符,则代码将无法在JDK 11中编译。它在JDK 8中生成警告,并从JDK 9开始生成错误。

    举个例子:

    static Object _ = new Object();

     

    此代码从编译器生成以下错误消息:

  • MyClass.java:2: error: as of release 9, \'_\' is a keyword, and may not be used as a legal identifier.

     

  • 如果使用-source-target选项javac,则检查您使用的值。

    支持的-source/-target值为11(默认值),10,9,8,7和6(不推荐使用6,并且在使用此值时会显示警告)。

    在JDK 8,-source-target1.5 / 5的值和更早被弃用,并引起了警告。在JDK 9及更高版本中,这些值会导致错误。

    >javac -source 5 -target 5 Sample.java 
    warning: [options] bootstrap class path not set in conjunction with -source 5 
    error: Source option 5 is no longer supported. Use 6 or later. 
    error: Target option 1.5 is no longer supported. Use 1.6 or later.

     

    如果可能,请使用新--release标志而不是-source-target选项。见javac在Java平台,标准版工具参考。

    --release标志的有效参数遵循与之相同的策略,-source并且-target一加三后退。

    javac可以识别和处理所有以前的JDK的类文件,一直回到JDK 1.0.2类文件。

    请参阅JEP 182:退休javac -source和-target选项的政策

  • 在JDK 11中仍然可以访问关键的内部JDK API,例如sun.misc.Unsafe,但是在编译时无法访问大多数JDK的内部API。您可能会收到编译错误,指出您的应用程序或其库依赖于内部API。

    要标识依赖项,请运行Java依赖关系分析工具。请参阅在您的代码上运行jdeps。如果可能,请更新代码以使用支持的替换API。

    您可以使用该--add-exports选项作为临时解决方法来编译源代码,并引用JDK内部类。

  • 您可能会看到比以前更多的弃用警告。

在您的代码上运行jdeps

jdeps在应用程序上运行该工具,以查看应用程序和库所依赖的包和类。如果您使用内部API,则jdeps可以建议替换以帮助您更新代码。

要查找内部JDK API的依赖项,请jdeps使用该-jdkinternals选项运行。例如,如果您jdeps在调用的类上运行sun.misc.BASE64Encoder,您将看到:

>jdeps -jdkinternals Sample.class
Sample.class -> JDK removed internal API
   Sample  -> sun.misc.BASE64Encoder  JDK internal API (JDK removed internal API)

Warning: JDK internal APIs are unsupported and private to JDK implementation that are
subject to be removed or changed incompatibly and could break your application.
Please modify your code to eliminate dependency on any JDK internal APIs.
For the most recent update on JDK internal API replacements, please check:
https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool

JDK Internal API                         Suggested Replacement
----------------                         ---------------------
sun.misc.BASE64Encoder                   Use java.util.Base64 @since 1.8

 

如果您使用Maven,则可以使用jdeps 插件。

对于jdeps语法,请参见jdeps在Java平台,标准版工具参考。

请记住,这jdeps是一个静态分析工具,代码的静态分析可能无法提供完整的依赖项列表。如果代码使用反射来调用内部API,则jdeps不会警告您。

从JDK 8迁移到以后的JDK版本

JDK 8和后来的JDK版本之间发生了重大变化。

每个新的Java SE版本都会引入一些二进制,源代码和行为不兼容的版本。在JDK 9中发生的Java SE平台的模块化带来了许多好处,但也带来了许多变化。仅使用官方Java SE平台API和受支持的JDK特定API的代码应继续无变化地工作。使用JDK内部API的代码应继续运行,但应迁移以使用支持的API。

以下部分描述了在将JDK 8应用程序迁移到以后的JDK版本时应注意的JDK包和API中的更改。

查看运行应用程序时可能遇到的更改列表。

当您的应用程序在最新版本的JDK上成功运行时,请查看后续步骤,这将帮助您避免将来的版本出现问题。

了解运行时访问警告

某些工具和库使用反射来访问仅供内部使用的JDK部分。在将来的JDK版本中将禁用此非法反射访问。目前,默认情况下允许并发出警告。

例如,以下是启动Jython时发出的警告:

>java -jar jython-standalone-2.7.0.jar
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by jnr.posix.JavaLibCHelper (file:/C:/Jython/jython2.7.0/jython-standalone-2.7.0.jar) to method sun.nio.ch.SelChImpl.getFD()
WARNING: Please consider reporting this to the maintainers of jnr.posix.JavaLibCHelper
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Jython 2.7.0 (default:9987c746f838, Apr 29 2015, 02:25:11)

  

如果您看到这样的警告,请联系工具或库的维护人员。警告的第二行命名精确的JAR文件,其代码使用反射来访问JDK的内部部分。

默认情况下,在java启动程序启动的进程的生命周期中,最多会发出一条有关反射访问的警告。警告的确切时间取决于执行反射访问操作的工具和库的行为。警告可能会在过程的生命周期的早期出现,也可能在启动后很长时间出现。

您可以使用--add-opens命令行标志在逐个库的基础上禁用警告消息。例如,您可以通过以下方式启动Jython:

>java --add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED -jar jython-standalone-2.7.0.jar
Jython 2.7.0 (default:9987c746f838, Apr 29 2015, 02:25:11)

  

这次,不发出警告,因为java调用明确地确认了反射访问。如您所见,您可能需要指定多个--add-opens标志来覆盖类路径上的库尝试的所有反射访问操作。

要更好地理解工具和库的行为,可以使用命令行标志。该标志导致为每个非法反射访问操作发出警告消息。此外,您还可以通过设置获取有关非法反射访问操作的详细信息,包括堆栈跟踪。 --illegal-access=warn``--illegal-access=debug

如果您更新了库,或者获得了库,那么您可以尝试使用命令行标志。除了由其他命令行选项启用的操作外,它禁用所有反射访问操作,例如。这将是未来版本中的默认模式。 --illegal-access=deny``--add-opens

有两个选项可以让您以特定方式打破封装。您可以结合使用它们,或者如前所述,来抑制警告。 --illegal-access=deny

  • 如果需要使用已无法访问的内部API,请使用--add-exportsruntime选项。您还可以--add-exports在编译时使用来访问内部API。
  • 如果必须允许类路径上的代码进行深入反射以访问非公共成员,请使用该--add-opens选项。

如果要禁止所有反射访问警告,请在需要时使用--add-exports--add-opens选项。

--add-exports

如果必须使用默认情况下无法访问的内部API,则可以使用--add-exports命令行选项中断封装。

--add-exports选项的语法是:

--add-exports <source-module>/<package>=<target-module>(,<target-module>)*

 

其中<source-module><target-module>是模块名称,<package>是包的名称。

--add-exports如果目标模块读取源模块,则该选项允许目标模块中的代码访问源模块的命名包中的类型。

作为特殊情况,如果<target-module>ALL-UNNAMED,则将源包导出到所有未命名的模块,无论它们是最初存在还是稍后创建。例如:

--add-exports java.management/sun.management=ALL-UNNAMED

 

此示例允许所有未命名模块中的代码(类路径上的代码)访问公共类型的公共成员java.management/sun.management。如果类路径上的代码尝试进行深度反射以访问非公共成员,则代码将失败。

如果oldApp在类路径上运行的应用程序必须使用模块的未导出com.sun.jmx.remote.internaljava.management,则可以通过以下方式授予其所需的访问权限:

--add-exports java.management/com.sun.jmx.remote.internal=ALL-UNNAMED

 

您还可以使用JAR文件清单中断封装:

Add-Exports:java.management/sun.management

 

--add-exports仔细使用该选项。您可以使用它来访问库模块的内部API,甚至是JDK本身的内部API,但这样做需要您自担风险。如果该内部API发生更改或被删除,则您的库或应用程序将失败。

另见JEP 261

--add-opens

如果必须允许类路径上的代码进行深度反射以访问非公共成员,请使用--add-opens运行时选项。

有些类库有深入反射,这意味着setAccessible(true)他们可以访问所有成员,包括私人成员。您可以在使用java命令行上加--add-opens选项授予此访问权限。使用此选项不会生成警告消息。

如果设置 --illegal-access=deny 您会在运行时看到 `IllegalAccessException``InaccessibleObjectException`信息,你可以在运行参数加--add-opens ,该参数决定异常消息是否显示。

语法--add-opens是:

--add-opens module/package=target-module(,target-module)*

 

该选项允许<module><package><target-module>,无论模块声明。

作为特殊情况,如果<target-module>ALL-UNNAMED,则将源包导出到所有未命名的模块,无论它们是最初存在还是稍后创建。例如:

--add-opens java.management/sun.management=ALL-UNNAMED

 

此示例允许类路径上的所有代码访问java.management/sun.management包中公共类型的非公共成员。

注意:

如果您正在使用JNI调用API(例如,包括Java Web Start JNLP文件),则必须在--add-opens其值和其值之间包含等号。

<j2se version="10" java-vm-args="--add-opens=module/package=ALL-UNNAMED"  />

 

--add-opens在命令行上,其值和它的值之间的等号是可选的。

新版本 - 字符串方案

JDK 10引入了一些小的更改,以更好地适应基于时间的发布模型,以及JDK 9中引入的版本字符串方案.JDK 11保留了JDK 10中引入的版本字符串格式。

如果您的代码依赖于版本字符串格式来区分主要版本,次要版本,安全版本和补丁更新版本,那么您可能需要更新它。

新版本字符串的格式为:

$FEATURE.$INTERIM.$UPDATE.$PATCH

添加了一个简单的Java API来解析,验证和比较版本字符串。请参阅java.lang.Runtime.Version

版本字符串格式的Java平台,标准版安装指南。

有关JDK 9中引入的版本字符串的更改,请参阅 JEP 223:新版本字符串方案

有关JDK 10中引入的版本字符串更改,请参阅JEP 322:基于时间的发行版本控制

对已安装的JDK / JRE映像的更改

JDK和JRE已经发生了重大变化。

更改了JDK和JRE目录结构

安装JDK之后,如果查看文件系统,您会注意到目录布局与JDK 9之前的版本不同。

JDK 11

JDK 11没有JRE映像。见JDK安装目录结构在Java平台,标准版安装指南。

JDK 9和JDK 10

早期版本生成了两种类型的运行时映像:JRE,它是Java SE平台的完整实现,以及JDK,它包括jre/目录中的整个JRE ,以及开发工具和库。

在JDK 9和JDK 10中,JDK和JRE是两种类型的模块化运行时映像,其中每个映像都包含以下目录:

  • bin:包含二进制可执行文件。

  • conf:包含.properties.policy和其他类型的文件,供开发人员,部署人员和最终用户编辑。这些文件以前位于lib目录或其子目录中。

  • lib:包含动态链接库和JDK的完整内部实现。

在JDK 9和JDK 10中,仍然有单独的JDK和JRE下载,但每个都具有相同的目录结构。JDK映像包含历史上在JDK中找到的额外工具和库。没有jdk/jre/包装目录相对应,并且二进制文件(例如java命令)不会重复。

请参阅JEP 220:模块化运行时映像

新的类加载器实现

JDK 9及更高版本维护自1.2版本以来存在的类加载器的层次结构。但是,已经进行了以下更改以实现模块系统:

  • 应用程序类加载器不再是URLClassLoader的实例,而是内部类的实例。它是模块中类的默认加载器,既不是Java SE也不是JDK模块。

  • 扩展类加载器已重命名; 它现在是平台类加载器。通过平台类加载器可以保证Java SE Platform中的所有类都可见。此外,通过平台类加载器可以保证在Java Community Process下标准化但不属于Java SE Platform的模块中的类。

    仅仅因为通过平台类加载器可见类并不意味着该类实际上是由平台类加载器定义的。Java SE平台中的某些类由平台类加载器定义,而其他类则由引导类加载器定义。应用程序不应该依赖于哪个类加载器定义哪个平台类。

    在JDK 9中实现的更改可能会影响使用null(即引导类加载器)创建类加载器的代码作为父类加载器,并假定所有平台类对父级是可见的。可能需要更改此类代码以使用平台类加载器作为父代(请参阅ClassLoader.getPlatformClassLoader)。

    平台类加载器不是URLClassLoader的实例,而是内部类的实例。

  • 引导类加载器仍然是内置的Java虚拟机和代表null中ClassLoader的 API。它定义了一些关键模块中的类,例如java.base。因此,它定义的类比JDK 8中的类少得多,因此使用-Xbootclasspath/a或创建类加载器null作为父级的应用程序可能需要如前所述进行更改。

删除了JDK 9中的rt.jar和tools.jar

类和资源文件之前存储在lib/rt.jarlib/tools.jarlib/dt.jar和其他各种内部JAR文件都存储在一个更有效的格式在实现特定的文件lib目录。

删除rt.jar和类似文件会导致以下方面的问题:

  • 从JDK 9开始,ClassLoader.getSystemResource不返回指向JAR文件的URL(因为没有JAR文件)。相反,它返回一个jrtURL,该URL命名存储在运行时映像中的模块,类和资源,而不会泄露图像的内部结构或格式。

    例如:

    ClassLoader.getSystemResource("java/lang/Class.class");

     

    在JDK 8上运行时,此方法返回以下形式的JAR URL:

    jar:file:/usr/local/jdk8/jre/lib/rt.jar!/java/lang/Class.class

     

    嵌入文件URL以命名运行时镜像中的实际JAR文件。

    模块化中不包含任何JAR文件,因此这种形式的URL毫无意义。在JDK 9及更高版本中,此方法返回:

    jrt:/java.base/java/lang/Class.class

     

  • java.security.CodeSource中的 API和安全策略文件所使用的网址来命名的将被授予特定权限的代码库的位置。请参阅策略文件语法在Java平台,标准版安全开发人员指南。目前conf/security/java.policy,使用文件URL 在文件中标识了需要特定权限的运行时系统组件。

  • 较旧版本的IDE和其他开发工具需要能够枚举存储在运行时映像中的类和资源文件,并通过打开和读取rt.jar以及类似文件直接读取其内容。模块化镜像无法实现这一点。

在JDK 9中删除了扩展机制

在JDK 8及更早版本中,扩展机制使运行时环境可以查找和加载扩展类,而无需在类路径上特别命名它们。从JDK 9开始,如果需要使用扩展类,请确保JAR文件位于类路径上。

在JDK 9和JDK 10中,如果设置了系统属性,或者目录存在,javac编译器和java启动器将退出。要另外检查特定于平台的系统范围目录,请指定命令行选项。如果目录存在且不为空,则会导致出现相同的退出行为。扩展类加载器保留在JDK 9(及更高版本)中,并被指定为平台类加载器(请参阅getPlatformClassLoader。)但是,在JDK 11中,此选项已过时,并在使用时发出警告。java.ext.dirs``lib/ext``-XX:+CheckEndorsedAndExtDirs

以下错误表示您的系统配置为使用扩展机制:

<JAVA_HOME>/lib/ext exists, extensions mechanism no longer supported; Use -classpath instead.
.Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

如果java.ext.dirs设置了系统属性,您将看到类似的错误。

要修复此错误,请删除ext/目录或java.ext.dirs系统属性。

请参阅JEP 220:模块化运行时映像

删除了Endorsed标准覆盖机制

java.endorsed.dirs系统属性和lib/endorsed目录不再存在。如果检测到任何一个,javac编译器和java启动器将退出。

从JDK 9开始,您可以使用可升级模块或将JAR文件放在类路径上。

此机制旨在供应用程序服务器覆盖JDK中使用的组件。要更新的包将放入JAR文件中,系统属性java.endorsed.dirs将告诉Java运行时环境在哪里找到它们。如果未指定此属性的值,则使用默认值$JAVA_HOME/lib/endorsed

在JDK 8中,您可以使用-XX:+CheckEndorsedAndExtDirs命令行参数来检查系统上任何位置的此类目录。

在JDK 9及更高版本中,如果设置了系统属性,或者目录存在,javac编译器和java启动器将退出。java.endorsed.dirs``lib/endorsed

以下错误表示您的系统配置为使用支持的标准覆盖机制:

<JAVA_HOME>/lib/endorsed is not supported. Endorsed standards and standalone APIs
in modular form will be supported via the concept of upgradeable modules.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

如果java.endorsed.dirs设置了系统属性,您将看到类似的错误。

要修复此错误,请删除该lib/endorsed目录,或取消设置java.endorsed.dirs系统属性。

请参阅JEP 220:模块化运行时映像

Windows注册表项更改

安装JDK时,Java 11安装程序会创建这些Windows注册表项:

  • “HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\JDK”

  • “HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\JDK\\11”

如果安装了两个版本的JDK,则会创建两个不同的Windows注册表项。例如,如果JDK 11.0.1与JDK 11一起安装,则安装程序会创建另一个Windows注册表项,如下所示:

  • “HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\JDK”

  • “HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\JDK\\11.0.1”

删除或更改的API

本节重点介绍了在默认行为中无法访问,删除或更改的API。编译或运行应用程序时,您可能会遇到本节中描述的问题。

请参阅JDK 11中的已删除API

删除了JDK 9和JDK 10中的API

以下是从JDK 9和JDK 10发行版中删除的一些重要API。

删除了java.* API

Java团队致力于向后兼容。如果应用程序在JDK 8中运行,那么它将在JDK 9及更高版本上运行,只要它使用受支持且供外部使用的API即可。

这些包括:

  • JCP标准,java.*,javax.*
  • JDK特定的API,部分com.sun.*,部分 jdk.*

支持的API可以从JDK中删除,但只能通知。通过运行静态分析工具,了解您的代码是否使用了弃用的API jdeprscan

java.*在JDK 9中删除的API包括java.util.logging.LogManager和java.util.jar.Pack200包中以前弃用的方法:

java.util.logging.LogManager.addPropertyChangeListener
java.util.logging.LogManager.removePropertyChangeListener
java.util.jar.Pack200.Packer.addPropertyChangeListener
java.util.jar.Pack200.Packer.removePropertyChangeListener
java.util.jar.Pack200.Unpacker.addPropertyChangeListener
java.util.jar.Pack200.Unpacker.removePropertyChangeListener

 

删除和将来删除sun.misc和sun.reflect API

与java.* API不同,几乎所有sun.* API都不受支持,JDK内部API,并且可能随时消失。

在JDK 9中删除了一些sun.* API。值得注意的是,sun.misc.BASE64Encoder和sun.misc.BASE64Decoder被删除了。而是使用在JDK 8中添加的受支持的java.util.Base64类。

如果您使用这些API,则可能希望迁移到其支持的替换项:

  • sun.misc.Unsafe

    通过使用变量句柄可以使用此类中的许多方法的功能,请参阅JEP 193:可变句柄

  • sun.reflect.Reflection :: getCallerClass(INT)

    相反,使用stack-walking API,请参阅JEP 259:Stack-Walking API

请参阅JEP 260:封装大多数内部API

java.awt.peer不可访问

该java.awt.peer中和java.awt.dnd.peer包无法访问,在JDK 9后包就不是Java SE API的一部分,尽管是java.*命名空间。

引用这些包中定义的类型的Java SE API中的所有方法都从JDK 9中删除。调用先前接受或返回在这些包中定义的类型的方法的代码不再编译或运行。

java.awt.peer类有两种常见用法。您应该按如下方式替换它们:

  • 要查看是否已设置对等方:

    if (component.getPeer() != null) { .. }

     

    将其替换为JDK 1.1 API中的Component.isDisplayable():

    public boolean isDisplayable() {
        return getPeer() != null;

     

    要测试组件是否轻量级:
  • if (component.getPeer() instanceof LightweightPeer) ..

     

    将其替换为JDK 1.2 API中的Component.isLightweight():

    public boolean isLightweight() {
        return getPeer() instanceof LightweightPeer;

     

删除了com.sun.image.codec.jpeg包

已删除非标准包com.sun.image.codec.jpeg。请改用Java Image I / O API。

该的com.sun.image.codec.jpeg包JDK 1.2中加入作为控制装载和JPEG格式的图像文件的保存的一个非标准的方式。它从未成为平台规范的一部分。

在JDK 1.4中,Java Image I / O API作为标准API添加,位于javax.imageio包中。它提供了一种标准机制,用于控制采样图像格式的加载和保存,并要求所有兼容的Java SE实现都支持基于Java Image I / O规范的JPEG。

删除了Compact Profiles 工具支持

从JDK 9开始,您可以选择针对Java运行时映像中的任何模块子集构建和运行应用程序,而无需依赖预定义的配置文件。

Java SE 8中引入的配置文件定义了Java SE Platform API的子集,这些子集可以减少存储容量有限的设备上Java运行时的静态大小。在JDK 8支持工具三个配置文件,compact1compact2,和compact3。有关每个配置文件的API组合,请参阅JDK 8文档中的详细配置文件组合API参考

在JDK 8中,您可以使用该-profile选项在运行javacjava命令时指定配置文件。从JDK 9开始,该-profile选项javac仅与--release 8选项一起支持,并且不受支持java

JDK 9及更高版本允许您选择在编译和运行时使用的模块。通过使用新--limit-modules选项指定模块,您可以获得紧凑配置文件中的相同API。该选项是由两个支持javacjava命令,如在以下实施例:

javac --limit-modules java.base,java.logging MyApp.java

java --limit-modules java.base,java.logging MyApp

为Java SE 8中的每个配置文件指定的包将通过以下模块集共同导出:

  • 对于compact1配置文件:java.base,java.logging,java.scripting

  • 对于compact2配置文件:java.base,java.logging,java.scripting,java.rmi,java.sql,java.xml

  • 对于compact3配置文件:java.base,java.logging,java.scripting,java.rmi,java.sql,java.xml,java.compiler,java.instrument,java.management,java.naming,java.prefs,java。 security.jgss,java.security.sasl,java.sql.rowset,java.xml.crypto

您可以使用该jdeps工具对源代码中使用的Java包进行静态分析。这为您提供了执行应用程序所需的一组模块。compact3例如,如果您一直在使用该配置文件,那么您可能会发现在构建应用程序时不需要包含整套模块。见jdeps在Java平台,标准版工具参考。

请参阅JEP 200:模块化JDK

默认情况下使用CLDR区域设置数据

从JDK 9开始,Unicode Consortium的公共区域设置数据存储库(CLDR)数据作为默认区域设置数据启用,因此您可以使用标准区域设置数据而无需任何进一步操作。

在JDK 8中,虽然CLDR区域设置数据与JRE捆绑在一起,但默认情况下不启用它。

使用区域设置敏感服务(如日期,时间和数字格式)的代码可能会使用CLDR区域设置数据生成不同的结果。请记住,即使System.out.printf()也是区域设置感知的。

要启用与JDK 8兼容的行为,请将系统属性设置为例如前面的java.locale.providers值。COMPAT``CLDR``java.locale.providers=COMPAT,CLDR

CLDR语言环境数据通过默认启用的Java平台,标准版国际指南和JEP 252:使用CLDR语言环境数据的默认

部署

Java部署技术在JDK 9中已弃用,在JDK 11中已删除。

使用jlinkJDK 9引入的工具打包和部署专用运行时,而不是依赖于预安装的系统JRE。

删除了启动时JRE版本选择

从JDK 9开始,删除了请求从发布时启动的JRE版本的JRE版本的能力。

现代应用程序通常使用Java Web Start(JNLP),本机OS打包系统或活动安装程序进行部署。这些技术有自己的方法来管理所需的JRE,根据需要查找或下载并更新所需的JRE。这使得启动程序的启动时JRE版本选择已过时。

在以前的版本中,您可以指定启动应用程序时要使用的JRE版本(或版本范围)。通过命令行选项和应用程序的JAR文件中的清单条目,可以选择版本。

从JDK 9开始,java启动器修改如下:

  • 如果-version:在命令行上给出了该选项,则发出错误消息并退出。
  • 如果JRE-Version在JAR文件中找到清单条目,则发出警告消息并继续。

请参阅JEP 231:删除启动时JRE版本选择。

删除了对序列化小程序的支持

从JDK 9开始,不支持将applet部署为序列化对象的能力。借助现代压缩和JVM性能,以这种方式部署applet没有任何好处。

object该属性applet标签和objectjava objectapplet的参数标签启动小程序时被忽略。

而不是序列化applet,使用标准部署策略。

JNLP规范更新

JNLP(Java网络启动协议)已更新,以消除不一致性,使代码维护更容易,并增强安全性。

JNLP已更新如下:

  1. &amp;而不是&在JNLP文件中。

    JNLP文件语法符合XML规范,所有JNLP文件都应该能够由标准XML解析器解析。

    JNLP文件允许您指定复杂的比较。以前,这是通过使用ampersand(&)完成的,但标准XML不支持此功能。如果您正在使用&创建复杂的比较,请&amp;在JNLP文件中替换它。&amp;与所有版本的JNLP兼容。

  2. 将数字版本元素类型与非数字版本元素类型进行比较。

    以前,当将int版本元素与另一个无法解析为int的版本元素进行比较时,版本元素按字典顺序通过ASCII值进行比较。

    从JDK 9开始,如果可以解析为inta 的元素是比其他元素更短的字符串,则在按字典顺序按ASCII值进行比较之前,将使用前导零填充该元素。这确保不存在圆形。

    在使用版本比较和JNLP servlet的情况下,您应该仅使用数值来表示版本。

  3. java(或j2se)元素中具有嵌套资源的组件扩展。

    这在规范中是允许的。它以前得到了支持,但这种支持没有反映在规范中。

  4. FX XML扩展。

    该JNLP规范已经增强,一个添加type属性application-desc元素,并添加子元素paramapplication-desc(因为它已经是applet-desc)。

    这不会导致现有应用程序出现问题,因为仍然支持以前指定JavaFX应用程序的方法。

请参阅JSR-056上的JNLP规范更新。

JDK 9中的安全更新

从JDK 9开始,一些与安全相关的默认值已更改。

JCE管辖权政策文件默认为无限制

如果您的应用程序以前需要Java Cryptography Extension(JCE)Unlimited Strength Jurisdiction Policy Files,那么您不再需要下载或安装它们。它们包含在JDK中,默认情况下处于激活状态。

如果您的国家/地区或用途需要更严格的策略,则仍然可以使用有限的Java加密策略文件。

如果默认情况下提供的任一策略文件都不满足要求,则可以自定义这些策略文件以满足您的需求。

请参阅文件中的crypto.policySecurity属性<java-home>/conf/security/java.security,或Java Platform,Standard Edition Security Developer\'s Guide中的Cryptographic Strength Configuration

建议您咨询您的出口/进口控制律师或律师以确定具体要求。

创建PKCS12密钥库

我们建议您为密钥库使用PKCS12格式。此格式是默认密钥库类型,基于RSA PKCS12个人信息交换语法标准。

请参阅创建密钥库与JSSE使用的Java平台,标准版安全开发人员指南和密钥工具在Java平台,标准版工具参考。

垃圾收集的变化

本节介绍从JDK 9开始的垃圾回收更改。

使G1成为默认垃圾收集器

Garbage-First垃圾收集器(G1 GC)是JDK 9及更高版本中的默认垃圾收集器。

对于大多数用户而言,低卡顿收集器(如G1 GC)应该提供比面向吞吐量的收集器更好的整体体验,例如Parallel GC,它是JDK 8的默认值。

为G1 GC人体工学默认值可调默认的Java平台,标准版Java虚拟机指南有关调整G1 GC的更多信息。

删除了GC选项

以下GC组合将导致您的应用程序无法在JDK 9及更高版本中启动:

  • DefNew + CMS
  • ParNew + SerialOld
  • Incremental CMS

CMS的前台模式也已删除。

Mostly-Concurrent收集器,也称并发标记清除收集器(Concurrent Mark-Sweep GC,CMS收集器),它管理新生代的方式与Parallel收集器和Serial收集器相同,而在老年代则是尽可能得并发执行,每个垃圾收集器周期只有2次短停顿。

 

被删除的命令行标志-Xincgc-XX:+CMSIncrementalMode-XX:+UseCMSCompactAtFullCollection-XX:+CMSFullGCsBeforeCompaction,和-XX:+UseCMSCollectionPassing

命令行标志-XX:+UseParNewGC不再有效。该ParNew标志只能用于CMS和CMS要求ParNew。因此,该-XX:+UseParNewGC标志已被弃用,并且有资格在将来的版本中删除。

请参阅JEP 214:删除JDK 8中不推荐使用的GC组合

删除了永久代

在JDK 8中删除了永久代,并且相关的VM选项会导致打印警告。您应该从脚本中删除这些选项:

  • -XX:MaxPermSize=size

  • -XX:PermSize=size

在JDK 9及更高版本中,JVM会显示如下警告:

Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option MaxPermSize; support was removed in 8.0

知道永久代的工具可能必须更新。

请参阅JEP 122:删除永久生成以上是关于JDK 8迁移到JDK 11版本指南的主要内容,如果未能解决你的问题,请参考以下文章

检测到的 JDK 版本:11.0.8 不在允许范围内 [1.8.0-101,1.8.9999]

jdk8的加密 jdk11不支持

Elasticsearch入门——Elasticsearch7.8.0版本指定JDK11版本

Elasticsearch入门——Elasticsearch7.8.0版本指定JDK11版本

Cordova 构建错误“JDK 8 ('1.8.*') 的要求检查失败!检测到的版本:11.0.2”

Jenkins:批量自动将 Maven 类型 Job 迁移到自由风格类型