以下代码在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中编译和运行的代码
在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的调用类型的返回类型和抛出类型。