Java is a first-class object-oriented language. With the exception of primitive data types, everything in Java is an object. Even an array is an object. Every class creates instances that are objects. There is no way to define just a standalone function/method in Java on its own. There is no way to pass a method as an argument or return a method body for an instance.
Anonymous inner classes were the usual resort to try to save written code.
In short, it is not easy to pass plain methods as arguments in Java. Because of this limitation, Java 8 adds a language-level feature called Lambda Expressions.
A functional language offers a closure, which has quite a few advantages over the traditional way of writing applications. A closure is a function or reference to a function, along with a referencing environment—a table that holds a reference to each of the non-local variables of that function. The closest thing Java can provide to a closure is lambda expressions. While there is a significant difference between a closure and a lambda expression, at least Lambda expressions offer a good alternative to closures. The difference is that Lambdas are not functions, but objects.
What are they?
A lambda expression is like an anonymous function. In short, it is a method without a declaration—that is, access modifier, return value declaration, and name.
It is a kind of shorthand that allows you to write a method in the exact place where it will be used. It is especially useful in places where a method is used only once and the method definition is short. This saves the effort of declaring and writing a separate method for the containing class.
Lambda expressions in Java are written using the syntax:
(arguments) → (body)
Example
int a, int b) -> { return a + b; }
() -> System.out.println("Hello World");
(String s) -> { System.out.println(s); }
() -> 42
() -> { return 3.1415 }
Structure
A lambda expression can have zero, one, or more parameters.
The type of the parameters can be explicitly declared or inferred from the context; for example (int a) is the same as (a).
Parameters are enclosed in parentheses and separated by commas, for example (a,b) or (int a, int b) or (String a, int b, float c).
Empty parentheses are used to represent an empty set of parameters, for example () → 42
When there is a single parameter, if its type is inferred, parentheses are not mandatory. For example a → return a*a
The body of lambda expressions can contain zero, one, or more statements.
If the body of a lambda expression has a single statement, curly braces are not mandatory and the return type of the anonymous function is the same as that of the body expression.
When there is more than one statement in the body, these must be enclosed in curly braces (a code block) and the return type of the anonymous function is the same as the return type inside the code block, or they will not be valid if it returns nothing.
Functional interfaces
In Java, an interface is a classifier without defined methods or declared attributes.
In the same way, a functional interface is an interface with a single abstract method declared in it.
java.lang.Runnable is an example of a functional interface. There is only one void run() method declared in the runnable interface. Similarly, the ActionListener interface is also a functional interface. We use anonymous inner classes to create instances of functional interface objects. With lambda expressions, this can be simplified. Every lambda expression can be implicitly assigned to an interface called a functional interface. For example, we can create the reference to the runnable interface as a lambda expression, as we can see:
Runnable r = () -> System.out.println("hola món");
This type of conversion is performed by the compiler when we do not specify the functional interface. For example:
new Thread( () -> System.out.println("hola món") ).start();
Thus, in the code above, the compiler automatically infers that the lambda expression can target the runnable interface from the class constructor:
Thread public Thread(Runnable r){}
@FunctionalInterface
public interface TrabajadorInterfaz{
public void hacerAlgo();
}
Functional interfaces are interfaces with a single deferred method. Once the functional interface is defined, we can simply use it in our API and take advantage of lambda expressions.