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.
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.
The IDE's recommended fix generated code like the following.
col1.setCellValueFactory(
(Callback<CellDataFeatures<String, String>, ObservableValue<String>>) param ->
new SimpleObjectProperty<>(param.getValue().getValue())
);
I do not understand the param between ObservableValue<String>>) and ->. Is there a hint like what this is called so that I can search the web for more details about this type of code?
Below are the signatures of the methods and interface.
void setCellValueFactory(Callback<TreeTableColumn.CellDataFeatures<S, T>, ObservableValue<T>> var1)
public interface Callback<P, R> {
R call(P var1);
}
PS: Since some person told me to specify col1, it is an object of the TreeTableColumn class in JavaFX.
I think I was deceived by the parentheses and the param's not having parenthesis, and thought those in the parentheses were the parameters. I had expected a form like below.
On close inspection, the code inside the parentheses is just type declarations, not variables... And it seems that parentheses for parameters can be omitted when there is only one parameter.
param is the parameter that is being passed on to lambda. This code will help you understand what is happening:
Function<String,String> s = (Function<String,String>) param -> {
System.out.println(param);
return param;
};
s.apply("Hello World");
This above code is unnecessarily casting the lambda to (Function<String, String>).
If you change it to (Function<String,Long>), you will get compile time error.
You asked what param was and whether it could be searched on. You also asked about the "form" of the lambda expression (why parenthesis are present or not). My answer below addresses those questions.
Searching for the text param will not usually work as the text param is arbitrary... you could replace it with p or even arbitraryName and as long as the name on the right of the -> in the lambda expression changes to the same value the code should still work.
You can think of param as the name given to a "passed in" parameter. In the method declaration below there are two parameters (param and anotherParam).
public void myPrint(String param, String anotherParam) {
System.out.println(param+", "+anotherParam);
}
A lambda expression is like a method declaration (like the above) but unneeded text can be removed in the syntax of the lambda expression. If the above COULD be made into a Lambda expression it would look like the following:
(String param, String anotherParam) -> { System.out.println(param+", "+anotherParam); }
Notice how similar the lambda expression is to the method declaration. Notice also that the text "myPrint" does not appear in the above. A lambda expression can be thought of as a "nameless" method declaration. In Java, a lambda expression is providing the code to implement a SingleAbstractMethod (SAM) in an an interface that only has a single abstract method defined. Assuming you had an interface with "MyPrint" defined as the name of the SAM then "MyPrint" is not needed (it is the only abstract method in the interface). Lambda Expressions work because a SAM Interface is a "Functional Interface" and lambda expressions implement the SAM in a functional interface. In a lambda expression the method name that you are implementing is ALWAYS not needed. This is one of the things that makes lambda expressions hard to understand as you normally understand a method by its name (to some degree) and you would like to search on the method name the lambda expression is implementing but that name does not appear in the lambda code.
The code above could also be written as...
(param, anotherParam) -> { System.out.println(param+", "+anotherParam); }
if the Java Type system can figure out the parameter types (in this case String) for itself. Again, the names param and anotherParam are arbitrary but their types are not. They are defined by the SAM in the functional interface you are implementing with the lambda. Another reason lambdas are hard to understand is the type of the parameter(s) is often interesting... but it is often left off from the lambda expression as it is not always needed by Java.
If there was only one parameter needed by the SAM the lambda expression could be written like the following
(String param) -> { System.out.println(param); }
or if "String" could be determined by Java
(param) -> { System.out.println(param); }
or even the () are not needed in this last version
param -> { System.out.println(param); }
There are other simplifications as well. In some cases the {} on the right side of the -> can be removed if it is only a single statement or expression.
If there are no parameters in the SAM being implemented then the code () -> is used where () signifies no parameters.
The last thing that I'll mention that is hard to understand about a lambda expression is the large number of syntax simplifications that can be made (see all the above). This appears to be the majority of your confusion.
Bottom Line: a lambda expression can be thought of as a nameless method declaration where you are overriding a SAM in a functional interface. The left hand side of the -> are the parameter declarations... the parameter types and even the () are not always needed. The right hand side of the -> is the body of the method and in some cases the {} are not needed.
Keys to understanding a lambda expression is understanding the syntax (all the above forms) and determining and understanding the functional interface and SAM that is being implemented. Unfortunately neither the functional interface or the name of the SAM show up in the lambda expression syntax itself... it is simplified away as not being needed!
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.
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.
This question already has answers here:
Lambda expression vs method reference implementation details
(3 answers)
Closed 5 years ago.
I just read in a book that when a lambda expression is assigned to a functional interface, then that sets the "target type" for the lambda and an instance of that type (that is, the functional interface's type) is created with the lambda expression used as implementation for the abstract method in the functional interface.
My question: If so, then does that mean lambdas aren't really standalone methods and as such a new type of element brought into the language, but are simply a more compact way for expressing an anonymous class and as such merely are added facility (just like generics) on the compiler's side?
Moreover, how do method references comply with that, in particular, static methods which are not associated with any objects? For example, when a method reference to an instance method is assigned to a functional interface then the encapsulating object for that method is used, but what happens in the case of a static method - those are not associated with any object.. ?
If so, then does that mean lambdas aren't really standalone methods and as such a new type of element brought into the language,
Correct, lambdas are compiled into normal methods with a synthetic name
but are simply a more compact way for expressing an anonymous class and as such merely are added facility (just like generics) on the compiler's side?
No, it's not only on the compiler side. There are is also code in the JVM involved, so that the compiler doesn't have to write class files for the lambdas.
Moreover, how do method references comply with that, in particular, static methods which are not associated with any objects?
Method references are not different from lambdas: at runtime there has to be an object implementing the functional interface. Upon calling the "SAM" of the object this method will call the referenced method.
For example, when a method reference to an instance method is assigned to a functional interface then the encapsulating object for that method is used,
No, it can't be used. Let's take the following example using a System.out::println method reference:
Arrays.asList("A", "B").forEach(System.out::println);
List<E>.forEach() expects a Consumer<? super E> which defines the method void accept(E e). The compiler need to generate byte code and other information in the class file so that at runtime the JVM can generate a class implementing Consumer<E> with a method void accept(E e). This generated method then calls System.out.println(Object o).
The runtime generated class would look something like
class $$lambda$xy implements Consumer<Object> {
private PrintStream out;
$$lambda$xy(PrintStream out) {
this.out = out;
}
void accept(Object o) {
out.println(o);
}
}
Your question from the comment: "Why not directly assign to instance and its method?"
Let's expand the example a little bit:
static void helloWorld(Consumer<String> consumer) {
consumer.apply("Hello World!");
}
public static void main(String[] args) {
helloWorld(System.out::println);
}
To compile this, the compiler has to generate bytecode that creates an object implementing Consumer<String> (so it can pass the object into helloWorld()). That object somehow has to store the information that upon calling it's accept(x) method it has to call println(x) on the System.out PrintStream.
Other languages may have other names or concepts for this kind of objects - in Java the established concept is "an anonymous class implementing the interface and an object of that anonymous class".
How does the object store this information? Well, you could invent some super cool new way to store this information. The Java Language designers decided that an anonymous class would be good enough - for the time being. But they had the foresight that if someone came along with a new idea to implement it in a more efficient way, this should be easy to integrate into the Java ecosystem (Java compiler and JVM).
So they also decided to create that anonymous class not at compile time but to let the compiler just write the necessary information into the class file. Now the JVM can at runtime decide on what the optimal way to store the information (calling the correct method on the correct object) is.
For example, when a method reference to an instance method is assigned
to a functional interface then the encapsulating object for that
method is used, but what happens in the case of a static method -
those are not associated with any object..
That depends on context. Let say we have a static Utils#trim(String) method that will obviously trim given string.
And now, lest have a List<String> list and lets have some strings in it. We can do something like this:
list.stream().map(Utils::trim).collect(Collectors.toList());
As you can see, in given context, we are using lambda static method reference in order to use every string in list as input argument of Utils::trim method.