How does this lambda feature in java 8 work? - java

I am trying to use java 8 features. While reading official tutorial I came across this code
static void invoke(Runnable r) {
r.run();
}
static <T> T invoke(Callable<T> c) throws Exception {
return c.call();
}
and there was a question:
Which method will be invoked in the following statement?"
String s = invoke(() -> "done");
and answer to it was
The method invoke(Callable<T>) will be invoked because that method returns a value; the method invoke(Runnable) does not. In this case, the type of the lambda expression () -> "done" is Callable<T>.
As I understand since invoke is expected to return a String, it calls Callable's invoke. But, not sure how exactly it works.

Let's take a look at the lambda
invoke(() -> "done");
The fact that you only have
"done"
makes the lambda value compatible. The body of the lambda, which doesn't appear to be an executable statement, implicitly becomes
{ return "done";}
Now, since Runnable#run() doesn't have a return value and Callable#call() does, the latter will be chosen.
Say you had written
invoke(() -> System.out.println());
instead, the lambda would be resolved to an instance of type Runnable, since there is no expression that could be used a return value.

Related

Why does .forEach(val -> list.add()) compile whereas .forEach(val -> true) doesn't? [duplicate]

This question already has answers here:
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)
Closed 4 years ago.
It's better to express this behavior in the code:
List<Integer> list= new ArrayList<>();
Stream.of(1,2,3).forEach(i -> list.add(1)); // COMPILES
Stream.of(1,2,3).forEach(i -> true); // DOES NOT COMPILE!
forEach(...) accepts Consumer, but why does the first example compile if List interface has following signature boolean add(E e)? whereas the second yields:
bad return type in lambda expression: boolean cannot be converted to
void
Though you might be looking just for
Stream.of(1,2,3).forEach(list::add); // adding all to `list`
why does the first example compile if List interface has following
signature boolean add(E e)
Primarily because the return type of the method is ignored in the first call. This is what it expands to:
Stream.of(1,2,3).forEach(new Consumer<Integer>() {
#Override
public void accept(Integer i) {
list.add(1); // ignored return type
}
}); // COMPILES
On the other hand, the other lambda representation is more like a Predicate(which is also a FunctionalInterface) represented as returning true always from its test method. If you even try to represent it as a Consumer, it might just look like
Stream.of(1,2,3).forEach(new Consumer<Integer>() {
#Override
public void accept(Integer i) {
return true; // you can correlate easily now why this wouldn't compile
}
}); // DOES NOT COMPILE!
To add to the design basis via a comment from Brian
Java allows you to call a method and ignore the return value (a method invocation expression as a statement). Since we allow this at
the invocation, we also allow this when adapting a method to a
functional interface whose arguments are compatible but the functional
interface is void-returning.
Edit: To put it in his own words as close to the language spec:
More precisely, list.add(x) is a statement expression, and
therefore is void-compatible. true is not a statement expression,
and therefore not void-compatible. forEach(Consumer) requires a
void-compatible lambda.
forEach() as a Consumer as the one and only parameter therefore you need to give an implemention of the method accept() which returns void so on the second example you're implementing a method with the given assinature static boolean method(int).
The Special Void-Compatibility Rule (JLS) says that a lambda that returns void may accept a statement whose return is non-void. In this case, the return is discarded. hence this compiles.
Stream.of(1,2,3).forEach(i -> list.add(1)); // return value of add is ignored
To word it a bit differently by quoting Java-8 in Action book:
If a lambda has a statement expression as its body, it’s compatible
with a function descriptor that returns void (provided the parameter
list is compatible too). For example, both of the following lines are
legal even though the method add of a List returns a boolean and not
void as expected in the Consumer context (T -> void):
// Predicate has a boolean return
Predicate<String> p = s -> list.add(s);
// Consumer has a void return
Consumer<String> b = s -> list.add(s);
As for the second example, this is explicitly trying to return a boolean where it's not expected hence not possible.
Stream.of(1,2,3).forEach(i -> true);
in other words:
Stream.of(1,2,3).forEach(i -> {return true;});
As you already know forEach takes a Consumer so attempting to "explicitly" return a boolean should & will yield a compilation error.

Meaning of lambda () -> { } in Java

I am looking at the following Stack Overflow answer:
How to change Spring's #Scheduled fixedDelay at runtime
And in the code there is the following line:
schedulerFuture = taskScheduler.schedule(() -> { }, this);
I would like to know what the lambda () -> {} means in that code. I need to write it without using lambdas.
Its a Runnable with an empty run definition. The anonymous class representation of this would be:
new Runnable() {
#Override public void run() {
// could have done something here
}
}
Lamda expression is an anonymous function that allows you to pass methods as arguments or simply, a mechanism that helps you remove a lot of boilerplate code. They have no access modifier(private, public or protected), no return type declaration and no name.
Lets take a look at this example.
(int a, int b) -> {return a > b}
In your case, you can do something like below:
schedulerFuture = taskScheduler.schedule(new Runnable() {
#Override
public void run() {
// task details
}
}, this);
For lambdas:
Left side is arguments, what you take. Enclosed in () are all the arguments this function takes
-> indicates that it's a function that takes what's on the left and passes it on to the right for processing
Right side is the body - what the lambda does. Enclosed in {} is everything this function does
After you figure that out you only need to know that that construction passes an instance of matching class (look at what's the expected argument type in the schedule() call) with it's only method doing exactly the same as the lambda expression we've just analyzed.
Lambda expressions basically express instances of functional interfaces.
In a way Lambda expression will be: (lambda operator params) -> {body}
() -> System.out.println("This means Lambda expression is not taking any parameters");
(p) -> System.out.println("Lambda expression with one parameter: " + p);

Why can this lambda expression assigned to different functional interfaces? [duplicate]

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".

Java 8 Consumer/Function Lambda Ambiguity

I have an overloaded method that takes a Consumer and a Function object respectively and returns a generic type that matches the corresponding Consumer/Function. I thought this would be fine, but when I try to call either method with a lambda expression I get an error indicating the reference to the method is ambiguous.
Based on my reading of JLS §15.12.2.1. Identify Potentially Applicable Methods: it seems like the compiler should know that my lambda with a void block matches the Consumer method and my lambda with a return type matches the Function method.
I put together the following sample code that fails to compile:
import java.util.function.Consumer;
import java.util.function.Function;
public class AmbiguityBug {
public static void main(String[] args) {
doStuff(getPattern(x -> System.out.println(x)));
doStuff(getPattern(x -> String.valueOf(x)));
}
static Pattern<String, String> getPattern(Function<String, String> function) {
return new Pattern<>(function);
}
static ConsumablePattern<String> getPattern(Consumer<String> consumer) {
return new ConsumablePattern<>(consumer);
}
static void doStuff(Pattern<String, String> pattern) {
String result = pattern.apply("Hello World");
System.out.println(result);
}
static void doStuff(ConsumablePattern<String> consumablePattern) {
consumablePattern.consume("Hello World");
}
public static class Pattern<T, R> {
private final Function<T, R> function;
public Pattern(Function<T, R> function) {
this.function = function;
}
public R apply(T value) {
return function.apply(value);
}
}
public static class ConsumablePattern<T> {
private final Consumer<T> consumer;
public ConsumablePattern(Consumer<T> consumer) {
this.consumer = consumer;
}
public void consume(T value) {
consumer.accept(value);
}
}
}
I also found a similar stackoverflow post that turned out to be a compiler bug. My case is very similar, though a bit more complicated. To me this still looks like a bug, but I wanted to make sure I am not misunderstanding the language spec for lambdas. I'm using Java 8u45 which should have all of the latest fixes.
If I change my method calls to be wrapped in a block everything seems to compile, but this adds additional verbosity and many auto-formatters will reformat it into multiple lines.
doStuff(getPattern(x -> { System.out.println(x); }));
doStuff(getPattern(x -> { return String.valueOf(x); }));
This line is definitely ambiguous:
doStuff(getPattern(x -> String.valueOf(x)));
Reread this from the linked JLS chapter:
A lambda expression (§15.27) is potentially compatible with a functional interface type (§9.8) if all of the following are true:
The arity of the target type's function type is the same as the arity of the lambda expression.
If the target type's function type has a void return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2).
If the target type's function type has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (§15.27.2).
In your case for Consumer you have a statement expression as any method invocation can be used as statement expression even if the method is non-void. For example, you can simply write this:
public void test(Object x) {
String.valueOf(x);
}
It makes no sense, but compiles perfectly. Your method may have a side-effect, compiler doesn't know about it. For example, were it List.add which always returns true and nobody cares about its return value.
Of course this lambda also qualifies for Function as it's an expression. Thus it's ambigue. If you have something which is an expression, but not a statement expression, then the call will be mapped to Function without any problem:
doStuff(getPattern(x -> x == null ? "" : String.valueOf(x)));
When you change it to { return String.valueOf(x); }, you create a value-compatible block, so it matches the Function, but it does not qualify as a void-compatible block. However you may have problems with blocks as well:
doStuff(getPattern(x -> {throw new UnsupportedOperationException();}));
This block qualifies both as a value-compatible and a void-compatible, thus you have an ambiguity again. Another ambigue block example is an endless loop:
doStuff(getPattern(x -> {while(true) System.out.println(x);}));
As for System.out.println(x) case it's a little bit tricky. It surely qualifies as statement expression, so can be matched to Consumer, but seems that it matches to expression as well as spec says that method invocation is an expression. However it's an expression of limited use like 15.12.3 says:
If the compile-time declaration is void, then the method invocation must be a top level expression (that is, the Expression in an expression statement or in the ForInit or ForUpdate part of a for statement), or a compile-time error occurs. Such a method invocation produces no value and so must be used only in a situation where a value is not needed.
So compiler perfectly follows the specification. First it determines that your lambda body is qualified both as an expression (even though its return type is void: 15.12.2.1 makes no exception for this case) and a statement expression, so it's considered an ambiguity as well.
Thus for me both statements compile according to the specification. ECJ compiler produces the same error messages on this code.
In general I'd suggest you to avoid overloading your methods when your overloads has the same number of parameters and has the difference only in accepted functional interface. Even if these functional interfaces have different arity (for example, Consumer and BiConsumer): you will have no problems with lambda, but may have problems with method references. Just select different names for your methods in this case (for example, processStuff and consumeStuff).

Java - Passing a method through a parameter

I'm trying to create a method that allows me to make use of what I believe is called lambdas, to execute a method over a series of connections.
Here's my code that I've come up with after some research, but it doesn't work:
performGlobalAction(()->{
// doSomething();
});
You'll also need to see the method I would assume:
private <T> void performGlobalAction(Callable<T> action) {
for(int i = 0; i < connectionList.size(); i++) {
connectionList.get(i).performAction(action);
}
}
This provides the following error:
The method performAction(Callable<T>) in the type Connection is not
applicable for the arguments (() -> {})
The goal of this method is to allow myself to construct a method "on the go" without creating a void for it.
Is this possible? It seems like I've used plenty of statements that have done this before. It seems like this is actually exactly how lambdas statements work.
The call method of the Callable interface returns a value of type T. Your lambda is simply shorthand for the call method, and likewise should return a T value.
Any interface that meets the requirements of a FunctionalInterface can be substituted by a lambda expression. Such an interface will have a single abstract method, one with no default implementation. For your question, the interface is Callable, and the abstract method is call. The lambda expression then acts as the body of that abstract method in an anonymous implementation of that interface.
Let's take as an example a method doStuff(Callable<Integer> stuff). To satisfy this interface, you could give an anonymous class:
doStuff(new Callable<Integer>(){
public Integer call(){
return 5;
}
});
Or you could use a lambda:
doStuff( () -> {
return 5;
} );
Or even more succinctly:
doStuff( () -> 5 );
If your method doesn't have a return type, perhaps Runnable would be a better fit.
See also: Lambda Expressions (Oracle) - 'Use Standard Functional Interfaces with Lambda Expressions'

Categories

Resources