I have a generic class with a constructor and builder method:
public class FilterBuilder<T> {
public FilterBuilder() {
}
public FilterBuilder<T> add(T x) {
...
return this;
}
}
I instantiate, yet add doesn't work from constructor call:
FilterBuilder<String> filter = new FilterBuilder().add("test");
This gives 'Cannot resolve method add' error in Intellij. I have to do this to make it work:
FilterBuilder<String> filter = new FilterBuilder();
filter.add("test");
but why?
With your actual code, I think that the problem occurs as you specify the diamond operator <> :
FilterBuilder<String> filter = new FilterBuilder<>().add("test");
Raw types should not generate compilation errors but warnings but if your IDE configuration is stricter on this matter.
It is a compilation error specific to IDE as they consider new FilterBuilder<>() as a raw type even if the type of the declared builder is <String>.
By compiling with javac, no compilation error while on Eclipse Oxygen, I have the issue.
I suspect that the diamond operator support was not implemented in IDEs to allow the chaining of the instantiation to an instance method invocation.
As workaround you could do things in two times :
FilterBuilder<String> filter = new FilterBuilder<>();
filter.add("test");
or specify the generic twice :
FilterBuilder<String> filter = new FilterBuilder<String>().add("test");
Related
For class with #Builder Eclipse auto complete (Ctrl+Space) builder methods:
ResponseVO.builder().
It also suggests new which can't work
ResponseVO.builder().new;
Error:
Syntax error on token(s), misplaced construct(s)
Also as creating new instance
new ResponseVO.builder();
Error:
ResponseVO.builder cannot be resolved to a type
Why new is added in suggestion to Builder class?
Checked with Eclipse 4.9.0 version and lower
EDIT
It's happening without lombok's builder, if extracting generated code using inner class Eclipse suggest new when calling MyClass.BuilderExampleBuilder.builder().
public class MyClass {
public static BuilderExampleBuilder builder() {
return new BuilderExampleBuilder();
}
public static class BuilderExampleBuilder {
BuilderExampleBuilder() { }
}
}
Opened Bug 558621 - [content assist] Eclipse suggests 'new' for qualified allocation even if no inner class exists
Proposing new after . is fundamentally correct, helping the user to create a qualified instance creation a la outerInstance.new InnerClass() (see JLS §15.9)
It seems wrong, however, that Eclipse proposes this syntax even if no applicable inner class exists.
I have a problem understanding the behaviour of Java generics in the following case.
Having some parametrised interface, IFace<T>, and a method on some class that returns a class extending this interface, <C extends IFace<?>> Class<C> getClazz() a java compilation error is produced by gradle, 1.8 Oracle JDK, OSX and Linux, but not by the Eclipse compiler within the Eclipse IDE (it also happily runs under Eclipse RCP OSGi runtime), for the following implementation:
public class Whatever {
public interface IFace<T> {}
#SuppressWarnings("unchecked")
protected <C extends IFace<?>> Class<C> getClazz() {
return (Class<C>) IFace.class;
}
}
➜ ./gradlew build
:compileJava
/Users/user/src/test/src/main/java/Whatever.java:6: error: incompatible types: Class<IFace> cannot be converted to Class<C>
return (Class<C>) IFace.class;
^
where C is a type-variable:
C extends IFace<?> declared in method <C>getClazz()
1 error
:compileJava FAILED
This implementation is not a very logical one, it is the default one that somebody thought was good, but I would like to understand why it is not compiling rather than question the logic of the code.
The easiest fix was to drop a part of the generic definition in the method signature. The following compiles without issues, but relies on a raw type:
protected Class<? extends IFace> getClazz() {
return IFace.class;
}
Why would this compile and the above not? Is there a way to avoid using the raw type?
It's not compiling because it's not type-correct.
Consider the following:
class Something implements IFace<String> {}
Class<Something> clazz = new Whatever().getClazz();
Something sth = clazz.newInstance();
This would fail with a InstantiationException, because clazz is IFace.class, and so it can't be instantiated; it's not Something.class, which could be instantied.
Ideone demo
But the non-instantiability isn't the relevant point here - it is fine for a Class to be non-instantiable - it is that this code has tried to instantiate it.
Class<T> has a method T newInstance(), which must either return a T, if it completes successfully, or throw an exception.
If the clazz.newInstance() call above did succeed (and the compiler doesn't know that it won't), the returned value would be an instance of IFace, not Something, and so the assignment would fail with a ClassCastException.
You can demonstrate this by changing IFace to be instantiable:
class IFace<T> {}
class Something extends IFace<String> {}
Class<Something> clazz = new Whatever().getClazz();
Something sth = clazz.newInstance(); // ClassCastException
Ideone demo
By raising an error like it does, the compiler is removing the potential for getting into this situation at all.
So, please don't try to fudge the compiler's errors away with raw types. It's telling you there is a problem, and you should fix it properly. Exactly what the fix looks like depends upon what you actually use the return value of Whatever.getClass() for.
It is kind of funny, that the Eclipse compiler does compile the code, but Oracle Java Compiler will not compile it. You can use the Eclipse Compiler during the gradle build to make sure, gradle is compiling the same way the IDE does. Add the following snippet to your build.gradle file
configurations {
ecj
}
dependencies {
ecj 'org.eclipse.jdt.core.compiler:ecj:4.4.2'
}
compileJava {
options.fork = true
options.forkOptions.with {
executable = 'java'
jvmArgs = ['-classpath', project.configurations.ecj.asPath, 'org.eclipse.jdt.internal.compiler.batch.Main', '-nowarn']
}
}
It fails to compile because C could possibly be anything, where the compiler can be sure that IFace.class does not fulfill that requirement:
class X implements IFace<String> {
}
Class<X> myX = myWhatever.getClass(); // would be bad because IFace.class is not a Class<X>.
Andy just demonstrated why this assignment would be bad (e.g. when trying to instantiate that class), so my answer is not very different from his, but perhaps a little easier to understand...
This is all about the nice Java compiler feature of the type parameters for methods implied by calling context. You surely know the method
Collections.emptyList();
Which is declared as
public static <T> List<T> emptyList() {
// ...
}
An implementation returning (List<T>)new ArrayList<String>(); would obviously be illegal, even with SuppressWarnings, as the T may be anything the caller assigns (or uses) the method's result to (type inference). But this is very similar to what you try when returning IFace.class where another class would be required by the caller.
Oh, and for the ones really enjoying Generics, here is the possibly worst solution to your problem:
public <C extends IFace<?>> Class<? super C> getClazz() {
return IFace.class;
}
Following will probably work:
public class Whatever {
public interface IFace<T> {}
#SuppressWarnings("unchecked")
protected <C extends IFace> Class<C> getClazz() {
return (Class<C>) IFace.class;
}
}
In your former code, problem is that C has to extend IFace<?>>, but you provided only IFace. And for type system Class<IFace> != Class<IFace<?>>, therefore Class<IFace> can not be cast to Class<C extends IFace<?>>.
Maybe some better solution exists, as I am not a generics expert.
I have cloned a maven project on a new machine but I am having some problems with some of the dependencies as they don't seem to have been loaded.
One such case, is fj.Effect of Functional java. I am not sure if I am (manually) adding the right library.
In the code, I have:
private Effect<EventDBEvent> downloadEvent = new Effect<EventDBEvent>() {
#Override
public void e(EventDBEvent eventDBEvent) {
...
}
};
I have tried adding org.org.functionaljava:functionaljava-java8:4.32 and org.functionaljava:functionaljava:4.3 IntelliJ recognizes Effect but highlights the first line as error and says:
I have a similar issue in another line:
final ... = new ...(new Effect<Option<Integer>>() {
#Override
public void e(Option<Integer> integerOption) {
}
}, ...);
Type fj.Effect does not have type parameters.
Am I importing the wrong packages?
More generally, is there a way of knowing which packages I should use, based on an existing code?
The Effect class changed so that the arity is in the class name, e.g. Effect0, Effect1, etc., where the arity indicates the number of parameters to the method. You want to use the Effect1 class.
A couple of days ago, I started refactoring some code to use the new Java 8 Streams library. Unfortunately, I ran into a compile time error when performing Stream::map with a method which is declared to throw a generic E that is further specified to be a RuntimeException.
Interesting enough, the compile time error goes away when I switch to using a method reference.
Is this a bug, or is my method reference not equivalent to my lambda expression?
(Also, I know I can replace p->p.execute(foo) with Parameter::execute. My actual code has additional parameters for the execute method).
Error message
Error:(32, 43) java: unreported exception E; must be caught or declared to be thrown
Code
import java.util.ArrayList;
import java.util.List;
public class JavaBugTest
{
interface AbleToThrowException<E extends Exception>
{
}
interface Parameter {
public <E extends Exception> Object execute(AbleToThrowException<E> algo) throws E;
}
interface ThrowsRuntimeException extends AbleToThrowException<RuntimeException>
{
}
static ThrowsRuntimeException foo;
public static Object manualLambda(Parameter p)
{
return p.execute(foo);
}
public static void main(String[] args)
{
List<Parameter> params = new ArrayList<>();
params.stream().map(p -> p.execute(foo)); // Gives a compile time error.
params.stream().map(JavaBugTest::manualLambda); // Works fine.
}
}
System setup
OS: Windows x64
Java compiler version: Oracle JDK 1.8.0_11
IDE: Intellij
A very simple solution is to explicitly provide a type argument for Parameter#execute(..).
params.stream().map(p -> p.<RuntimeException>execute(foo)); // Gives a compile time error.
Without the explicit type argument, it seems like the JDK compiler cannot infer a type argument from the invocation context, though it should. This a bug and should be reported as such. I have now reported it and will update this question with new details when I have them.
Bug Report
I have this rather simple code written in java. This is actually from a DAQ framework, called Kmax
import kmax.ext.*;
public class Runtime implements KmaxRuntime {
KmaxToolsheet tlsh; // Store a reference to the toolsheet environment
KmaxHist hist1D;
KmaxWidget checkBoxWidget;
public void init(KmaxToolsheet toolsheet) {
tlsh = toolsheet; // Save this reference for use in the toolsheet
hist1D = tlsh.getKmaxHist("HIST1D");
checkBoxWidget = tlsh.getKmaxWidget("CHECK_BOX_CALIB_METH");
tlsh.getKmaxWidget("CHECK_BOX_CALIB_METH").setProperty("VALUE", "1");
}
public void CalibInit(KmaxWidget widget, KmaxHist histo){
histo.setUseXAxisCalibration(stringToBool(widget.getProperty("VALUE")));
histo.update();
}
CalibInit(checkboxWidget,hist1D);
public void GO(KmaxToolsheet toolsheet){}
public void SRQ(KmaxDevice device) {}
public void HALT(KmaxToolsheet toolsheet) {}
} // End of the Runtime object
Note that there I have created an object named CHECK_BOX_CALIB_METH. When I compile this code I get those errors messages
compiler msg>error: invalid method declaration; return type required
compiler msg> CalibInit(checkboxWidget,hist1D);
compiler msg> ^
compiler msg>error: <identifier> expected
compiler msg>CalibInit(checkboxWidget,hist1D);
compiler msg> ^
compiler msg>error: <identifier> expected
compiler msg>CalibInit(checkboxWidget,hist1D);
compiler msg> ^
Note that if I remove the CalibInit method and replace it with
public void CHECK_BOX_CALIB_METH(KmaxWidget widget) {
hist1D.setUseXAxisCalibration(stringToBool(widget.getProperty("VALUE")));
hist1D.update();
}
I get no compile error. The keypoint is that the method's name is the same as the object's name. The reason I created CalibInit() is to avoid having each method for every object of the same type, with the same functionality. Is there a way around it?
How to avoid those errors?
Only variables can declare out side of methods. You can call methods only in methods and constructor (avoiding static context here).
CalibInit(checkboxWidget,hist1D);
Please move that line to any method or constructor , if needed. More specifically call where you need it.
In short: CalibInit(checkboxWidget,hist1D); is orphan now. make it belong to something.
The code
CalibInit(checkboxWidget,hist1D);
that is on a line of its own is not inside any of your methods. The compiler assumes that this is a new method declaration which is probably not what you want.
Side note:
It is not recommended to have methods starting with a upper case character: "Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized." from Code Conventions for the Java Programming Language
You can't call
CalibInit(checkboxWidget,hist1D);
directly in the class like you're doing. This instruction should be inside a constructor if your goal is to call it when an instance of Runtime is constructed.
BTW: methods start with a lowercase letter by convention in Java, and you shouldn't call your class Runtime: it will confuse people because a standard Runtime class already existsin the standard libraries.
You are calling CalibInit(checkboxWidget,hist1D) method directly in the class not in any method. Java doesn't support this.