How to pass a constructor reference for parameterised lambda? - java

I have a method looks like this.
static void doSomething(Function<Irrelevant, Some> supplier) {
}
When I try to do this,
doSomething((i) -> new Some()); // i is irrelevant
it works. But when I try to do this,
doSomething((i) -> Some::new); // compiler -> bad return type in lambda expression
it doesn't.
Is this normal? Is there any way that I can pass a constructor reference for a parameterised function?

A constructor with no parameters would be a Supplier<Some> and thus it is incompatible with a method asking for a Function<Irrelevant, Some>.
Your lambda in doSomething((i) -> Some::new) would actually take some element and return a reference to that constructor, i.e. a Supplier<Some>, not that Some itself. You were probably looking for doSomething(Some::new) -- but as I said, this will not work either since the constructor does not match the method's parameter (it would work, if the constructor had a parameter of type Irrelevant).
If the parameter is really irrelevant, then you could change the method's signature to
static void doSomething(Supplier<Some> supplier) {
If that's not possible, your approach with doSomething((i) -> new Some()); is perfectly fine.

Related

Can you explain why the first unwrapped method reference does not compile?

In this example, passing a method reference to Stream.of does not work but once it's wrapped it works. I can't quite get my head around why this is. Isn't the method reference equivalent to the functional interface?
public class A {
String a() {
return "";
}
void b() {
Stream.of(this::a); // won't compile
Stream.of(wrap(this::a)); // will compile
}
static <T> Supplier<T> wrap(Supplier<T> f) {
return f;
}
}
Stream.of has the following signature:
public static<T> Stream<T> of(T t)
The following example will compile because you explicitly providing a type information for T.
Stream<Supplier<String>> a = Stream.of(this::a);
The first example Stream.of(this::a); equivalent to:
Object a = this::a;
where Object is not a functional interface and will not compile.
Providing with a functional interface this example compiles:
Runnable a = this::a;
Stream.of(a);
In the second example, wrap provides a functional interface Supplier
Stream.of(T) expects an Object and you pass to it a method reference in the first statement. But an Object parameter is not a functional interface, so it cannot accept a method reference or a lambda that is not specifically typed.
With lambda, it would produce also an error : Stream.of(()->this.a()).
A simpler example could be Stream.of(()-> "foo") that will just not compile.
But if you type the method reference or the lambda it works :
Stream.of((Supplier<String>) this::a)
or
Stream.of((Supplier<String>) () -> this.a())
In the working statement you pass to Stream.of(T) a parameter that is a Supplier<String>. That refers to a functional interface but that is typed as in the previous working examples, so it is valid as parameter that expects an Object.
this::a is contextless and could mean different things. You need to provide some context to help the compiler to figure out what you actually meant by this::a.
Stream.<Supplier<String>>of(this::a);
Though, that Stream<Supplier<String>> doesn't seem to be what you wanted. If you need a Stream<String>, use Stream.generate: no extra type information needed since the method takes a Supplier<T> (no ambiguity here).
Stream.generate(this::a);
On a side note, both statements expect you to save their results into variables. Defining variables of the right type often facilitates resolving such issues.
Stream<Supplier<String>> s1 = Stream.of(this::a);
Stream<String> s2 = Stream.generate(this::a);
All credit to #J-Alex and #Holger for their precious comments.

Functional Interface Object Cast

I've encountered the following code in a Java project, and I'm not sure what to make of it:
public Function<CustomEnum,String> foo(SomeObject someObject) {
return ((Function<CustomEnum,String>) (someObject::toString)).andThen(r -> someObject::getSomethingWithEnumParameter);
}
I don't really understand how you can cast something to a Functional Interface. What does that even mean?
Isn't the resulting type of the return value going to be whatever value someObject.
Isn't Function<CustomEnum, String> defining an anonymous function that takes a type CustomEnum and returns a String?
I've read the java doc for Function<T,R>, and to be honest, this doesn't make much more sense than before I read the document.
This is what I believe is happening.
foo is returning an anonymous function that is applied to some CustomEnum to return a String
the anonymous function inside of foo (which is somehow cast onto someObject::toString, which I don't understand) is applied to the CustomEnum that will be passed from the initial call of foo(someObject).apply(customEnum).
The andThen will take the resulting String from the anonymous function inside of foo (which was cast somehow I still don't understand), and then return the value of someObject::getSomethingWithEnumParameter. Why isn't the return type just the type of someObject::getSomethingWithEnumParameter, which we'll say is a Map<R,T>, for sake of discussion.
If anyone could help me understand this flow, I would greatly appreciate it.
In an ideal world this would work:
public Function<CustomEnum,String> foo(SomeObject someObject) {
return (someObject::toString).andThen(...);
}
However Java needs an interface type in order to implicitly create an interface instance from the method reference., hence the explicit cast is required to cast to the Function interface type.
Once you have an instance of Function then you can call any method on it as per normal, in this case the andThen method which composes it with another function object to form a new function.
Breaking it down:
someObject::toString is a method reference with implied type Function<CustomEnum, String>. I.e. toString is a method on SomeObject which takes a parameter of type CustomEnum and returns a String.
r -> someObject::getSomethingWithEnumParameter has the wrong type though - it's a function which returns a function. If you get rid of the "r ->" part then it is valid, as long as someObject::getSomethingWithEnumParameter is a method on SomeObject that takes a String and returns a String. Alternatively the return type of foo would need to change to Function<CustomEnum, Function<String, String>>.
If you combine those two with andThen then you have a Function which takes a CustomEnum and returns a String, as pr the return type of foo.

Cannot access class methods via generics

I changed my method to generic method. What is happening now is that I was deserializing the class inside the methodB and accessing its methods which I can not do anymore.
<T> void methodB(Class<T> clazz) {
T var;
HashMap<String, T> hash = new HashMap<>();
}
void methodA () {
methodB(classA.class);
}
Initially inside methodB with no generics,
var = mapper.convertValue(iter.next(), ClassA.class);
var.blah() //works fine
After using generics,
var = mapper.convertValue(iter.next(), clazz);
var.blah() //cannot resolve the method.
How do I access blah() method of classA?
I think you should use interfaces instead of generics, if you want to call the same 'blah' function on a variety of classes (A,X,Y,Z) (each of which has the same function signature)..
Your other option (if you cannot modify A, e.t.c) is to use reflection. read more about this in https://docs.oracle.com/javase/tutorial/reflect/
Thanks to Passing a class with type parameter as type parameter for generic method in Java. Solved using TypeToken
The line where you assign to var at runtime is absolutely irrelevant. The only thing that matters for compiling a call is the static (compile-time) type of var. Since T is unbounded (other than by Object), it is not known to support any methods, other than those provided by Object. Both pieces of code should fail to compile.

How to call a generic method directly?

Here is the method I am calling:
public static <T extends Something> Group<T> getGroup() { ... }
If I wanted to store the result in a variable, I would do something like this:
Group<SomethingSubClass> group = StaticClass.getGroup();
How would I call the method without storing it in a variable?
StaticClass.getGroup();
The above is what I tried, but I am unsure (mostly don't think it is possible from the way my method is) to add the generic type T.
Solution:
StaticClass.<SomethingSubClass>getGroup();
You don't need anything special. Just invoke it as
StaticClass.getGroup();
You will simply be ignore the return value. The type argument will be inferred as Something, which is what you'd have access to in your method anyway.
You would specify an actual type argument by doing
StaticClass.<SomeTypeThatExtendsSomething>getGroup();
but you don't need that since the only part of your method that makes use of the generic type is the return type, which you are discarding.

What's the difference between <T> T vs T in the return type of a method?

I have a method, like this,
public <T> T doSomething(Class<T> T) {
return T.newInstance();
}
I can also do the same like this,
public T doSomething(Class<T> T) {
return T.newInstance();
}
Is there any difference between these two? Please ignore T.newInstance(), I'm basically going to create a new instance of T somehow and return it.
thanks,
sam
What's the difference between <T> T vs T in the return type of a method?
There is no <T> T. The <T> is not part of the return type; it's a separate thing, indicating the type parameter. (You can also have public <T> void ....)
In the version with <T>, you're declaring T as a type parameter of the method, and the T in the argument and the return-type are referring to that type parameter.
In the version without <T>, you're not declaring T as a type parameter of the method, so it's most likely a type parameter of the containing class or another containing scope. (Alternatively, someone may have named an actual class or interface T, in which case you should give that person a talking-to.)
If both versions compile, then the second is probably the one you want: you probably want to be using the class's type parameter T, rather than adding a new one that hides it. (And if you really do want a new type parameter unrelated to your class's type parameter, then you should use a new name for it to avoid confusion.)
In the first example, you declare a generic method doSomething with its own type parameter <T>. If it's in a generic class, then this <T> is separate from any type parameters that the class may have (even another <T>!).
In the second example, you don't declare a generic type parameter on doSomething. If the class defines <T>, then this method simply uses it. If it doesn't, then T is unrecognized and a compiler error results.
Second option will work only if T is declared as a class generic type. If class doesn't define any generic type and only its member function accepts/returns generic type , you need to explicitly declare it in function declaration.

Categories

Resources