I am writing a snippet:
List<Integer> list=Arrays.toList(2,4,6,8);
list.forEach(i -> System.out.println(i));
Please explain me the flow of method call in the above snippet. How the forEach() method is passing the parameters to the accept() method? Does the forEach() method calls the accept method each time?
Please correct me if I am wrong.
i-> System.out.println(i)
returns an object of Consumer interface. forEach() calls the accept() method of that object with i as the parameter.
Because Consumer is a functional interface, your lambda function can implicitly satisfy it. So when you do
list.forEach(i -> System.out.println(i));
what you're doing conceptually (more below) is
list.forEach(new Consumer<String>() {
#Override
public void accept(String i) {
System.out.println(i);
}
});
The instance is then passed into forEach, which calls its accept method for each entry in the list.
From a comment you made on the question:
I am confused which method is invoked first. Is it the "forEach()" or the "accept ()" because both of them are working togather!
The order of things is:
An instance of the anonymous class is created (in effect, via the invokedynamic operation)
forEach is called, passing in that reference
forEach's code calls accept repeatedly, each time passing one of the list items into it (which it receives as i)
Note I said conceptually. An anonymous class isn't really created by the compiler; instead, a new bytecode operation called invokedynamic is used to create the consumer instance.
Related
Would appreciate any help on understanding below two concepts in Java 8.
What I know
A lambda is an object without an identity and should not be used as a regular object.
A lambda expression should not be calling methods from Object class like toString, equals, hashCode etc.
What I'd like know more about
What difference does lambda expression have to be called as an object without identity?
Why exactly should methods from Objectclass not be used while using lambda expression?
1) A lambda is an object without an identify and should not be used as a regular object.
This is not true. A lambda is a Java object, and it does have an identity1. The problem is that the lifecycle is deliberately left specified to allow Java compilers freedom to optimize the code that evaluates them. Therefore, you cannot know when new lambda objects are going to be created, or existing ones are going to be reused.
JLS 15.27.4 says:
"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. ... "
2) A lambda expression should not be calling methods from Object class like toString, equals, hashCode etc.
As written, that is also not true. A lambda expression may call those methods. However, it is not advisable to rely on those methods to have any specific behavior when you call them on a lambda object
The JLS states:
"The class ... may override methods of the Object class."
In other words, it may ... or may not ... override them. If you rely a particular behavior of these methods, your application is (in theory) non-portable.
Furthermore, since the instantiation semantics are also unspecified, the behavior of Object::equals and Object::hashCode are uncertain.
Finally, it is unspecified whether lambdas are clonable.
1 - Sure, a lambda doesn't have a name: it is anonymous. But name and identity are different concepts.
Basically, a lambda is a convenience of doing this:
#FunctionalInterface
interface A {
void b();
}
void c(A a) {
...
}
void main() {
c(new A() {
void b() {
...
}
});
}
I apologize for the less than stellar variable names, but as you can see, A is an interface with one method. c is a method that takes in an A interface. However, instead of creating your own class that implements A, you can create it on the spot. This is what you call an anonymous class, since it doesn't have a name. This is where the quote you have:
A lambda is an object without an identify
comes from. The class doesn't have an identity. The reason it relates to lambdas is because if an interface has only one method, you can use lamdas to simplify it.
void main() {
c(
() -> {
...
}
);
}
This is the exact same as before.
The second part, why lambdas shouldn't use Object's methods, I didn't know before. You should probably have someone else answer this, however my guess is that lambda classes don't look like it extends Object directly, so you can't use it's methods.
Can we be sure that methods being called in a java lambda are only being called when the lambda itself is executed, and never in advance?
If you take a look at my code:
StringBuilder myStringBuilder = new StringBuilder("my result");
Supplier<String> mySupplier = () -> "result: " + myStringBuilder.toString();
myStringBuilder.append(", after appending.");
System.out.println(mySupplied.get());
Can we be 100% certain that the result will always be:
result: my result, after appending
And never just
result: my result
Consider the following snappet:
Runnable runnable = () -> expensiveMethod(); // Runnable not called
firstMethodCall(); // Runnable not called
secondMethodCall(); // Runnable not called
runnable.run(); // HERE IT COMES, Runnable IS called
The lambda expression is nothing else than the implementation of an anonymous class with one method (this secures #FunctionalInterface annotation).
Runnable runnable = new Runnable() {
void run() {
expensiveMethod();
}
};
// runnable's method is not executed since the method run is not called
// the runnable.run() invokes the expensiveMethod()
The Java 8 specification 15.27. Lambda Expressions explains that the expression is called when the appropriate method of the functional interface is invoked:
Evaluation of a lambda expression produces an instance of a functional interface (§9.8). Lambda expression evaluation does not cause the execution of the expression's body; instead, this may occur at a later time when an appropriate method of the functional interface is invoked.
Yes. The lambda code only executes when called not when the containing line is executed.
As per the spec
Lambda expression evaluation does not cause the execution of the expression's body; instead, this may occur at a later time when an appropriate method of the functional interface is invoked.
Lambda is like implementation code of an interface and just like an interface implementation, it will only be executed when you call it.
Lamba is an implementation of a Functional Interface. Its content will be changed / computed at the time of its call.
So, yes, you can 100% be sure about your assumption :)
This is my first code:
public class MethodReference {
public static void main (String []args) {
Stream<String> s = Stream.of("brown bear", "grizzly");
s.sorted(Comparator.reverseOrder()).forEach(System.out::print);
//...
}
}
Result: grizzlybrown bear
This is my second code:
public class MethodReference {
public static void main (String []args) {
Stream<String> s = Stream.of("brown bear", "grizzly");
s.sorted(Comparator::reverseOrder()).forEach(System.out::print);
//...
}
}
Result: compiler error
My questions:
Why is there a compiler error in the second code?
Can't I use the method reference for static method of functional interface?
I know I can't use method reference with default method of functional interface.
I know I can use method reference with a class in 5 cases:
Class
Class::staticMethod
Class::instanceMethod
instance::instanceMethod
Class::new
Functional Interface
Interface::abstractMethod
Thanks a lot!
Comparator.reverseOrder() is an expression which resolves to the Comparator type, because that's what it returns.
Comparator::reverseOrder is an expression which resolves to a method which takes no arguments and returns a Comparator e.g. a Supplier<Comparator<String>>, though it could be any matching functional interface.
In the second instance you are trying to pass a method (which provides a Comparator) as an argument. The method doesn't want that - it just wants the Comparator itself.
You could think of it like this (just pseudo-code to demonstrate the point):
s.sorted(new Comparator())
vs
s.sorted(new Supplier(new Comparator()))
To answer your second question as to whether it's ever possible to use a method reference for a static method of an interface - yes, absolutely!
If we declare the following method:
<T> void giveMeAComparatorSupplier(Supplier<Comparator<T>> supplier) { }
then we can definitely call it with a method reference
giveMeAComparatorSupplier(Comparator::reverseOrder);
(And FYI your method reference syntax is wrong - it never uses ())
Two things are wrong with your second code. First, method references do not use parentheses or arguments at all. You would need to supply only the method that would be called later; you are not calling the method at that point.
Second, the sorted method takes a Comparator, not a functional interface that would supply a Comparator. The method needs a Comparator already created and ready to go, not a functional interface that will supply a Comparator when needed.
It has nothing to do with the fact that Comparator is an interface; one can generally create a method reference to a static interface method. It has everything to do with the fact that sorted needs an actual Comparator instance and not an instance of a functional interface, which is when you could supply a method reference.
So even if you take off the parentheses, it still won't compile. Only your first code, which directly passes a Comparator, will compile and work as expected.
I am new to functional programming, so far i have understood how to use it, anonymous function etc.
I saw many examples of code where the object needed as parameter in my lambda expression actually doesn't exist in that moment (it isn't instantiated).
For example, is this:
myClass.myMethod(c -> {my overridden code});
the same as this
myClass.myMethod(new String() -> {my overridden code});
considering that c is not declared in my code and myMethod correctly implements a functional interface which abstract method requires a String?
EDIT:
I got some problems with this question:
JavaFX ComboBox Image
With this part of code:
comboBox.setCellFactory(c -> new StatusListCell());
I can't figure out where c is taken from, it's not declared at all, that's why i was wondering if lambda expressions could create new objects automatically.
c is actually only a placeholder, like a parameter in a method would be (which does not differ from the functioning of the lambda here).
myClass.myMethod(c -> {my overridden code});
is the equivalent of the following
myClass.myMethod(new Consumer<String>(){
#Override
public void accept(String c) {
{my overridden code}
}
}
So the answer to your question is : No. The lambda represents a method, a function but is not an executable piece by itself, it has to be invoked with outside parameters.
I am new to java8. I was trying to understand working of foreach loop in Streams.
My code is as follows:-
Stream<String> s = someist.stream();
Consumer<String> consumer = (String s1)->System.out.println(s1);
s.forEach(consumer);
Question is how does foreach loop know to call consumer.accept(T t) when i am just passing the reference of Consumer and not calling consumer.accept(T t) inside it. Although, when we provide some lambda expression for a functional interface we need to call its abstract method, we are just not calling it here.
So how does foreach loop comes to know what should it do with the consumer reference provided as a parameter?
The concrete implemention of forEach will call accept, for example:
public class MyStream implements Stream<String> {
#Override
public void forEach(Consumer<? super String> action) {
while (hasNext()) {
action.accept(next());
}
}
...
}
As the java doc states:
void forEach​(Consumer<? super T> action)
Performs an action for each
element of this stream.
i.e the behavioural parameter passed to the forEach method will be called internally for each element of the source.
This is how Functional Interface works. They have only one abstract method. There might be optional default methods. The behaviour of the abstract method is passed in form of lambda expression (passing behaviour as if data). This behaviour is, in turn, the method body for the abstract method of the Functional Interface. The default methods are called using their names.
So when you pass a Functional Interface as a method parameter to another method, in this case, Consumer<T> to the forEach() method of java.util.stream.Stream interface, its abstract method accept(T t) is called for each item of the stream.
Put it this way, logically, there's only one method to be invoked if only the Functional Interface is passed as a parameter.