I have this piece of code
public <T> someMethod(Supplier<T> supplier) {
Objects.requireNonNull(supplier);
SupplierThrowsException<T, Throwable> supplierThrowsException = supplier::get;
return withThrowable(supplierThrowsException);
}
I am calling it like this
obj.someMethod(() -> myMethod(message))
I am 100% sure that the class of the object returned by myMethod() does not implement Supplier interface. So where is the implementation of get().
I went through the Javadoc, I didn't get anything. I would like to understand what's going on here.
I found this and this but it doesn't clear my doubt. Let me know if I am missing anything here.
I am 100% sure that the class of the object returned by myMethod() does not implement Supplier interface.
Sure, but the expression () -> myMethod(message) does.
Please, read 15.27.4. Run-Time Evaluation of Lambda Expressions.
At run time, evaluation of a lambda expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. Evaluation of a lambda expression is distinct from execution of the lambda body.
Either a new instance of a class with the properties below is allocated and initialized, or an existing instance of a class with the properties below is referenced.
The value of a lambda expression is a reference to an instance of a class with the following properties:
The class implements the targeted functional interface type and, if the target type is an intersection type, every other interface type mentioned in the intersection.
In short, the lambda expression () -> myMethod(message) will be resolved to an instance of Supplier.
Where is the implementation of get()?
You've provided it within the lambda body.
() -> myMethod(message)
(it's a statement expression, a shorter form to construct a lambda body)
() -> {
return myMethod();
}
(it's a value-compatible block, a more expanded version where many statements may be declared)
In this call:
obj.someMethod(() -> myMethod(message))
you are implementing the Supplier interface using a lambda expression - () -> myMethod(message).
It is as if (I say "as if" because this is not what actually happens under the hood. Here is what happens under the hood) you have created an inner class implementing Supplier like this:
static class MyInnerClass implements Supplier<SomeClass> {
public SomeClass get() {
return myMethod(message);
}
}
And then passed new MyInnerClass() to someMethod.
I think this document may shed some light on your question:
https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#target-typing
To determine the type of a lambda expression, the Java compiler uses the target type of the context or situation in which the lambda expression was found. It follows that you can only use lambda expressions in situations in which the Java compiler can determine a target type:
Variable declarations
Assignments
Return statements
Array initializers
Method or constructor arguments
Lambda expression bodies
Conditional expressions, ?:
Cast expressions
Supplier is a functional interface and contains following single abstract method:
#FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* #return a result
*/
T get();
}
Now, you have provided definition of get method along with instantiation with following invocation:
obj.someMethod(() -> myMethod(message))
Above line gets translated as follows:
obj.someMethod(new Supplier() {
#Override
public T get()
{
return myMethod(message);
}
});
Related
I'm learning Java at the moment and I see some code that looks like this:
public interface Await {
boolean await(long timeout, TimeUnit timeUnit) throws InterruptedException;
}
public Await spinServerUp() {
this.startServers()
return (timeout, timeUnit) -> countDownLatch.await(timeout, timeUnit);
}
Now, I understand that countDownLatch waits for the threads to complete before continuing on.
My question is - how do parameters timeout and timeunit get passed to the Lambda expression? I can't find any usage examples on my end for this block of code that I'm reading, so I'm a bit confused.
I'm also not sure if I follow the spinServerUp() method that well, I understand that it calls this.startServers() then returns the Lambda expression - thus giving control to the Lambda expression. Why return the Lambda expression, though?
I've tried to do some research and reading, but I got more confused. Any clarifications would be appreciated
how do parameters timeout and timeunit get passed to the Lambda expression?
Just treat the returnValue as a function. Basically same as function you declared in class:
Await await = spinServerUp();
await.await(3, TimeUnit.SECONDS);
Why return the Lambda expression though?
Lambda function declaration does nothing util you call it like code snippet above.
The typical usage of lambda is callback. It is something that will happen if certain event is triggered (e.g. mouse clicked on a button). So it will not do anything if certain event is not triggered.
Or for a real world example. Jack told Nick to [call him] if Bob arrived. Call Jack is the lambda in this case and it will only be triggered if Bob arrived.
public ThingsToDo planForBobArriving() {
String personToCall = "Jack";
return () -> call(personToCall);
}
public void mainLogic() {
ThingsToDo thingsToDoWhenBobArrived = planForBobArriving();
while(keepWaiting) {
if (bobArrived()) {
thingsToDoWhenBobArrived.execute(); // call Jack
break;
}
}
}
Await is a Functional interface (i.e. an interface defining only a single abstract method).
And method spinServerUp() produces an implementation of this Functional interface (which is expressed in the form of Lambda expression).
Hence, in what ever place that requires an instance of Await you can use a Method reference intanceName::spinServerUp(), where intanceName is a reference to the instance of a class that own method spinServerUp(), also within the owning class you can use this keyword this::spinServerUp().
how do parameters timeout and timeunit get passed to the Lambda expression?
Suppose you have the following method:
public void foo(long timeout, TimeUnit timeUnit, Await a) {
a.await(timeout, timeout);
}
You can call it like that:
foo(5, TimeUnit.MILLI_SCALE, intanceName::spinServerUp()
The parameters require by the Await contract should be provided by the code that uses it directly by invoking Await.await().
I understand that it calls the this.startServers() then returns the Lambda expression - thus giving control to the Lambda expression.
If you mean that you think that while spinServerUp() gets executed it also fairs the logic of the lambda expression, then it's not correct. A Lambda expression (as well a method references) is just a way to obtain an instance of a Function interface. Lambda basically is an object representing a certain behavior, when you're defining a lambda this behavior doesn't get executed.
In order to actually execute the behavior of a lambda expression, you need to plug the reference to it into a code which would invoke the abstract method of the Function interface it's represents (Await.await(), Function.apply(), Predicate.test(), etc.).
I recommend you to get familiar with these tutorials on Lambda expressions and Method references provided by Oracle
You can use the lamda to invoke the await function:
try {
if (spinServerUp().await(1, MINUTES)) {
// do stuff
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
// just exit on interruption?
}
recently i started reading about java8 features,and one such feature i came across was
default method
,there is nothing unique as far as concept is concerned,but i stumbled across this code snippet which used lambda expression for returning the value(void) from the default method.but i see that the return type of the default method is of the type interface.(which i believe should be void),since the logic inside the default method doesn't return anything ,Now i am puzzled by the behavior as i don't see any compilation error,But when i set the type of the default method as void ,the compiler spouts(The target type of this expression must be a functional interface) error. Could someone explain about this behavior wrt to the lambda usage.
public interface Op {
void runOp();
static void timeOperation(Op testOp) {
}
default Op combinedOp(Op secondOperation) {
return ()->{secondOperation.runOp();};
}
}
You can always write a lambda expression in a non-lambda way
with an anonymous class containing the implementation of the single abstract method.
Applied to your example, you can write the method
default Op combinedOp(Op secondOperation) {
return ()->{secondOperation.runOp();};
}
in a non-lambda way like this:
default Op combinedOp(Op secondOperation) {
return new Op() {
#Override
public void runOp() {
secondOperation.runOp();
}
};
}
Now it is clearer to see that the combinedOp method returns something,
i.e. an instance of the Op interface.
However, the runOp method of this instance returns nothing.
Hence its return type is void.
Op is a functional interface i.e. an interface with a SAM (single abstract method).
The combinedOp is a default method which takes an Op as a parameter and returns an Op not void. In Java, functional interfaces can be used as target types for lambda expressions or method references hence the code below is completely valid:
default Op combinedOp(Op secondOperation) {
return ()->{secondOperation.runOp();};
}
this code consumes an Op which then returns a function which when called upon will execute the secondOperation function.
I am using this code:
renameWindow.showingProperty().addListener(new InvalidationListener() {
#Override
public void invalidated(Observable observable) {
//Remove the Invalidator Listener
renameWindow.showingProperty().removeListener(this);
}
});
And i want to do in lambda way and i use:
renameWindow.showingProperty().addListener(listener->{
renameWindow.showingProperty().removeListener(this);
});
and i am getting error cause maybe the listener is the Observable interface or what?.I want to do this using lambda expression.How can this be done?How to remove the InvalidationListener using lambda.
this refers to a instance of the class containing the code, not to the lambda expression itself.
jls-15.27.2: Lambda Body
Unlike code appearing in anonymous class declarations, the meaning of names and the this and super keywords appearing in a lambda body, along with the accessibility of referenced declarations, are the same as in the surrounding context (except that lambda parameters introduce new names).
Therefore you're trying to call removeListener with a object as parameter that doesn't implement InvalidationListener or ChangeListener, which means none of the removeListener methods is applicable.
The only way to get a reference to the lambda expression is by using some expression access a reference to it from the lambda body that is evaluated at the time the lambda body is executed.
This could be done e.g. by assigning it to a field.
Example
private InvalidationListener listener = observable -> renameWindow.showingProperty().removeListener(this.listener);
I know about lambda method references.
However, I am wondering whether the reverse might be possible, because I have a method that just proxies its arguments to a lambda:
Function<Arg, Result> lambda = (a) -> new Result(a);
public Result myMethod(Arg arg) {
return lambda.apply(a);
}
Haven't found anything on Google, so I guess it's not possible. Which makes sense, because after all, as I understand it, a lambda is just shorthand for a whole interface. A method and an interface are different. But you can make a lambda from a method, so maybe you can make a method from a lambda?
You can't make a method from a lambda because, as you say, a lambda is not a method and more importantly you cannot dynamically change a class by adding methods to it at runtime. That's a basic design invariant of Java classes. It is possible to dynamically respond to a predefined method of an interface with your own implementation, although it's fairly clunky. Take a look at http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html
The variable lambda has the type Function which doesn’t say anything about how the instance has been created. It might be a lambda expression, but it doesn’t have to. That said, if you want to delegate myMethod to a method declared in Function, there is no reason to automatically choose the abstract method of that interface, so, similar to method references, you would have to specify the target method like lambda::apply to make clear you want that method and not one of the other methods of the interface Function.
But unlike method references, which use a target type, you can’t derive a method declaration from the surrounding context, so you can’t spare the method declaration. So such a hypothetical feature would still require the method declaration, the reference to the lambda field and the target method name (apply), so there is not much left that you can save that would justify a new language feature.
And there is no need for such a functionality anyway. If you have code to be expressed as both, a function and a method, express it as method:
Instead of
Function<Arg, Result> lambda = (a) -> new Result(a);
public Result myMethod(Arg arg) {
return lambda.apply(a);
}
write
Function<Arg, Result> lambda = this::myMethod;
public Result myMethod(Arg arg) {
return new Result(arg);
}
But even a code replication might be acceptable, as in
Function<Arg, Result> lambda = (a) -> new Result(a);
public Result myMethod(Arg arg) {
return new Result(arg);
}
considering that lambda expressions should host rather small, often trivial, code only.
In Java 8 it looks like the lambdas of a class are kept in an array. For example, lets say we have this class:
public class LambdaFactory {
public Supplier<Integer> getOne(){
return () -> 42;
}
public Supplier<Integer> getTwo(){
return () -> 128;
}
public Supplier<Integer> getThree(){
return () -> 3;
}
}
and then I print it out like so:
System.out.println(factory.getOne());
System.out.println(factory.getOne());
System.out.println(factory.getTwo());
System.out.println(factory.getThree());
the output will be something like
examples.LambdaFactory$$Lambda$1#4e515669
examples.LambdaFactory$$Lambda$1#4e515669
examples.LambdaFactory$$Lambda$2#1b9e1916
examples.LambdaFactory$$Lambda$3#ba8a1dc
So we can see two thing here. The same lambda called twice gives us the same lambda object (this is not the same as with anon inner classes where we could get a new one every time). We also see that they look like they are being kept in some kind of "Lambda" structure that is part of the class
My question is, can I get ahold of the lambdas in a class? I don't have any reason to do so, I just like dissecting things
The lambdas are created by the JRE and the way they are created is controlled by the JRE and might vary between different JRE vendors and might change in future versions.
If you want to have fun you can create a lambda at runtime which has no corresponding information within the class file:
import java.lang.invoke.*;
public class ManualLambda {
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup me=MethodHandles.lookup();
MethodType t=MethodType.methodType(void.class);
MethodType rt=MethodType.methodType(Runnable.class);
CallSite site = LambdaMetafactory.metafactory(
me, "run", rt, t, me.findStatic(ManualLambda.class, "sayHello", t), t);
MethodHandle factory=site.getTarget();
Runnable r=(Runnable)factory.invoke();
System.out.println("created lambda: "+r);
r.run();
}
private static void sayHello() {
System.out.println("hello world");
}
}
The code above retraces what happens when a lambda is created. But for compile-time (“real”) lambda expressions the entire thing is triggered by a single invokedynamic byte code instruction. The LambdaMetafactory.metafactory(…) method is the bootstrap method which is called when the invokedynamic instruction is executed the first time. The returned CallSite object is permanently associated with the invokedynamic instruction. If the CallSite is a ConstantCallSite and its MethodHandle returns the same lambda object on every execution, the invokedynamic instruction will “produce” the same lambda instance forever.
The Java Language Specification states
At run time, evaluation of a lambda expression is similar to
evaluation of a class instance creation expression, insofar as normal
completion produces a reference to an object. [...]
Either a new instance of a class with the properties below is
allocated and initialized, or an existing instance of a class with the
properties below is referenced.
[...]
These rules are meant to offer flexibility to implementations of the
Java programming language, in that:
A new object need not be allocated on every evaluation.
[...]
As such, it is up to a compiler or run time environment to decide what should be returned when a lambda expression is evaluated.
My question is, can I get ahold of the lambdas in a class? I don't
have any reason to do so, I just like dissecting things
You can think of a lambda expression as any other class constant, a String, an integer literal, etc. These are constants that appear in the constant pool of a .class file. These are references to objects that are created and exist at run time. There is no way to refer to the actual objects from a class' constant pool.
In the case of a lambda, it wouldn't be helpful anyway because it might not actually be the same object.