Maven编译器插件使用Java 7配置但仍编译Java 8代码

Try*_*est 4 java eclipse maven maven-compiler-plugin

在我的项目中,我们将使用Java 7,maven-compiler-plugin并且我们假设在Maven编译之后,使用Java 8的所有代码都不应该成功编译.

但是,就我而言,有一个文件Arrays.stream(T[] array)可以在Java 8中使用,它仍然可以成功编译.下面是pom.xml配置Java版本的一些文件.请您查看并告诉我为什么我的文件仍可以成功编译,尽管我将其配置为Java 7?

对于pom.xml,我跳过依赖项等等,只列出属性和构建.

<properties>
    <java.version>1.7</java.version>
</properties>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven-compiler-plugin.version}</version>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
            </configuration>
        </plugin>
    </plugins>
</build> 
Run Code Online (Sandbox Code Playgroud)

对于我在Java 8中使用方法的文件,该行是这样的:

buffer.append(Arrays.stream(arg).collect(Collectors.joining("/")));
Run Code Online (Sandbox Code Playgroud)

我想要的是,因为我在Maven中配置Java版本为7并且在编译之后,使用Java 8的文件不应该成功编译并显示诸如"......仅允许在源级别1.8或更高级别的错误" ".

Tun*_*aki 8

<source><target>编译器插件,其直接映射到的标志-source-target Java编译器的选项javac(当它是所使用的一个),是通常误解.

source不指示javac使用指定的JDK版本编译Java源文件.它指示javac检查接受的源代码的版本,这是非常不同的.Java的主要版本有时会改变源代码的语法.例如,在Java 1.4中,您无法编写包含泛型的源代码,例如List<String>; 它无效.但是使用Java 5,您可以,这意味着JDK 5编译器现在接受了一种新的Java源代码.面向a的JDK 1.4编译器List<String>只能出错,因为当JDK 5编译器完全接受它时它不知道.设置该-source 1.4选项将告诉JDK 5编译器将源代码解释为JDK 1.4源代码; 因此,如果该代码确实包含泛型,它将失败,因为该源代码在该版本中无效.这也意味着,如果源代码不包含任何Java 5特定的源代码,它将编译得很好-source 1.4.

在这里的示例中,您有一种情况,其中javac指示JDK 8 的编译器检查关于Java 7的源代码.实际上,该行

buffer.append(Arrays.stream(arg).collect(Collectors.joining("/")));
Run Code Online (Sandbox Code Playgroud)

不使用任何Java 8特定的源代码.当然,它使用Java 8特定的,但JDK 7编译器完全可以理解源代码本身.

  • 没有lambda表达式.map(i -> i)在你的管道中添加一个简单的,然后javac会出错,告诉你:

    不支持lambda表达式 -source 1.7

    它检测到源代码使用了JDK 7源代码功能集中不可用的特定功能.

  • 接口上没有静态方法的调用.用Stream.of(arg)而不是替换您的Stream管道Arrays.stream(arg).这一次,你会收到一个错误:

    不支持静态接口方法调用 -source 1.7

    Arrays不是接口,因此stream在该类上调用静态方法是完全有效的JDK 7源代码.但是,Stream是一个接口(当然,您正在使用的JDK 8编译器已知),并且在Java 8之前,接口不能包含静态方法.因此,它不是有效的Java 7源代码.

还有更多类似的东西,但重点不是在这里描述它们(类型注释,重复注释,方法引用,转换中的交集类型 ......例如,您可以javac源代码中看到所有这些).总而言之,没有理由javac使用该源代码和-source 7选项失败.

target完全是另一头野兽; 这不是问题,因此可以说它指示javac生成以VM的指定版本为目标的字节代码.它不能以任何方式确保生成的字节代码实际上将与所述VM版本一起运行.如果要确保,-bootclasspath则使用该选项.


回到这里的任务,这实际上是为了使编译在这里失败.使用Maven,您有2个解决方案:

  • fork编译器,并设置指向JDK 7编译器的可执行文件.
  • 或者(首选),使用工具链的机制,以确保每个Maven插件(知道工具链)在整个构建过程中使用此JDK(例如,使用javadocJDK安装工具的Javadoc插件).