gpt4 book ai didi

java - JDK 9 是否应该不允许在覆盖方法中引用最终字段的 Lambda 表达式实例化?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:48:06 27 4
gpt4 key购买 nike

我一直在使用新的 Eclipse Neon,我的一些代码立即开始出错。
起初这对我来说很奇怪,但后来我发现了here Neon ECJ(Eclipse Java Compiler)采用了JDK 9早期版本编译器的态度。
我没有遇到该链接中的相同问题,而是我将在此处解释的另一个问题。

Lambda 表达式声明作为字段的问题

这是一个测试类,在 Eclipse NeonJDK 9 编译器和 JDK 8 编译器(虽然不是以前版本的 Eclipse)中给我一个编译错误.

public class Weird
{
private final Function<String, String> addSuffix =
text -> String.format( "%s.%s", text, this.suffix );

private final String suffix;

public Weird( String suffix )
{
this.suffix = suffix;
}
}

鉴于上面的代码,第 4 行suffix 的错误是:

╔══════════╦═══════════════════════════════════════════════╗
║ Compiler ║ Error ║
╠══════════╬═══════════════════════════════════════════════╣
║ ECJ ║ Cannot reference a field before it is defined ║
║ JDK 9 ║ error: illegal forward reference ║
╚══════════╩═══════════════════════════════════════════════╝

现在看看如果我将 suffix 字段声明移动到 addSuffix 声明之前,同一个类会发生什么。

public class Weird
{
private final String suffix;

private final Function<String, String> addSuffix =
text -> String.format( "%s.%s", text, this.suffix );

public Weird( String suffix )
{
this.suffix = suffix;
}
}

鉴于上面的代码,第 6 行suffix 错误是:

╔══════════╦════════════════════════════════════════════════════════════╗
║ Compiler ║ Error ║
╠══════════╬════════════════════════════════════════════════════════════╣
║ ECJ ║ The blank final field suffix may not have been initialized ║
║ JDK 9 ║ error: variable suffix might not have been initialized ║
╚══════════╩════════════════════════════════════════════════════════════╝

Java 9 应该这样做吗?

这在 JDK 8 中工作得很好;突然强制执行似乎是一件奇怪的事情。特别是考虑到已经存在编译时检查以确保正确实例化最终字段。
因此,在访问函数 addSuffix 时,需要suffix (null 或其他情况是另一回事)

我还会注意到我已经尝试了以下代码,它可以很好地与 JDK9 和 ECJ 编译:

public class Weird
{
private final String suffix;

private final Function<String, String> addSuffix =
new Function<String, String>()
{
@Override
public String apply( String text )
{
return String.format( "%s.%s", text, suffix );
}
};

public Weird( String suffix )
{
this.suffix = suffix;
}
}

在 JDK 9 中,匿名类声明和 Lambda 表达式之间似乎有很大的区别。因此,在出现编译器错误的这种情况下,至少 ECJ 准确地模仿了 JDK 9 编译器。


流和泛型问题

这真的让我感到惊讶,因为我想不出为什么编译器会以与代码中的 Generic 所指示的不同的方式解释它:

public class Weird
{
public void makePDFnames( String [] names )
{
final List<String> messages = Arrays.asList( "nice_beard", "bro_ski" );

final List<String> components = messages.stream()
.flatMap( s -> Stream.of( s.split( "_" ) ) )
.collect( Collectors.toList() );
}
}

这段代码给出了这些错误:

╔══════════╦═══════════════════════════════════════════════════════════════════════╗
║ Compiler ║ Error ║
╠══════════╬═══════════════════════════════════════════════════════════════════════╣
║ ECJ ║ Type mismatch: cannot convert from List<Serializable> to List<String> ║
║ JDK 9 ║ NO ERROR. Compiles fine! ║
╚══════════╩═══════════════════════════════════════════════════════════════════════╝

根据这些信息,出现在这个案例中,ECJ 没有正确模仿 JDK 9,这只是一个 Eclipse 错误。

最佳答案

首先,如果您阅读了您链接的错误报告,ECJ 不会“采纳”JDK 9 编译器的态度。两个编译器都有一个错误,一个在 JDK 9 中修复,另一个在 Neon 中修复。

在 Eclipse Mars 和 Java 8 中,lambda 字段都无法为我编译。这完全有道理,因为它可能违反了 final 字段的不变性保证。令人惊讶的是匿名子类编译成功。考虑这个例子:

public static class Weird
{
private final String suffix;

private final Function<String, String> addSuffix = new Function<String, String>() {
@Override
public String apply(String text) {
return String.format( "%s.%s", text, suffix );
}
};

public final String s = addSuffix.apply("1");

public static void main(String[] args) {
System.out.println(new Weird("p").s);
// 1.null (!!)
}
}

我怀疑以上可能是两个编译器中的错误。

至于流错误,相同的代码也可以在 Java 8 中编译。所以这可能只是另一个 ECJ 错误,与 Java 9 无关。

可能相关:

关于java - JDK 9 是否应该不允许在覆盖方法中引用最终字段的 Lambda 表达式实例化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42168439/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com