Java Lambda Expressions
A lambda expression (Java 8) is a short way to write an anonymous function. It is mostly used to pass a small piece of behavior to a method, for example how to sort or how to filter a list.
Syntax
(parameters) -> expression
(parameters) -> { statements; }
From the old way to a lambda
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> names = new ArrayList<>(List.of("Meera", "Al", "Riya", "Karan"));
// old way: an anonymous class
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
});
System.out.println(names);
// lambda
names.sort((a, b) -> b.length() - a.length());
System.out.println(names);
// method reference
names.sort(String::compareTo);
System.out.println(names);
}
}
[Al, Riya, Meera, Karan]
[Meera, Karan, Riya, Al]
[Al, Karan, Meera, Riya]
Functional interfaces
A lambda works with an interface which has one abstract method. The package java.util.function has the common ones:
| Interface | Method | Meaning | Example |
|---|---|---|---|
| Predicate<T> | boolean test(T) | A yes or no question | n -> n > 5 |
| Function<T,R> | R apply(T) | Change a value into another | s -> s.length() |
| Consumer<T> | void accept(T) | Do something with a value | s -> System.out.println(s) |
| Supplier<T> | T get() | Make a value | () -> 42 |
| UnaryOperator<T> | T apply(T) | Same type in and out | s -> s.trim() |
| BinaryOperator<T> | T apply(T, T) | Two in, one out | (a, b) -> a + b |
import java.util.function.*;
public class Fn {
public static void main(String[] args) {
Predicate<Integer> isEven = n -> n % 2 == 0;
Function<String, Integer> length = s -> s.length();
Consumer<String> shout = s -> System.out.println(s.toUpperCase() + "!");
Supplier<Double> pi = () -> Math.PI;
BinaryOperator<Integer> add = (a, b) -> a + b;
System.out.println(isEven.test(10));
System.out.println(length.apply("lambda"));
shout.accept("hello");
System.out.println(pi.get());
System.out.println(add.apply(4, 5));
// combine
Predicate<Integer> bigAndEven = isEven.and(n -> n > 100);
System.out.println(bigAndEven.test(102));
Function<Integer, Integer> twice = n -> n * 2;
System.out.println(twice.andThen(n -> n + 1).apply(5));
}
}
true
6
HELLO!
3.141592653589793
9
true
11
Lambdas with collections
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class Coll {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
numbers.removeIf(n -> n % 2 == 1);
System.out.println(numbers);
numbers.replaceAll(n -> n * n);
System.out.println(numbers);
numbers.forEach(n -> System.out.print(n + " "));
System.out.println();
Map<String, Integer> map = new TreeMap<>(Map.of("a", 1, "b", 2));
map.forEach((k, v) -> System.out.println(k + "=" + v));
}
}
[2, 4, 6]
[4, 16, 36]
4 16 36
a=1
b=2
Method references
When the lambda only calls one method, you can write it shorter with ::.
| Kind | Example | Same as |
|---|---|---|
| Static method | Integer::parseInt | s -> Integer.parseInt(s) |
| Instance method of a type | String::length | s -> s.length() |
| Method of an object | System.out::println | x -> System.out.println(x) |
| Constructor | ArrayList::new | () -> new ArrayList<>() |
Variables in lambdas
A lambda can use the local variables of the method, but they must be final or effectively final (not changed after they are set):
public class Eff {
public static void main(String[] args) {
int count = 0;
Runnable r = () -> count++; // error: count is changed
r.run();
}
}
Eff.java:4: error: local variables referenced from a lambda expression must be final or effectively final
Runnable r = () -> count++; // error: count is changed
^
1 error
error: compilation failed
| Exercises & Assignments |
|---|
| No Content Found. |
| Interview Questions & Answers |
|---|
| No Content Found. |