这里的示例代码无法在Java 8(1.8.0_40)中编译,但在Eclipse 4.4 JDT独立编译器(Bundle-Version:3.10.0.v20140604-1726)中编译并成功运行:
import java.util.Arrays;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Test method references to local class constructors.
*/
public class LocalClassTest {
public long sumOfLengths(String[] input) {
class Sum {
final long value;
Sum(long value) {
this.value = value;
}
Sum(Sum left, Sum right) {
this.value = left.value + right.value;
}
Sum add(String s) {
return new Sum(value + s.length());
}
}
return Arrays.stream(input)
.reduce(new Sum(0), Sum::add, Sum::new)
.value;
}
static String[] input =
{
"a", "ab", "abc"
};
@Test
public void localClassConstructorMethodRefs() {
assertEquals(sumOfLengths(input), 6);
}
}
javac
吐出以下错误消息:
Error:(32, 25) java: incompatible types: cannot infer type-variable(s) U
(argument mismatch; invalid constructor reference
cannot access constructor Sum(Sum,Sum)
an enclosing instance of type LocalClassTest is not in scope)
通过JLS 15.9.2(确定封闭实例)和15.13.3(方法引用的运行时评估)阅读,我无法理解为什么这应该无法编译,并且错误消息似乎完全错误,因为我可以用同样的方法手动构建一个Sum
实例。
我发现之前的问题Constructor reference for inner class fails with VerifyError at runtime似乎相关,而那里的链接JDK问题(https://bugs.openjdk.java.net/browse/JDK-8037404)表明该领域存在一系列编译问题;也许这是一个更普遍的问题的另一个例子。不过,我不确定我是否正确阅读规范;这可以用另一种方式工作吗?
答案 0 :(得分:4)
这看起来像处理本地类的编译器错误(方法中的类声明)。如果您更改为内部类(在方法外移动类声明),那么它可以正常工作。您可以同时将其更改为静态类,这可以略微降低开销。
(内部类和本地类都有一个对包含类的隐式引用,这意味着构造函数有一个“隐藏”的第一个参数,你可以用javap看到它。我怀疑编译器知道补偿这个隐藏参数时使用Sum::new
作为内部类,但缺少对本地类执行相同操作的逻辑。)