Cannot convert functional interface with generic method into lambda expression - java

Cannot convert functional interface with generic method into lambda expression.
Following code is working. It is without lambda expression i.e. using anonymous class.
public interface Pro{
public <T> void callee(T t);
}
public void fun(Pro obj){}
public void implement() {
fun(new Pro() {
#Override
public <Integer> void callee(Integer t){}
});
}
I cannot understand how to use lambda expression instead of anonymous class.
After trying it myself I used the hint shown in netbeans. I used the shown bulb to do it.
And here is what I got, an ERROR.
public void implement() {
fun((Integer t) -> {
});
}
It is showing error. What is the correct lambda expression to be used here?
Here is the error :
one\LambdaScopeTest.java:18: error: incompatible types: invalid functional descriptor for lambda expression
fun((Integer t) -> {
^
method <T>(T)void in interface Pro is generic
where T is a type-variable:
T extends Object declared in method <T>callee(T)
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get
full output

The main problem is that you've got a generic method instead of a generic interface. That doesn't make a lot of sense. As soon as you make the interface generic instead, it works:
#FunctionalInterface
interface Pro<T> {
void callee(T t);
}
public class Test {
public static <T> void fun(Pro<T> obj){}
public static void main(String[] args) {
fun((Integer t) -> {});
}
}
It makes much more sense for the interface to be generic, as then it makes sense to have different implementations for different types. For the method to be generic suggests that every implementation should be able to accept any value of any type, because the caller would be specifying it - which doesn't make sense if you then use a lambda expression with a specific type.
Your original version is only working because you're declaring a generic type parameter called Integer... you're not specifying an implementation for the Integer type. In other words, this:
fun(new Pro() {
#Override
public <Integer> void callee(Integer t){}
});
is equivalent to:
fun(new Pro() {
#Override
public <T> void callee(T t){}
});
... and I don't know of a way of representing that as a lambda expression. Basically, I think your original interface is inappropriate for lambda expressions.

Related

Java generic interface implementation cannot omit type parameter?

I found that in Java I could use anonymous class to implement interface like Runnable (non-generic). I could also declare a variable without specifying type parameter on the right of "=". But I found for generic type, I cannot omit this:
import java.util.ArrayList;
import java.util.List;
interface Normal {
Integer f();
void g();
}
interface Generic<T> {
T f();
void g();
}
public class GenericInterface {
public static void main(String[] args) {
List<Integer> li = new ArrayList<>(); // ArrayList without type parameter, OK
Runnable r = new Runnable() {
#Override public void run() {}
};
Normal n = new Normal() { // declare implementation, OK.
#Override public Integer f() {
return new Integer(0);
}
#Override public void g() {}
};
Generic<Integer> i = new Generic<>() { // Why need type paramter here?
#Override public Integer f() {
return new Integer(0);
}
#Override public void g() {}
};
}
}
As you could see, javac report compilation failure for this line:
Generic<Integer> i = new Generic<>() {
While the compiler is smart enough to compile List<Integer> li = new ArrayList<>(), when compiler already know the real type from the left of this statement, why it still needs me to write new Generic<Integer>() { ?
Or Java prevents generic interface implementation without specifying the type parameter? What is the reason?
In Java 8 the compiler gives this error:
GenericInterface.java:23: error: cannot infer type arguments for Generic<T>
Generic<Integer> i = new Generic<>() { // Why need type paramter here?
^
reason: cannot use '<>' with anonymous inner classes
where T is a type-variable:
T extends Object declared in interface Generic
1 error
I cannot see where this is explicitly forbidden in the Java 8 edition of the JLS (but I might have missed it).
In any case, this is permitted in Java 9 and later. It was one of the changes made as part of Project Coin (JEP 213):
"3. Allow diamond with anonymous classes if the argument type of the inferred type is denotable. Because the inferred type using diamond with an anonymous class constructor could be outside of the set of types supported by the signature attribute, using diamond with anonymous classes was disallowed in Java SE 7. As noted in the JSR 334 proposed final draft, it would be possible to ease this restriction if the inferred type was denotable."
This improvement was delivered in Java 9.
What is the reason?
The technical reason is given in the quoted text above.

Inexplicable behaviour of overloaded method using generics

class My<T> {
void overloadMethod(String s) {
System.out.println("string");
}
void overloadMethod(Integer i) {
System.out.println("integer");
}
void overloadMethod(T t) {
System.out.println("t");
}
}
public class MyClass01 {
public static void main(String[] args) {
String o = "abc";
new My<String>().overloadMethod(o);
}
}
This gives the following error:
/MyClass01.java:20: error: reference to overloadMethod is ambiguous
new My<String>().overloadMethod(o);
^
both method overloadMethod(String) in My and method overloadMethod(T) in My match
where T is a type-variable:
T extends Object declared in class My
1 error
I was expecting "string" output assuming that type erasure would ensure that the third method would be:
void overloadMethod(Object t) {
System.out.println("t");
}
What am I missing here?
Thanks.
By instantiating the generic class MyClass<T> into the specific parameterized type new My<String>().overloadMethod(o);, you've effectively declared two methods with this same signature: overloadMethod(String s).
That's what the compiler error is trying to tell you with: „error: reference to overloadMethod is ambiguous“.
„…What am I missing here?…“
Because you say: „I was expecting "string" output“, it sounds like you're mistakenly assuming that your declaration of class My<T> has somehow imbued your non-generic method overloadMethod(String s) with the powers of parametric polymorphism. It hasn't.
The problem is the void overloadMethod(T t), here T is generic Class, it could be anything, when you declared
new My<String>() then T = String
try to comment in the overloadMethod(String s), you will get "t" as output
The ambiguity comes into play since T = String in this case, so the class has 2 methods to call
void overloadMethod(String s) = void overloadMethod(T t)
And doesn't know wich one to call

Overloading a method: both methods have same erasure

I have the following code and it doesn't work: the error both methods have same erasure appears.
public class Foo<V> {
public static void main(String[] args) {
}
public void Bar(V value) {
}
public void Bar(Object value) {
}
}
Also I have this code:
public class Foo<V> {
public static void main(String[] args) {
}
public void Bar(B value) {
}
public void Bar(A value) {
}
}
class A {
}
class B extends A {
}
And this works. In the first case V is a child of Object, just like in the second case B is a child of A. Then why the first case results in error, while the second compiles successfully?
EDIT: What should I do to achieve method overloading, without raising an error?
What should I do to achieve method overloading, without raising an error?
Simple: don't try to overload the method with parameters with the same erasure.
A few options:
Just give the methods different names (i.e. don't try to use overloading)
Add further parameters to one of the overloads, to allow disambiguation (ideally only do this if you actually need those parameters; but there are examples in the Java API where there are junk parameters simply to avoid overloading issues).
Bound the type variable, as suggested by #Kayaman:
<V extends SomethingOtherThanObject>
V isn't "a child of Object". V is an unbounded generic type that erases to Object, resulting in the error. If the generic type were bounded, such as <V extends Comparable<V>>, it would erase to Comparable and you wouldn't get the error.

Java 8 method references : validation of methods at compile time

I'd like to use the new method references of Java 8 to provide more validation of some code at compile time.
Let's say I have a validateMethod method which requires one parameter : a "method" to be validated. For example :
validateMethod(foo, "methodA");
Here, the method would validate that foo#methodA() exists, at runtime.
Using method references, I'd like to be able to do :
validateMethod(foo::methodA);
So the existence of the method would be validated at compile time.
The problem is that it seems method references have to be assigned to a functional interface. For example, this :
Object dummy = foo::methodA;
Generates the error : "The target type of this expression must be a functional interface".
If I create a functional interface that has a compatible signature with the methodA method, it works :
#FunctionalInterface
public interface MyFunctionalInterface
{
public String run();
}
MyFunctionalInterface dummy = foo::methodA;
Now the existence of foo#methodA() is validated at compile time, which is what I want!
But...
Let's say validateMethod doesn't know the signature of the method it has to validate. Is it still possible to implement it then?
Let's pretend we don't care about ambiguity and overloaded methods. Is it possible in Java 8 to implement some kind of method which would trigger the validation of any method reference?
For example :
public class Foo
{
public String methodA()
{
return "methodA";
}
public String methodB(String str)
{
return "methodB";
}
public String methodC(String str, int nbr)
{
return "methodC";
}
}
Foo foo = new Foo();
validateMethod(foo::methodA); // Compile
validateMethod(foo::methodB); // Compile
validateMethod(foo::methodC); // Compile
validateMethod(foo::methodD); // Error!
Would it be possible to implement validateMethod in such a way that any method reference would be accepted, so the existence of the method would be validated at compile time?
I tried :
public void validateMethod(Object obj){}
But it doesn't work : "The target type of this expression must be a functional interface"
This would work :
#FunctionalInterface
public interface MyFunctionalInterface
{
public String run();
}
public void validateMethod(MyFunctionalInterface param){}
But only for methodA of the Foo class, because its signature (no parameter) is compatible with the functional interface's method signature!
Would it be possible to implement the functional interface MyFunctionalInterface in such a way that any method reference would be a valid parameter and therefore would be validated at compile time?
Any other ways you see to validate the existence of a method at compile time?
You seem to be trying to use method references, which are really the short-hands for lambda expressions, as method literals, which are the syntactic references to methods (much like Foo.class is the syntactic reference to class instance of Foo). These two are not the same, and this is the reason for the impedance you encounter. Things you try are the abuse of language feature which javac compiler utterly resists.
Unfortunately, there is no method literals in Java, so you will have to describe the method by other means, e.g. Reflection, MethodHandles.Lookup, etc. I think it is very easy to come up with the reflective checker for this kind of thing, or even build up the annotation processor to check the existence of given methods in compile time.
You could try something like the following:
public class Validate {
public String methodA() { return "methodA"; }
public String methodB(String s) { return "methodB"; }
public String methodC(String s, int n) { return "methodC"; }
public static void main(String[] args) {
Validate foo = new Validate();
validateMethod(foo::methodA);
validateMethod(foo::methodB);
validateMethod(foo::methodC);
}
private interface Func0 { void method(); }
private interface Func1<T> { void method(T t); }
private interface Func2<T, U> { void method(T t, U u); }
private interface Func3<T, U, V> { void method(T t, U u, V v); }
public static void validateMethod(Func0 f) { }
public static <T> void validateMethod(Func1<T> f) { }
public static <T, U> void validateMethod(Func2<T, U> f) { }
public static <T, U, V> void validateMethod(Func3<T, U, V> f) { }
}
But you'll need to provide an interface and an overload of validateMethod for every arity of method you need to validate. Also, it will not work if the method to validate is overloaded, unless you add an explicit cast:
// if there are two methodA's:
public String methodA() { return "methodA"; }
public String methodA(long x) { return "methodA"; }
validateMethod(foo::methodA); // this doesn't work
validateMethod((Func0)foo::methodA); // this does
validateMethod((Func1<Long>)foo::methodA); // so does this
would interface Method { public Object runMethod(Object... args); } work? the only potential problem i see is methods that deal with primitive types, but perhaps they could be upcast automatically to Double's / Long's, dont really have a running java8 compiler atm.

Java Generics Value.<SomeValue>

I had an interview test and saw the following code:
EDIT:
public class TestValue {
private Value<SomeValue> defaultValue;
#Test
public void Empty_Value_Has_No_Value() {
Assert.assertFalse(Value.<SomeValue> createEmptyValue()
.hasValue());
}
#Test
public void Default_Value_IsEmpty() {
Assert.assertEquals(Value.<SomeValue> createEmptyValue(),
defaultValue);
}
#Test
public void Non_Empty_Value_Has_Value() {
Assert.assertTrue(new Value<SomeValue>(true, new SomeValue())
.hasValue());
}
}
I had never seen Java generic like
Value.<SomeValue>
The test is to implement Value class with the given unit test code above.
I tried to figure out the Value method signature below (need implementation):
public interface Value<T> {
public boolean hasValue();
public Value<T> createEmptyValue();
}
Any one know, please help?
Thank you
EDIT: Should be like this according to answers below #marlon
public class Value<T> {
public boolean hasValue(){}
public static <M> Value<M> createEmptyValue(){}; //need <M>
}
The key syntax to know:
Value.<SomeValue> //ClassName.<Type>method
is way to invoke static method of a class with parameterized argument.
EDIT: according to #snipes83, syntax to invoke non-static method of a class with parameterized argument.
SomeObject.<Type>method
Value.<SomeValue> it's the way generics are represented for methods.
Using Google Guava's Optional as an example:
Optional<String> email = Optional.<String>of(strEmail);
See Generic Types - Invoking generic methods
Since interfaces cannot declare static methods (shame on you java), just declare your method as static and forget about the interface, like this:
class Value<T> {
public static <T> Value<T> createEmptyValue(){
return null;
}
}
Look at the class Test with the method getEmptyList below:
public class Test {
public <T> List<T> getEmptyList() {
return new ArrayList<T>();
}
}
It returns an empty List containing objects of type T.
If you use Test like this
Test t = new Test();
List<Integer> list = t.getEmptyList();
Then the type inference mechanism is able to infer the type parameter based on the variable type.
However if you need to use the return value of getEmptyList within a method invocation expression like in the following example where the method printList expects a single argument of type List<Integer>, then the type can not be infered from any variable type.
public void printList(List<Integer> list) {
for (int i : list) {
System.out.print(i);
}
}
printList(t.getEmptyList()); // This will FAIL.
In this case you need to specify the type using the following:
printList(t.<Integer>getEmptyList());
1) This is how generic methods are invoked. Refer >> http://docs.oracle.com/javase/tutorial/java/generics/methods.html
2) <SomeValue> in Value.<SomeValue> is optional. Compiler can infer the type. This is called TypeInference. Refer >> http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html
Answer Updated:
3) Value.<SomeValue> createEmptyValue() is right and Value.<SomeValue>createEmptyValue() is right too. Both ways are legal. Just tested it. Didn't notice before.
Although Value is itself obviously typed ( based on the instance variable type of Value<SomeValue>), the static createEmptyValue() method is also typed.
A reasonable assumption, if naming conventions have been adhered to, is that SomeValue extends (or implements) Value.
Although there us no one correct answer, a likely possibility for the signature of Value is:
public class Value<T extend Value> {
public static <V extends Value> V createEmptyValue() {
// some impl
}
}

Categories

Resources