Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 337
hi.nitish Avatar asked Mar 30 '18 17:03

hi.nitish


People also ask

Can we use VAR declarations inside a lambda expression?

A lambda expression can't define any new scope as an anonymous inner class does, so we can't declare a local variable with the same which is already declared in the enclosing scope of a lambda expression. Inside lambda expression, we can't assign any value to some local variable declared outside the lambda expression.

Why VAR is not used in Java?

In Java, var can be used only where type inference is desired; it cannot be used where a type is declared explicitly. If val were added, it too could be used only where type inference is used. The use of var or val in Java could not be used to control immutability if the type were declared explicitly.

Can we use this keyword in lambda expression in Java?

The "this" and "super" references within a lambda expression are the same as in the enclosing context. Since the lambda expression doesn't define a new scope, "this" keyword within a lambda expression signifies "this" parameter of a method where the lambda expression is residing.

Can we use var keyword in Java?

The var keyword was introduced in Java 10. Type inference is used in var keyword in which it detects automatically the datatype of a variable based on the surrounding context. The below examples explain where var is used and also where you can't use it.


2 Answers

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.

like image 68
Brian Goetz Avatar answered Nov 08 '22 16:11

Brian Goetz


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.

like image 34
Jorn Vernee Avatar answered Nov 08 '22 14:11

Jorn Vernee