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.