Difference Between Javac and the Eclipse Compiler

What is the difference between javac and the Eclipse compiler?

Eclipse has implemented its own compiler called as Eclipse Compiler for Java (ECJ).

It is different from the javac, the compiler that is shipped with Sun JDK. One notable difference is that the Eclipse compiler lets you run code that didn't actually properly compile. If the block of code with the error is never ran, your program will run fine. Otherwise, it will throw an exception indicating that you tried to run code that doesn't compile.

Another difference is that the Eclipse compiler allows for incremental builds from within the Eclipse IDE, that is, all code is compiled as soon as you finish typing.

The fact that Eclipse comes with its own compiler is also apparent because you can write, compile, and run Java code in Eclipse without even installing the Java SDK.

A few examples where ECJ is preferred over javac is:

  • Apache Tomcat uses ECJ to compile JSPs,
  • IntelliJ IDEA has support for ECJ, as of GNU Compiler for Java (GCJ) 4.3,
  • GCJ integrates with ECJ,
  • Liferay builds with ECJ.

Strange compiler difference between Eclipse and javac

This looks like a bug, as reported on Oracle's bug database here.

According to the JLS §7.5, the order of import-statements should not matter.

Generics and lambdas - different behavior in javac and Eclipse compiler

Yes, you're right in every aspect. I honestly wouldn't be able to link to specific lines of the JLS about this: type inference is a whole chapter.

Disclaimer: I tested using Eclipse Mars 4.5.1 and JDK 1.8.0_60.


Variant 1 should compile and Eclipse has a bug here. I couldn't find anything related to this in their Bugzilla so you could go ahead and file it. You can assure yourself that it should compile if you reduce your example to this:

public static <T> void foo(Supplier<T> a) {
a.get();
}

foo(() -> Optional.of("foo"));

This compiles fine both with Eclipse and javac. Adding parameters does (should) not change the type inferred for T during compilation.


Variant 2 does not compile for javac and this is indeed a bug, as reported in JDK-8056983. The compiler should be able to infer that X is RuntimeException. As to why Eclipse is still not able to compile this, again, I couldn't find anything in their Bugzilla so feel free to report this!

Which Java compiler is used by Eclipse?

Eclipse has its own Java compiler, which is called [JDT Core][1] (org.eclipse.jdt.core). The compiler itself is included in the org.eclipse.jdt.core plugin. Eclipse won't use any user installed JDK. Instead it uses its own JDT core to compile Java program due to the following primary reason:

The primary reason is that JDT core has the ability of incremental compilation, which means that it incrementally compiles changes in your code (this is also why Eclipse does not need a compilation button because it automatically compiles when changes are detected). But Oracle's JDK does not support incremental compilation.

Does Eclipse's JDT core compiler include a JRE?

  • No. JDT core is different from JDK. JDT core is a compiler not including a JRE (while JDK includes JRE). This is why we must specify installed JREs for Eclipse to start.

In summary, Eclipse uses its own JDT core as the Java compiler. The JDT core compiler does not have a JRE. So Eclipse requires user installed JRE to run the .class code.

References:

[1] JDT Plug-in Developer Guide, http://help.eclipse.org/kepler/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Fguide%2Fjdt_api_compile.htm

[2] JDT Core Component, https://www.eclipse.org/jdt/core/

[3] How does Eclipse compile classes with only a JRE? How does Eclipse compile classes with only a JRE?

Java Generics: Who is right, javac or Eclipse compile?

I do not understand why javac did not infer the correct type,

but you can help the compiler by supplying the types as in

public @Nonnull Maybe<Foo> visit() {
return Maybe.<Foo, BarExtendsFoo>something(new BarExtendsFoo());
}

eclipse compiler compiles code that javac will not - code looks to be legal

One of the suppressed "unchecked" warnings reveals the problem, in Eclipse 4.6.3:

Type safety: The expression of type Stream needs unchecked conversion to conform to Stream<Boolean>

And in javac 1.8.0_131:

Puzzle.java:12: warning: [unchecked] unchecked conversion
Stream<Boolean> bs1 = outer.stream().flatMap(inner -> inner.stre
am()).map(obj -> obj.hashCode() % 2 == 0);

^
required: Stream<Boolean>
found: Stream

Without any casting, here are the actual return types from each method call in the chain:

Stream<List> s1 = outer.stream();
Stream s2 = s1.flatMap(inner -> inner.stream());
Stream s3 = s2.map(obj -> obj.hashCode() % 2 == 0);
Stream s4 = s3.filter(b -> !b); // compiler error
Optional opt = s4.findAny();
boolean b = opt.isPresent();

If you add a wildcard to make it List<List<?>> outer, this is what you get instead:

Stream<List<?>> s1 = outer.stream();
Stream<?> s2 = s1.flatMap(inner -> inner.stream());
Stream<Boolean> s3 = s2.map(obj -> obj.hashCode() % 2 == 0);
Stream<Boolean> s4 = s3.filter(b -> !b); // compiles OK
Optional<Boolean> opt = s4.findAny();
boolean b = opt.isPresent();

So the issue is that the .map call on the raw Stream doesn't actually return Stream<Boolean>, you're just implicitly casting it when you assign bs1, and that fixes the raw types in the rest of the chain. In fact, you can add this cast to the one-line version and it compiles:

boolean b2 = ((Stream<Boolean>) outer.stream().flatMap(inner -> inner.stream())
.map(obj -> obj.hashCode() % 2 == 0))
.filter(b -> !b).findAny().isPresent();

Now, the raw .map call is missing the class type parameter <T>, but <R> is a method type parameter, so why doesn't it return Stream<R>? The raw types section in the Java language specification states that "a non-static type member of a raw type is considered raw". The example given is a generic inner class, but assuming it applies to generic methods as well, this should be the reason for the <R> parameter of .map getting dropped when it's called on a raw Stream, causing it to return another raw Stream.

EDIT: Found this in an Eclipse bug report:

It looks like javac infers the return type of the method invocation to be the raw type I when passed in arguments are raw types. This may be motivated by the almost last bit of §18.5.2 after bounds set 4 has been generated

[...]

If unchecked conversion was necessary for the method to be applicable during constraint set reduction in §18.5.1, then the parameter types of the invocation type of m are obtained by applying θ' to the parameter types of m's type, and the return type and thrown types of the invocation type of m are given by the erasure of the return type and thrown types of m's type.

Interesting generics-related discrepancy between javac and Eclipse IDE compiler

It doesn't compile in javac. (after adding static to getPercentiles)

Get your facts straight; don't waste other people's time.

Kids today, too much ADD.



Related Topics



Leave a reply



Submit