Lambdas in Java
Lambdas are undeclared functions, meaning they do not need to be explicitly declared to be used. There is no need to specify a name, parameters, access modifiers, or return type. Essentially, a lambda is a simpler way to implement an interface with a single method.
In Java, the basic syntax of lambda functions is:
(args) -> (body)
Examples
(int x, int y) -> { return x * y; }
Aluno display = (Pessoa p) -> { System.out.println(p.idade); }
() -> System.out.println(new Date());
() -> { return 25.789; }
x -> x < 100;
Curly braces are required only when the function body contains more than one statement. For example:
(int x, int y) -> { return x * y; }
Can be written as:
(int x, int y) -> return x * y;
Both forms produce the same result.
Lambda functions can have parameters or none at all. The parameter types can also be omitted, as Java will infer their types.
Examples
- Function with parameters (with declared types):
(int x, int y) -> { return x * y; }
- Function with parameters (without declared types):
(x, y) -> { return x * y; }
- Function without parameters:
() -> System.out.println(new Date());
If no return
keyword is used, the function's return type is inferred as void
:
(a) -> this.x = a;
It is important to note that lambdas are different from anonymous classes. This can be observed in the generated .class
files. Unlike anonymous classes, lambdas do not generate multiple .class
files for each usage.
Applications of Lambdas in Java
Threads
Lambdas simplify code by reducing verbosity when working with threads.
// Implementing the Runnable interface and creating a thread with it
Runnable e = new Runnable() {
public void run() {
System.out.println(new Date());
}
};
new Thread(e).start();
// The same implementation using a lambda expression
Runnable e = () -> System.out.println(new Date());
new Thread(e).start();
// Even more concise
new Thread(
() -> System.out.println(new Date())
).start();
Collections
Lambdas simplify functions such as sorting and filtering in collections.
// Print all elements in a list
List<String> list = Arrays.asList("João", "Ana", "Maria", "Cesar");
for (String s : list) {
System.out.println(s);
}
// Using lambdas
list.forEach(s -> System.out.println(s));
// Lambda with multiple statements
list.forEach(s -> {
if (StringUtils.equals("Cesar", s)) {
System.out.println(s);
}
});
// Conventional sorting
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
list.forEach(p -> System.out.println(p));
// Sorting using lambdas
Collections.sort(list, (String s1, String s2) -> s1.compareTo(s2));
list.forEach(p -> System.out.println(p));
Listeners
Lambdas simplify code in listeners, which implement the Observer design pattern.
// Listening to an action on a button in a Swing window
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Some actions...");
}
});
// Using lambdas
button.addActionListener((e) -> {
System.out.println("Some actions...");
});
Generic Functions
Lambdas can be used in generic functions to solve problems by passing lambda expressions as parameters.
public class Main {
/*
* A method that tests a condition
*/
public static void testExpression(List<String> list, Predicate<String> predicate) {
list.forEach(n -> {
if (predicate.test(n)) {
System.out.println(n);
}
});
}
/*
* Calling the method with a lambda
*/
public static void main(String[] args) {
List<String> list = Arrays.asList("João", "Ana", "Maria", "Cesar");
// Prints "Cesar" if it exists
testExpression(list, (n) -> StringUtils.equals("Cesar", n));
// Prints the entire list
testExpression(list, (n) -> true);
// Prints nothing
testExpression(list, (n) -> false);
}
}
Top comments (0)