8

I've been working with the new Eclipse Neon and some of my code started to give me errors straight away.
This was strange to me at first, but then I found here that the Neon ECJ(Eclipse Java Compiler) adopts the attitude of the JDK 9 early release compiler.
I do not encounter the same issue that is in that link, but rather another that I will explain here.

Issue with Lambda Expression declarations as fields

Here is a test class that gives me a compilation error in Eclipse Neon, the JDK 9 compiler, and the JDK 8 compiler (Not previous versions of Eclipse though).

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;
    }
}

Given the code above, the errors at line 4 for suffix are:

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

Now see what happens with the same class if I move the suffix field declaration before the the addSuffix declaration.

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;
    }
}

Given the code above, the errors at line 6 for suffix are:

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

          Should Java 9 behave this way?

This worked perfectly fine in JDK 8; seems like a strange thing to suddenly enforce. Especially considering that there are already compile-time checks in place to ensure final fields are instantiated correctly.
Therefore, by the time the function addSuffix is ever accessed, there would need to be a value in place for suffix (null or otherwise is another story).

I'll also note that I've tried the following code, which compiles fine with JDK9 and 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;
    }
}

It appears that in JDK 9, there is a big difference between anonymous class declarations and Lambda expressions. So in this case where we get a compiler error, at least the ECJ is accurately in mimicking the JDK 9 compiler.


Issue with Stream & Generics

This one really surprised me, because I cannot think of why the compiler would interpret this any differently than what the Generic in the code indicates:

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() );
    }
}

This code gives these errors:

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

In light of this information, it appears in this case, the ECJ is at fault for not properly mimicking the JDK 9 and is just an Eclipse bug.

4

2 回答 2

7

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

lambda 字段在 Eclipse Mars 和 Java 8 中都无法为我编译。这很有意义,因为它可能违反了 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 无关。

可能相关:

于 2017-02-10T21:24:38.843 回答
0

我不确定这是否解决了这个问题,但实际上在编译代码之前,必须使用构造函数或赋值运算符初始化最终字段成员:

class A
{
     private final String suffix = null;
}
于 2018-05-03T06:42:13.523 回答