This question already has answers here:
Lambda 'special void-compatibility rule' - statement expression
(3 answers)
Why do Consumers accept lambdas with statement bodies but not expression bodies?
(3 answers)
Why does a Java method reference with return type match the Consumer interface?
(2 answers)
Consumer lambda in Java 8 [duplicate]
(2 answers)
Closed 4 years ago.
Given this method:
private static Integer return0() {
return 0;
}
I discovered a weird property of the following lambda expression:
() -> return0();
Does it actually return the value from the function it calls (which would make it a Supplier-Interface) or does it not return the value but only calls the function and returns void (which would make it a Runnable-Interface). Intuitively, I would expect the first case to be correct but could live with the second.
When trying to assign the statement:
Supplier<Integer> supplier2 = () -> return0();
Runnable runnable2 = () -> return0();
It turns out both lines do compile! Why would they allow that? It is completely ambiguous and really confusing!
EDIT:
Here is more code to demonstrate what I mean by confusing/ambigous:
public static void main(String[] args) {
callMe(() -> return0());
}
private static Integer return0() {
return 0;
}
private static void callMe(Supplier<Integer> supplier) {
System.out.println("supplier!");
}
private static void callMe(Runnable runnable) {
System.out.println("runnable!");
}
This all compiles well and upon execution prints "supplier!". I do not find it particularly intuitive that the first method is chosen but rather arbitrary.
The relevant part of the spec is Sec 15.27.3 (emphasis mine):
A lambda expression is congruent with a function type if all of the following are true:
The function type has no type parameters.
The number of lambda parameters is the same as the number of parameter types of the function type.
If the lambda expression is explicitly typed, its formal parameter types are the same as the parameter types of the function type.
If the lambda parameters are assumed to have the same types as the function type's parameter types, then:
If the function type's result is void, the lambda body is either a statement expression (§14.8) or a void-compatible block.
If the function type's result is a (non-void) type R, then either i) the lambda body is an expression that is compatible with R in an assignment context, or ii) the lambda body is a value-compatible block, and each result expression (§15.27.2) is compatible with R in an assignment context.
Your lambda body is a statement expression, and the function type's result is void.
In other words, it would be fine for you to write:
return0();
and ignore the return value in "regular" code, so it's fine to ignore the result value in a lambda too.
In terms of the question over ambiguity of overloads, there is no ambiguity in this case (it's easy to construct a case where there is ambiguity, e.g. another overload with a parameter that looks like Supplier but is a different interface, i.e. takes no parameters, returns a value).
You would have to read the spec in detail for the precise reasoning, but I think the most relevant section is Sec 15.12, which describes method invocation expressions, and the most useful quote from that is in Sec 15.12.2.5, which deals with selecting the most-specific overload:
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
You can use a Supplier<Integer> in place of a Runnable (with a bit of a hand-wavy fudge) because you can simply ignore the return value; you can't use a Runnable in place of a Supplier<Integer> because it doesn't have a return value.
So a method taking the Supplier<Integer> is more specific than the method taking the Runnable, hence that is the one which is invoked.
If you get confused with lambda expressions, replace them with anonymous classes for a better understanding (IntelliJ IDEA can easily help you with that). The following code snippets are completely valid:
Supplier<Integer> supplier2 = () -> return0() is equivalent to:
Supplier<Integer> supplier2 = new Supplier<Integer>() {
#Override
public Integer get() {
return return0();
}
};
Runnable runnable2 = () -> return0() is equivalent to:
Runnable runnable2 = new Runnable() {
#Override
public void run() {
return0();
}
};
public static void main(String[] args) throws Exception
{
Supplier<Integer> consumer2 = Trial::return0;
Runnable runnable2 = Trial::return0;
run(Trial::return0);
}
private static Integer return0() {
return 0;
}
private static int run(Supplier<Integer> a)
{
System.out.println("supplier");
return a.get();
}
private static void run(Runnable r)
{
System.out.println("runnable");
r.run();
}
As far as method overloading is concerned, this code in class Trial prints "supplier".
Related
This question already has answers here:
In java, Can we override a method by passing subclass of the parameter used in super class method?
(7 answers)
Closed 7 months ago.
I have a set of derived classes (mathematical values, such as Length, Angle, Value) and I'm defining calculation functions for them. The overloaded functions aren't being called as I expected. Problem boiled down to simple form...
public abstract class Operand {
public abstract Operand multiply(Operand other);
public static void main(String[] args) {
try {
Operand x = new Value(5);
Value y = new Value(6);
Operand z = x.multiply(y);
System.out.println(z);
} catch (Throwable e) {
e.printStackTrace(System.out);
}
}
}
public class Value extends Operand {
final double value;
Value(double arg) { value = arg; }
#Override
public Operand multiply(Operand other) { // type of other not known
System.out.println("dispatch of " + getClass().getSimpleName() +
".multiply(" + other.getClass().getSimpleName()+")");
return other.multiply(this); // dispatch to handler through polymorphism.
}
public Operand multiply(Value other) { // this and other are specific type
System.out.println("calculation of " + getClass().getSimpleName() +
".multiply(" + other.getClass().getSimpleName()+")");
return new Value(value*other.value);
}
#Override
public String toString() {
return Double.toString(value);
}
}
Hopefully you can see that I basically want multiple type derived from "Operand" and I want to be able to do:
Operand a;
Operand b;
Operand a.function(b)
And have the right function eventually called for the underlying specific type.
However, Java is not picking of the type of this in the dispatch and applying it on the subcall. I thought java was supposed to pick the most specific method prototype when the class is know.
Instead I'm getting infinite recursive calls to the dispatch function:
dispatch of Value.multiply(Value)
dispatch of Value.multiply(Value)
dispatch of Value.multiply(Value)
dispatch of Value.multiply(Value)
...
this is certainly known in this case to be Class==Value so why isn't other.multiply(this) resulting in Value multiply(Value) being the chosen prototype?
What understanding of Java am I missing here?
You've created an infinite recursion in multiply(Operand) implementation.
While line return other.multiply(this); is executed, method multiply(Operand) repeatedly calls itself because it's the only method accessible for the type Operand. It happens because variable other is of type Operand and it doesn't know the method multiply(Value), hence the multiply call is mapped by the Compiler to multiply(Operand).
That's how you might fix this problem:
#Override
public Operand multiply(Operand other) { // type of other not known
System.out.println("dispatch of " + getClass().getSimpleName() +
".multiply(" + other.getClass().getSimpleName()+")");
if (other instanceof Value otherValue) {
return otherValue.multiply(this); // note that's not a polymorphic call
}
throw new RuntimeException(); // todo
}
In this case, compiler will be sure that multiply() call should be mapped to the multiply(Value), since it knows the type of the variable otherValue and would resolve the method call to the most specific overloaded version which is multiply(Value) because this is of type Value, hence this method is more specific than multiply(Operand) which would require performing widening conversion.
Here's a link to the part of Java Language Specification that describes how method resolution works.
In short, the compiler needs to find potentially applicable methods based on the type and method name. Then it analyzes method signatures if there's a method applicable by so-called strict invocation (i.e. provided arguments and signature match exactly) no further action is needed (which is the case in all situations described above). Otherwise, compiler would try to apply widening reference conversion (in case if argument is of reference type).
Also note multiply(Operand) and multiply(Value) are overloaded methods, i.e. they absolutely independent and might have different return types, access modifiers and sets of parameters (which totally unacceptable for overridden methods).
This question already has answers here:
What does the type parameter <T> in the method definition mean? [duplicate]
(1 answer)
What are Generics in Java? [closed]
(3 answers)
Java Generics: Generic type defined as return type only
(6 answers)
Understanding generic parameters with void return types
(5 answers)
Closed 10 months ago.
I have the following class which builds:
public class Test<T> {
public T DoSomething(T value) {
return value;
}
}
I can also define it like this class like this (notice the extra in the DoSomething signature (which also builds):
public class Test<T> {
public <T> T DoSomething(T value) {
return value;
}
}
What is its purpose and when do I need to include it? I am asking about the additional <T> in the return type, not what generics are.
Maybe this will clear it up. The notation <T> declares a type variable.
So we have one variable T at the class level, and a redeclaration of that same symbol for a particular method.
class Test<T> {
<T> T doSomething(T value) {
// <T> declares a new type variable for this one method
System.out.println("Type of value: " + value.getClass().getSimpleName());
return value;
}
T doSomethingElse(T value) {
// T is not redeclared here, thus is the type from the class declaration
System.out.println("Type of value: " + value.getClass().getSimpleName());
return value;
}
public static void main(String... a) {
Test<String> t = new Test<>();
t.doSomething(42);
t.doSomething("foo"); // also works
t.doSomething(t); // contrived, but still works
t.doSomethingElse("hi");
t.doSomethingElse(42); // errors because the type `T` is bound to `String` by the declaration `Test<String> t`
}
}
In main, I create a Test<String> so the class-level T is String. This applies to my method doSomethingElse.
But for doSomething, T is redeclared. If I call the method with an Integer arg, then T for that case is Integer.
Really, it would have been better to call the second type variable anything else at all, on the declaration of doSomething. U, for example.
(In most cases, I actually favour giving useful names to type variables, not just single letters).
The concept is known as a generic method (docs.oracle.com).
In the code presented, we have an especially tricky case of generics since we have two generic parameters with the same name:
the <T> on the class-level: public class Test<T>, and
the <T> on the method-level: public <T> T DoSomething(T value)
The latter hides the former within the scope of the method DoSomething(...), just like a local variable would hide an instance field with the same name. In general, I would advice against this type of "hiding" since it makes the code harder to read and understand. Thus, for the rest of the discussion we will work with this (slightly modified) version of the code:
public class Test<T> {
public T doSomethingWithT(T t) {
return t;
}
public <U> U doSomethingWithU(U u) {
return u;
}
}
The scope of the class-level generic parameter T is for the whole class, while the scope of the method-level generic parameter U is only for the one method it is delared on. This will lead to the following observation:
// T is bound to type String for the instance testString:
final Test<String> testString = new Test<>();
final String tString = testString.doSomethingWithT("Hello");
System.out.println(tString); // prints "Hello"
// will not compile since 1 is not a String:
// int tInt = testString.doSomethingWithT(1);
// For this one invocation of doSomethingWithU(...), U is bound to
// type String:
final String uString = testString.doSomethingWithU("World!");
System.out.println(uString); // prints "World!"
// for this one invocation of doSomethingWithU(...), U is bound to
// type Integer:
final int uInt = testString.doSomethingWithU(1);
System.out.println(uInt); // prints "1"
Ideone demo
Notice that, although doSomethingWithU(...) is a generic method, we did not have to specify the generic parameter, the compiler inferred the type for us. While seldom used, we can also explicitly specify the generic parameter for thie method:
final Test<String> testString = new Test<>();
final Number number = testString.<Number>doSomethingWithU(1);
System.out.println(number);
Ideone demo
(In this example, the explicit generic parameter is not necessary, the code works without it aswell, but there are rare cases where this may be useful or even necessary.)
The following is not strictly necessary to understand generic methods, but more of a curiosity one might find in code and is meant to prime the reader that it is bad practice, should not be used and removed when seen.
It should also be mentioned that the JLS allows us to add generic method parameters on method invocations that do not have any generic parameter. Those parameter do not have any effect:
Object o = new Object();
// Method "hashCode()" on "Object" has not generic parameters, one
// can "add" one to the method invocation, it has no effect on the
// semantics, however
int hash = o.<String>hashCode();
Ideone demo
A remark on the code: In Java, methods should be written in camelCase instead of CamelCase (DoSomething(...) -> doSomething(...))
This question already has answers here:
:: (double colon) operator in Java 8
(17 answers)
Closed 2 years ago.
There is this other question that only explains passing function references but this does not answer the question below on how this Java assignment works, the conversion to this Supplier object and when this happens.
I have the following code snippet and struggling a bit to understand it and probably I am not the only one. Can someone give a "for dummies" explanation of this code (both the Supplier pattern and the assignment using double-colon (::) operator. When is Java actually making the function call? My expectation is that objectFactorySupplier becomes a function pointer.
private Supplier<ObjectFactory> getObjectFactorySupplier(String name) {
// how does this assignment work?
Supplier<ObjectFactory> objectFactorySupplier = this::getObjectFactory;
...
return objectFactorySupplier;
}
private ObjectFactory getObjectFactory() {
ObjectFactory factory = new ObjectFactorySupplier().get();
...
return factory;
}
Supplier is a functional interface introduced as part of Java 8. So, a functional interface can be substituted within lambda expression, for example: Runnable, Callable etc. So, by definition, it represents a supplier of results.
:: is a method reference
In your code,
Supplier<ObjectFactory> objectFactorySupplier = this::getObjectFactory;
this::getObjectFactory returns a method reference to your private method. And this method reference is assigned to the left hand side of the expression. And by its code definition, it basically supplies a objectFactory. It can be assigned because it qualifies for the definition of Supplier functional interface
Now, this method reference is used to get objectFactory ultimately.
The statement
Supplier<ObjectFactory> objectFactorySupplier = this::getObjectFactory;
could also b represented with lambda as
Supplier<ObjectFactory> objectFactorySupplier = () -> getObjectFactory();
which is easy to read, that without any input supply the return type of getObjectFactory method call.
And what does it return? an ObjectFactory! So it's easy to be inferred as and assigned to a Supplier<ObjectFactory> variable.
What is Supplier interface?
It is a functional interface. You can declare a lambda in java and use a functional interface as its target. Also it provides a single abstract method get() which is also called a functional method. get() is used to fetch the results that are returned by the Supplier whenever it is invoked.
Hence you can declare a supplier, invoke it and fetch its results by using the get.
An example
A very simple example to understand how to create a supplier and then use it. Here I have created a supplier for my Rectangle which will return a new rectangle of a width and height whenever the supplier is invoked.
public class Main
{
// A simple class
public static class Rectangle
{
int width, height;
public Rectangle(int w, int h) {
width = w; height = h;
}
#Override
public String toString() {
return String.format("width=%s height=%s", width, height);
}
}
public static void main(String[] args) {
// How to create a supplier?
Supplier<Rectangle> rectSupp = new Supplier<Rectangle>() {
/**
* Important to implement this functional method
*/
#Override
public Rectangle get() {
return new Rectangle(1, 2);
}
};
// How to create a lambda supplier?
Supplier<Rectangle> lambdaRectSupp = () -> new Rectangle(3, 4);
System.err.println(rectSupp.get());
System.err.println(lambdaRectSupp.get());
}
}
In my JavaFX, I attempted to have an ObservableMap<String, String> and a MapChangeListener that listens to keys and values changes(adding/removing a key or the corresponding value) and then does its job.
To make the listener be effective, the method to implement is:
void onChanged(MapChangeListener.Change<? extends K,? extends V> change)
What I first did, with a lambda expression, that doesn't generate any error:
map.addListener((MapChangeListener.Change<? extends String, ? extends String> change) -> {
//code here to implement onChange method
}
And here is what I discovered, that still doesn't generate any error:
map.addListener((MapChangeListener<String, String>) change -> {
//code here to implement onChange method
}
Note the position of the round brackets in this two different examples. The second seems to me to be a cast, but I really don't understand why this second option works.
Can anyone explain me this, please?
P.S.: Actually, I came accross this because I was dealing with a
ObservableMap<String, List<String>>,
that is a multimap, and the first "way" of the two above didn't work (with the right adjustments). /EDIT: I tried again with the first "way" and actually it does work, there was an error on the code I didn't notice END EDIT/. Then I tried with the second option, and it did work, and I was dazed. Then I discovered this same "behaviour" with a simple map <String, String> and this question has arisen.
These two are equivalent. The first one, you are defining the parameter of the lambda expression - note that your bracket covers the whole change parameter. This allows the compiler to know which overload to match it against.
The second one is simply a cast. You are telling the compiler what kind of method signature to match this lambda against. (MapChangeListener<String, String>) casts the whole lambda expression into a MapChangeListener, so the compiler knows that it really is addListener(MapChangeListener). Since you have defined the single parameter defined by MapChangeListener, the compiler doesn't complain that it is wrong either.
Edit
Now that I have a bit more time, I would give you some concrete example that will help you understand a little more in depth.
public class Foo {
public final void bar(IntfA a) {}
public final void bar(IntfB b) {}
public final void bar(IntfC c) {}
}
#FunctionalInterface
public interface IntfA {
void doSomething(Double a);
}
#FunctionalInterface
public interface IntfB {
void doSomething(Integer a);
}
#FunctionalInterface
public interface IntfC {
void doSomething(Double a);
}
public class Test {
public static void main(String[] args)
{
Foo foo = new Foo();
foo.bar(a -> {}); // Ambiguous
foo.bar((Integer a) -> {}); // Okay, this is IntfB
foo.bar((Double a) -> {}); // Ambiguous between IntfA and IntfC
foo.bar((IntfC) a -> {}); // No longer ambiguous since you specified that it's IntfC
foo.bar((IntfC) (a, b) -> {}); // Method signature does not match IntfC
}
}
Edit 2
It seems like you need a little more help here.
When you define a method bar(IntfA), you are expecting an object of IntfA, regardless whether IntfA is an interface type or a class type.
Then, lambda expressions are just compile-time convenient syntax. When I write foo.bar((Integer a) -> {}), the compiler will eventually turn it into Java bytecodes (within .class file) that is equivalent to this:
foo.bar(new IntfB() {
public void doSomething(Integer a) {
}
});
That equivalence is what we call Anonymous Class.
The biggest and possibly only difference in using lambda is, it makes your code shorter. Sometimes it makes your code more readable, sometimes it makes your code less readable.
Since lambda reduces the amount of things that you need to type out, it is very easy to have a lambda expression that is ambiguous for the compiler when there are overload methods like in the example. Remember that the compiler needs to figure out which overload first, then it will help you to instantiate the object for you.
When you write foo.bar((Double a) -> {}), the compile notices that you have a lambda expression that takes in one Double parameter and returns nothing. It will then look at the three overloads of bar(). It notices that both bar(IntfA) and bar(IntfC) takes in a functional interface, and both interface's method takes in one Double parameter and returns nothing. At this point, the compiler is not sure whether it should generate bytecodes equivalent to which two set of codes:
Choice 1:
foo.bar(new IntfA() {
public void doSomething(Double a) {
}
});
Choice 2:
foo.bar(new IntfC() {
public void doSomething(Double a) {
}
});
If you write foo.bar((IntfC) a -> {}), you are already hinting to the compiler that you want it to match foo.bar(IntfC) overload. The compiler sees that you have one parameter of unknown type, but since you have already tell it to match to IntfC, it will assume that parameter is Double.
Now to the last part, calling foo.bar(IntfA) doesn't automatically call the doSomething(Double a) method specified by IntfA. In my example the bar() methods did nothing, but normally people would write something useful.
Example again:
public final void bar(IntfB obj) {
if (obj == null)
System.out.println("I was waiting for an IntfB object but I got nothing!");
else
obj.doSomething(100);
}
foo.bar((Integer a) -> {
System.out.println("I got " + a + " marks for my exam!");
});
This causes "I got 100 marks for my exam!" to be printed on the console.
Lambda in reality doesn't require its type to be expressed unless there is an ambiguity.
If you would not type change it would conflict with addListener(InvalidationListener) that has the same argument length. There are 2 ways of solving this, either by explicitly expressing the type (your first snippet) or by directing the compiler to the correct overload (second), which has nothing to do with lambda semantics.
To reiterate the second point, say you have
void print(String s)
and
void print(Integer i)
calling
print(null) would cause an ambiguity. The solution is print((String)null) which is of course not a type cast, as null has no type, but rather a compiler note.
I'm playing around with Java 8 to find out how functions as first class citizens. I have the following snippet:
package test;
import java.util.*;
import java.util.function.*;
public class Test {
public static void myForEach(List<Integer> list, Function<Integer, Void> myFunction) {
list.forEach(functionToBlock(myFunction));
}
public static void displayInt(Integer i) {
System.out.println(i);
}
public static void main(String[] args) {
List<Integer> theList = new ArrayList<>();
theList.add(1);
theList.add(2);
theList.add(3);
theList.add(4);
theList.add(5);
theList.add(6);
myForEach(theList, Test::displayInt);
}
}
What I'm trying to do is pass method displayInt to method myForEach using a method reference. To compiler produces the following error:
src/test/Test.java:9: error: cannot find symbol
list.forEach(functionToBlock(myFunction));
^
symbol: method functionToBlock(Function<Integer,Void>)
location: class Test
src/test/Test.java:25: error: method myForEach in class Test cannot be applied to given ty
pes;
myForEach(theList, Test::displayInt);
^
required: List<Integer>,Function<Integer,Void>
found: List<Integer>,Test::displayInt
reason: argument mismatch; bad return type in method reference
void cannot be converted to Void
The compiler complains that void cannot be converted to Void. I don't know how to specify the type of the function interface in the signature of myForEach such that the code compiles. I know I could simply change the return type of displayInt to Void and then return null. However, there may be situations where it's not possible to alter the method I want to pass somewhere else. Is there an easy way to reuse displayInt as it is?
You are trying to use the wrong interface type. The type Function is not appropriate in this case because it receives a parameter and has a return value. Instead you should use Consumer (formerly known as Block)
The Function type is declared as
interface Function<T,R> {
R apply(T t);
}
However, the Consumer type is compatible with that you are looking for:
interface Consumer<T> {
void accept(T t);
}
As such, Consumer is compatible with methods that receive a T and return nothing (void). And this is what you want.
For instance, if I wanted to display all element in a list I could simply create a consumer for that with a lambda expression:
List<String> allJedi = asList("Luke","Obiwan","Quigon");
allJedi.forEach( jedi -> System.out.println(jedi) );
You can see above that in this case, the lambda expression receives a parameter and has no return value.
Now, if I wanted to use a method reference instead of a lambda expression to create a consume of this type, then I need a method that receives a String and returns void, right?.
I could use different types of method references, but in this case let's take advantage of an object method reference by using the println method in the System.out object, like this:
Consumer<String> block = System.out::println
Or I could simply do
allJedi.forEach(System.out::println);
The println method is appropriate because it receives a value and has a return type void, just like the accept method in Consumer.
So, in your code, you need to change your method signature to somewhat like:
public static void myForEach(List<Integer> list, Consumer<Integer> myBlock) {
list.forEach(myBlock);
}
And then you should be able to create a consumer, using a static method reference, in your case by doing:
myForEach(theList, Test::displayInt);
Ultimately, you could even get rid of your myForEach method altogether and simply do:
theList.forEach(Test::displayInt);
About Functions as First Class Citizens
All been said, the truth is that Java 8 will not have functions as first-class citizens since a structural function type will not be added to the language. Java will simply offer an alternative way to create implementations of functional interfaces out of lambda expressions and method references. Ultimately lambda expressions and method references will be bound to object references, therefore all we have is objects as first-class citizens. The important thing is the functionality is there since we can pass objects as parameters, bound them to variable references and return them as values from other methods, then they pretty much serve a similar purpose.
When you need to accept a function as argument which takes no arguments and returns no result (void), in my opinion it is still best to have something like
public interface Thunk { void apply(); }
somewhere in your code. In my functional programming courses the word 'thunk' was used to describe such functions. Why it isn't in java.util.function is beyond my comprehension.
In other cases I find that even when java.util.function does have something that matches the signature I want - it still doesn't always feel right when the naming of the interface doesn't match the use of the function in my code. I guess it's a similar point that is made elsewhere here regarding 'Runnable' - which is a term associated with the Thread class - so while it may have he signature I need, it is still likely to confuse the reader.
Set return type to Void instead of void and return null
// Modify existing method
public static Void displayInt(Integer i) {
System.out.println(i);
return null;
}
OR
// Or use Lambda
myForEach(theList, i -> {System.out.println(i);return null;});