JDK 9是否应该允许Lambda Expression实例化,在重写方法中引用最终字段?

aai*_*zza 8 java eclipse ecj java-9 eclipse-neon

我一直在使用新的Eclipse Neon,我的一些代码开始直接给我错误.
这是很奇怪,我在第一,但后来我发现这里的霓虹灯欧洲法院(Eclipse的Java编译器)采用JDK 9提前释放编译器的态度.
我没有遇到该链接中的相同问题,而是我将在此解释的另一个问题.

Lambda Expression声明作为字段出现问题

这是一个测试类,它在Eclipse Neon,JDK 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

鉴于上面的代码,在所述误差线4suffix是:

????????????????????????????????????????????????????????????
? Compiler ?                     Error                     ?
????????????????????????????????????????????????????????????
? ECJ      ? Cannot reference a field before it is defined ?
? JDK 9    ? error: illegal forward reference              ?
????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

现在看看我动什么相同类别发生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;
    }
}
Run Code Online (Sandbox Code Playgroud)

鉴于上面的代码,在所述误差线6suffix是:

?????????????????????????????????????????????????????????????????????????
? Compiler ?                           Error                            ?
?????????????????????????????????????????????????????????????????????????
? ECJ      ? The blank final field suffix may not have been initialized ?
? JDK 9    ? error: variable suffix might not have been initialized     ?
?????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

          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;
    }
}
Run Code Online (Sandbox Code Playgroud)

似乎在JDK 9中,匿名类声明和Lambda表达式之间存在很大差异.因此,在这种情况下,我们得到编译器错误,至少ECJ准确地模仿JDK 9编译器.


Stream&Generics的问题

这个让我感到很惊讶,因为我无法想到为什么编译器会解释这个问题与代码中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() );
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码提供以下错误:

????????????????????????????????????????????????????????????????????????????????????
? Compiler ?                                 Error                                 ?
????????????????????????????????????????????????????????????????????????????????????
? ECJ      ? Type mismatch: cannot convert from List<Serializable> to List<String> ?
? JDK 9    ? NO ERROR. Compiles fine!                                              ?
????????????????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

根据这些信息,在这种情况下,ECJ因错误地模仿JDK 9而出现错误,并且只是一个Eclipse错误.

shm*_*sel 7

首先,如果您阅读了您链接的错误报告,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 (!!)
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

可能相关:

  • 流示例*是*https://bugs.eclipse.org/508834,已经针对4.7M5进行了修复,并为后续的4.6.3版本进行了移植. (3认同)