Why can't I assign lambda to Object? - java

I was trying to assign a lambda to Object type:
Object f = ()->{};
And it gives me error saying:
The target type of this expression must be a functional interface
Why is this happening, and how to do this?

It's not possible. As per the error message Object is not a functional interface, that is an interface with a single public method so you need to use a reference type that is, e.g.
Runnable r = () -> {};

This happens because there is no "lambda type" in the Java language.
When the compiler sees a lambda expression, it will try to convert it to an instance of the functional interface type you are trying to target. It's just syntax sugar.
The compiler can only convert lambda expressions to types that have a single abstract method declared. This is what it calls as "functional interface". And Object clearly does not fit this.
If you do this:
Runnable f = (/*args*/) -> {/*body*/};
Then Java will be able to convert the lambda expression to an instance of an anonymous class that extends Runnable. Essentially, it is the same thing as writing:
Runnable f = new Runnable() {
public void run(/*args*/) {
/*body*/
}
};
I've added the comments /*args*/ and /*body*/ just to make it more clear, but they aren't needed.
Java can infer that the lamba expression must be of Runnable type because of the type signature of f. But, there is no "lambda type" in Java world.
If you are trying to create a generic function that does nothing in Java, you can't. Java is 100% statically typed and object oriented.
There are some differences between anonymous inner classes and lambdas expressions, but you can look to them as they were just syntax sugar for instantiating objects of a type with a single abstract method.

Related

How does the compiler know which class the lambda is implementing?

I see Thread() takes both Runnable and String for single argument constructors. How does the compiler know that a lambda is implementing a Runnable class and not a String class?
(new Thread( () -> {
System.out.println("Deleting stats...");
})).start();
Maybe it goes by the number of methods in the class/interface? But what if a class had multiple constructors that took single argument class that only had one method, for example:
Thread( Runnable r );
Thread( Comparable c );
Thread( ActionListener al );
What happens then when you try to implement a lambda then? How would the compiler know which class the lambda is implementing?
The Java compiler must choose a functional interface type for the type of a lambda expression. This is governed by the JLS, Section 15.27.3, which states:
A lambda expression is compatible in an assignment context, invocation context, or casting context with a target type T if T is a functional interface type (ยง9.8) and the expression is congruent with the function type of the ground target type derived from T.
The type String is not a functional interface type, but Runnable is. The lambda takes no arguments and returns no data, so it is congruent with Runnable.
More generally, the types of parameters in a lambda expression must match the types of parameters of the single abstract method of a functional interface type, and the return types must match also.
In your example, each of the 3 functional interface types is distinct, so at most one will match. If there are multiple functional interface types that could possible match, that would be ambiguous, only resolvable by casting the lambda expression to the intended functional interface type.
Lambda expressions are converted to an instance of a class implementing a functional interface. A "functional interface" means an interface with only 1 (non-default) method in it.
String isn't an interface - it's a class. So the compiler looks at the lambda expression and knows that if the code is to make sense then it should convert the lambda to instance of an implementation of Runnable, as it's the only possible thing that could work!

Does lambda expression automatically create new object for its entry parameters?

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.

Why can't the var keyword in Java be assigned a lambda expression?

It is allowed to assign var in Java 10 with a string like:
var foo = "boo";
While it is not allowed to assign it with a lambda expression such as:
var predicateVar = apple -> apple.getColor().equals("red");
Why can't it infer a lambda or method reference type when it can infer the rest like String, ArrayList, user class, etc.?
This has nothing to do with var. It has to do with whether a lambda has a standalone type. The way var works is that it computes the standalone type of the initializer on the RHS, and infers that.
Since their introduction in Java 8, lambda expressions and method references have no standalone type -- they require a target type, which must be a functional interface.
If you try:
Object o = (String s) -> s.length();
you also get a type error, because the compiler has no idea what functional interface you intend to convert the lambda to.
Asking for inference with var just makes it harder, but since the easier question can't be answered, the harder one cannot either.
Note that you could provide a target type by other means (such as a cast) and then it would work:
var x = (Predicate<String>) s -> s.isEmpty();
because now the RHS has a standalone type. But you are better off providing the target type by giving x a manifest type.
From the Local-Variable Type Inference JEP:
The inference process, substantially, just gives the variable the type of its initializer expression. Some subtleties:
The initializer has no target type (because we haven't inferred it yet). Poly expressions that require such a type, like lambdas, method references, and array initializers, will trigger an error.
Because a lambda expression by itself does not have a type, it can not be inferred for var.
... Similarly, a default rule could be set.
Sure, you can come up with a way to work around this limitation. Why the developers made the decision not to do that is really up to speculation, unless someone who was part of the decision making can answer here. (Update: answered here.) If you're interested anyway, you could ask about it on one of the openjdk mailing lists: http://mail.openjdk.java.net/mailman/listinfo
If I were to guess, they probably didn't want to tie lambda inference in the context of var to a specific set of functional interface types, which would exclude any third party functional interface types. A better solution would be to infer a generic function type (i.e. (Apple) -> boolean) that can than be converted to a compatible functional interface type. But the JVM does not have such function types, and the decision to not implement them was already made during the project that created lambda expressions. Again if you're interested in concrete reasons, ask the devs.
To everyone who is saying this is impossible, undesired, or unwanted, I just want to point out that Scala can infer the lambda's type by specifying only the argument type:
val predicateVar = (apple: Apple) => apple.getColor().equals("red")
And in Haskell, because getColor would be a standalone function not attached to an object, and because it does full Hindley-Milner inference, you don't need to specify even the argument type:
predicateVar = \apple -> getColor apple == "red"
This is extraordinarily handy, because it's not the simple types that are annoying for programmers to explicitly specify, it's the more complex ones.
In other words, it's not a feature in Java 10. It's a limitation of their implementation and previous design choices.
As several people have already mentioned, what type should var infer and why should it?
The statement:
var predicateVar = apple -> apple.getColor().equals("red");
is ambiguous and there is no valid reason why the compiler should pick Function<Apple, Boolean> over Predicate<Apple> or vice versa assuming the apple identifier in the lambda represents an Apple isntance.
Another reason is that a lambda in its own doesn't have a speakable type hence there is no way for the compiler to infer it.
Also, "if this was possible" imagine the overhead as the compiler would have to go through all the functional interfaces and determine which functional interface is the most appropriate each time you assign a lambda to a var variable.
To answer this we have to go into details and understand what a lambda is and how it works.
First we should understand what a lambda is:
A lambda expression always implements a functional interface, so that when you have to supply a functional interface like Runnable, instead of having to create a whole new class that implements the interface, you can just use the lambda syntax to create a method that the functional interface requires. Keep in mind though that the lambda still has the type of the functional interface that it is implementing.
With that in mind, lets take this a step further:
This works great as in the case of Runnable, I can just create a new thread like this new Thread(()->{//put code to run here}); instead of creating a whole new object to implement the functional interface. This works since the compiler knows that Thread() takes an object of type Runnable, so it knows what type the lambda expression has to be.
However, in a case of assigning a lambda to a local variable, the compiler has no clue what functional interface this lambda is implementing so it can't infer what type var should be. Since maybe it's implementing a functional interface the user created or maybe it's the runnable interface, there is just no way to know.
This is why lambdas do not work with the var keyword.
Because that is a non-feature:
This treatment would be restricted to local variables with initializers, indexes in the enhanced for-loop, and locals declared in a traditional for-loop; it would not be available for method formals, constructor formals, method return types, fields, catch formals, or any other kind of variable declaration.
http://openjdk.java.net/jeps/286
In a nutshell, the types of a var and lambda expression both need inference, but in opposite way. The type of a var is inferred by the initializer:
var a = new Apple();
The type of a lambda expression is set by the context. The type expected by the context is called the target type, and is usually inferred by the declaration e.g.
// Variable assignment
Function<Integer, Integer> l = (n) -> 2 * n;
// Method argument
List<Integer> map(List<Integer> list, Function<Integer, Integer> fn){
//...
}
map(List.of(1, 2, 3), (n) -> 2 * n);
// Method return
Function<Integer, Integer> foo(boolean flag){
//...
return (n) -> 2 * n;
}
So when a var and lambda expression are used together, the type of the former needs to be inferred by the latter while the type of the latter needs to be inferred by the former.
var a = (n) -> 2 * n;
The root of this dilemma is Java cannot decide the type of a lambda expression uniquely, which is further caused by Java's nominal instead of structural type system. That is, two types with identical structures but different names are not deemed as the same, e.g.
class A{
public int count;
int value(){
return count;
}
}
class B{
public int count;
int value(){
return count;
}
}
Function<Integer, Boolean>
Predicate<Integer>

Lambda expressions mechanisms in Java [duplicate]

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.

Java 8: How do functional Interfaces list hidden files?

In a Java 8 introduction mini-book, I saw these implementation for listing hidden files:
File[] hiddenFiles = mainDirectory.listFiles(f -> f.isHidden());
and
File[] hiddenFiles = mainDirectory.listFiles(File::isHidden);
I checked the docs and it looks like listFiles accepts both FileFilter or FilenameFilter implementation. Both are functional interfaces.
From the Javadocs:
Functional Interface:
This is a functional interface and can therefore be used as the
assignment target for a lambda expression or method reference.
My questions: What happens in both cases (the expression versus the method reference), and how does Java adjust what I send to listFiles?
What I mean: In the source code, I can't find any indication whether listFiles checks for a method reference or lambda expression. I understand that Java internally checks and adjust both (lambda or method ref) to become FileFilter or FilenameFilter instances, as shown by the lambda expression and how it can be the accept method, but what happens internally with File::isHiiden? Is it wrapped with some kind of class, or is it transformed into expression such as the first case?
I know I'm kind of lost here, maybe confused, but I hope you could understand pretty much what my questions is.
Edit:
I found few useful statements from the docs (I changed a bit):
Evaluation of a method reference expression is distinct from
invocation of the method itself.
At run time, evaluation of a method reference expression is similar to
evaluation of a class instance creation expression
The class implements the targeted functional interface type
A new instance of a class with properties(depends on the expression) is
allocated and initialized, or an existing instance of a class with the
properties below is referenced
The value of a method reference expression is a reference to an
instance of a class with the following properties(depends on the
expression)
So for example in my case, where I use File::isHidden, an object will be created by a class that implements FileFilter, FileFilter have accept method that accepts File type objects and calls isHidden on those File type objects.
If you look at JLS 15.27.3, "Type of a Lambda Expression", you will know that the lambda expression is simply an expression that can be assigned to a variable of that functional interface (here your lambda is an expression of a type assignable to FileFilter. This is because your expression (File -> boolean) is congruent with the FileFilter functional interface, and not the FilenameFilter interface.
To answer the second part of your question, there is in fact wrapping in a class, as described in JLS 15.27.4.

Categories

Resources