Java 11:javac --release 与-source 和-target 命令行参数有什么区别?

Java 11: What is the difference between javac --release and -source and -target command line parameters?

有人知道使用 --release 与旧的 -source 和 -target 命令行参数之间的区别吗?

在 javac 手册页中: -资源 提供与指定版本的源兼容性 -target 为特定 VM 版本

生成 class 文件

--发布 针对特定 VM 版本进行编译。支持的目标:6、7、8、9、10、11

--release 能否将 -source 和 -target 绑定到同一版本?

我在 Java 11 SDK 源代码中找到了 java 编译器的答案:

/**
     * Handles the {@code --release} option.
     *
     * @param additionalOptions a predicate to handle additional options implied by the
     * {@code --release} option. The predicate should return true if all the additional
     * options were processed successfully.
     * @return true if successful, false otherwise
     */
    public boolean handleReleaseOptions(Predicate<Iterable<String>> additionalOptions) {
        String platformString = options.get(Option.RELEASE);

        checkOptionAllowed(platformString == null,
                option -> reportDiag(Errors.ReleaseBootclasspathConflict(option)),
                Option.BOOT_CLASS_PATH, Option.XBOOTCLASSPATH, Option.XBOOTCLASSPATH_APPEND,
                Option.XBOOTCLASSPATH_PREPEND,
                Option.ENDORSEDDIRS, Option.DJAVA_ENDORSED_DIRS,
                Option.EXTDIRS, Option.DJAVA_EXT_DIRS,
                Option.SOURCE, Option.TARGET,
                Option.SYSTEM, Option.UPGRADE_MODULE_PATH);

        if (platformString != null) {
            PlatformDescription platformDescription =
                    PlatformUtils.lookupPlatformDescription(platformString);

            if (platformDescription == null) {
                reportDiag(Errors.UnsupportedReleaseVersion(platformString));
                return false;
            }

            options.put(Option.SOURCE, platformDescription.getSourceVersion());
            options.put(Option.TARGET, platformDescription.getTargetVersion());

            context.put(PlatformDescription.class, platformDescription);

            if (!additionalOptions.test(platformDescription.getAdditionalOptions()))
                return false;

            JavaFileManager platformFM = platformDescription.getFileManager();
            DelegatingJavaFileManager.installReleaseFileManager(context,
                                                                platformFM,
                                                                getFileManager());
        }

        return true;
    }

如代码所示,--release 选项会将源和目标设置为相同的值。

事实上,如果已经设置了源或目标,则有一个禁止使用 --release 参数的检查。

 void checkOptionAllowed(boolean allowed, ErrorReporter r, Option... opts) {
        if (!allowed) {
            Stream.of(opts)
                  .filter(options :: isSet)
                  .forEach(r :: report);
        }
    }

--release 选项由 "JEP 247: Compile for Older Platform Versions" 添加:

javac provides two command line options, -source and -target, which can be used to select the version of the Java language accepted by the compiler and the version of the class files it produces, respectively. By default, however, javac compiles against the most-recent version of the platform APIs. The compiled program can therefore accidentally use APIs only available in the current version of the platform. Such programs cannot run on older versions of the platform, regardless of the values passed to the -source and -target options.

此外 --release 选项的 documentation 表示:

Note: When using --release, you cannot also use the --source/-source or --target/-target options.

--release 标志不仅设置源版本和目标版本,而且还会导致编译器对与指定版本对应的 JDK 库使用符号 table,从而防止您可能不小心使用了编译 JDK 中存在但不存在于指定版本中的 API。 --release 标志是后来添加的,在大多数情况下,应该取代 --source--target.

的使用