Intermediate · Lambdas, streams and files · topic 36 of 60 · 25 min
Lambdas and functional interfaces
Explanation
Why lambdas?
Before Java 8, passing a small piece of behaviour (how to compare, what to do when a button is clicked) needed an anonymous inner class of five or six lines. Lambdas say the same thing in one line, which made the Stream API and modern Java style possible.
// Before Java 8: an anonymous class
Comparator<String> byLength = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return Integer.compare(a.length(), b.length());
}
};
// Java 8+: a lambda
Comparator<String> byLength2 = (a, b) -> Integer.compare(a.length(), b.length());Lambda syntax
Runnable hello = () -> System.out.println("Namaste"); // no parameters
Function<Integer, Integer> square = x -> x * x; // one parameter: brackets optional
BinaryOperator<Integer> add = (a, b) -> a + b; // two parameters
Function<Double, Double> withGst = amount -> { // a block body needs return
double tax = amount * 0.18;
return amount + tax;
};The standard functional interfaces (java.util.function)
| Interface | Method | Takes → returns | Example |
|---|---|---|---|
| Predicate<T> | test | T → boolean | o -> o.amount() > 500 |
| Function<T, R> | apply | T → R | s -> s.length() |
| Consumer<T> | accept | T → nothing | msg -> System.out.println(msg) |
| Supplier<T> | get | nothing → T | () -> LocalDate.now() |
| UnaryOperator<T> | apply | T → T | s -> s.trim() |
| BinaryOperator<T> | apply | (T, T) → T | (a, b) -> a + b |
| BiFunction<T, U, R> | apply | (T, U) → R | (price, qty) -> price * qty |
Predicate<String> isValidPin = pin -> pin.matches("[1-9][0-9]{5}");
System.out.println(isValidPin.test("560001")); // true
Predicate<String> notBlank = s -> !s.isBlank();
Predicate<String> both = isValidPin.and(notBlank); // predicates combine with and, or, negate
Function<Integer, Integer> plusGst = p -> p + p * 18 / 100;
Function<Integer, String> label = p -> "Rs " + p;
System.out.println(plusGst.andThen(label).apply(100)); // Rs 118Capturing variables: effectively final
A lambda can use local variables from the surrounding method, but only if they are final or effectively final (never reassigned after initialisation). This avoids confusing bugs when a lambda runs later or on another thread.
double rate = 18;
Function<Double, Double> tax = amt -> amt * rate / 100; // OK: rate is never changed
// rate = 5; // would make the lambda above a compile error
int count = 0;
// list.forEach(x -> count++); // compile error: count must be effectively final
// Use a stream count(), or an AtomicInteger, instead.Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Lambdas and functional interfaces · 1/6
In this lesson you will write lambdas, short functions you can pass around.
Prefer a video by a teacher? Find free videos on “java lambda expressions functional interfaces predicate function consumer supplier” on YouTube ↗
In real life: Configurable discount rules
A retail billing system applies different discount rules on different days: festival 10% off, member ₹50 off above ₹500, and so on. Each rule is a UnaryOperator<Double>, and today's rules are chained with andThen, so marketing can change rules without new if/else code.
UnaryOperator<Double> festival = p -> p * 0.9;
UnaryOperator<Double> member = p -> p > 500 ? p - 50 : p;
Function<Double, Double> today = festival.andThen(member);
System.out.println(today.apply(1000.0)); // 1000 → 900 → 850.0Practice (0/3 done)
Which functional interface fits o -> o.amount() > 500?
Why does this NOT compile? int total = 0; List.of(1, 2, 3).forEach(n -> total += n);
Write three Predicate<String> rules for a username: at least 4 characters, only letters and digits, and not starting with a digit. Combine them with and(...) into one isValid predicate and test it on five usernames, printing each result.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Method referencesLambdas, streams and files · same module
- Streams: filter, map and collectLambdas, streams and files · same module
- Collectors: grouping and summarisingLambdas, streams and files · same module
- Lambdas and higher-order functionsKotlin and Android App Development · Null safety, functions and lambdas
- Delegates, lambdas, Func, Action and PredicateC# and .NET · Exceptions, delegates, events and async
- Lambdas: small functions written in placeC++ Programming (modern C++ and DSA) · Modern C++: lambdas, C++17 and C++20 essentials
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What is a functional interface?
Answer: An interface with exactly one abstract method
Lambdas implement functional interfaces.
Supplier<T> takes…
Answer: Nothing and returns a T
Supplier.get() produces a value.
Function<Integer, Integer> f = x -> x + 1; f.andThen(x -> x * 2).apply(3) is…
Answer: 8
(3 + 1) * 2 = 8.
When did lambdas arrive in Java?
Answer: Java 8
Java 8 (2014) added lambdas and streams.
What is a functional interface?Related
Answer: An interface with exactly one abstract method
It can be implemented by a lambda.
From Interfaces
Which call uses trailing lambda syntax?Related
Answer: list.filter { it > 0 }
The lambda moves outside the parentheses.
Predicate<int> p = n => n > 10; What is p(7)?Related
What makes a lambda "generic"?Related
Answer: It uses auto in its parameter list
auto parameters turn the call operator into a template.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 4 more topics in “Lambdas, streams and files” before its exam: Method references, Streams: filter, map and collect, Collectors: grouping and summarising, Reading and writing files.
- Module 8 exam: Lambdas, streams and files · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Multithreading and concurrency. 60 topics left in the course before the final exam.