提问者:小点点

eclipse编译器编译javac不会编译的代码-代码看起来是合法的


以下代码在Eclipse版本中编译:Mars.2 Release(4.5.2)Build id: 20160218-0600 on Windows 10 Version 10.0.14393。它不能在一系列oracle javac编译器上编译。还有其他关于使用Eclipse JDT编译器编译但不能使用javac的代码片段的问题。我找不到类似于此示例的代码。这是一段玩具代码,它的唯一目的是展示这种好奇心。

eclipse编译器编译这个是否正确?

注意:如果eclipse编译器生成的. class被反编译,它会生成可以使用javac编译的源代码。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class Puzzle {
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void main(String[] args) {
        List<List> outer = Arrays.asList(Arrays.asList(new Object(), new Object()), 
                                         Arrays.asList(), 
                                         Arrays.asList(new Object(), new Object()));

        Stream<Boolean> bs1 = outer.stream().flatMap(inner -> inner.stream()).map(obj -> obj.hashCode() % 2 == 0);
        boolean b0 = bs1.filter(b -> !b).findAny().isPresent();

        boolean b2 = outer.stream().flatMap(inner->inner.stream())
                            .map(obj -> obj.hashCode() % 2 == 0)
                            .filter(b ->  !b).findAny().isPresent();

        System.out.printf("%s %s %s", outer, b0, b2);
    }
}

这是编译器错误,在几个版本的编译器中:

C:\Users\tofti>C:\jdk1.8.0_121\bin\javac -version & C:\jdk1.8.0_121\bin\javac Puzzle.java
javac 1.8.0_121
Puzzle.java:23: error: bad operand type Object for unary operator '!'
                            .filter(b -> !b).findAny().isPresent();
                                     ^
1 error

C:\Users\tofti>C:\jdk1.8.0_112\bin\javac -version & C:\jdk1.8.0_112\bin\javac Puzzle.java
javac 1.8.0_112
Puzzle.java:23: error: bad operand type Object for unary operator '!'
                            .filter(b -> !b).findAny().isPresent();
                                     ^
1 error

C:\Users\tofti>C:\jdk1.8.0_141\bin\javac -version & C:\jdk1.8.0_141\bin\javac Puzzle.java
javac 1.8.0_141
Puzzle.java:23: error: bad operand type Object for unary operator '!'
                            .filter(b -> !b).findAny().isPresent();
                                     ^
1 error

这是在Eclipse中编译和执行的代码:在eclipse中编译和运行的代码


共1个答案

匿名用户

在Eclipse 4.6.3中,其中一个被抑制的“未经检查”警告揭示了问题:

Type safety: The expression of type Stream needs unchecked conversion to conform to Stream<Boolean>

在javac 1.8中。0_131:

Puzzle.java:12: warning: [unchecked] unchecked conversion
        Stream<Boolean> bs1 = outer.stream().flatMap(inner -> inner.stre
am()).map(obj -> obj.hashCode() % 2 == 0);

     ^
  required: Stream<Boolean>
  found:    Stream

如果没有任何转换,以下是链中每个方法调用的实际返回类型:

Stream<List> s1 = outer.stream();
Stream s2 = s1.flatMap(inner -> inner.stream());
Stream s3 = s2.map(obj -> obj.hashCode() % 2 == 0);
Stream s4 = s3.filter(b -> !b); // compiler error
Optional opt = s4.findAny();
boolean b = opt.isPresent();

如果您添加通配符以使其成为List

Stream<List<?>> s1 = outer.stream();
Stream<?> s2 = s1.flatMap(inner -> inner.stream());
Stream<Boolean> s3 = s2.map(obj -> obj.hashCode() % 2 == 0);
Stream<Boolean> s4 = s3.filter(b -> !b); // compiles OK
Optional<Boolean> opt = s4.findAny();
boolean b = opt.isPresent();

所以问题是对原始Stream. map调用实际上并没有返回Stream

boolean b2 = ((Stream<Boolean>) outer.stream().flatMap(inner -> inner.stream())
        .map(obj -> obj.hashCode() % 2 == 0))
        .filter(b -> !b).findAny().isPresent();

现在,原始. map调用缺少类类型参数

编辑:在Eclipsebug报告中发现:

当传入的参数是原始类型时,javac似乎推断方法调用的返回类型是原始类型I。这可能是由生成边界集4后§18.5.2的几乎最后一位引起的

[...]

如果在§18.5.1中约束集约简过程中,方法必须进行未经检查的转换,则通过对m的类型的参数类型应用θ'来获得m的调用类型的参数类型,并通过删除m的类型的返回类型和抛出类型来给出m的调用类型的返回类型和抛出类型。