Mastering java 8 (Lambda expression & functional interface) - day 2
Source: Dev.to
What Is a Lambda Expression? – “The Anonymous Function”
A lambda expression is a concise way to represent an anonymous (nameless) function.
It lets you treat “code as data” and dramatically reduces boiler‑plate.
Anatomy
(parameters) -> { body }
| Part | Description |
|---|---|
| (parameters) | Input arguments. • One parameter → parentheses optional, e.g. s -> …• No parameters → empty parentheses, e.g. () -> … |
| -> (arrow token) | Separates the parameter list from the implementation. It reads as “goes to” or “executes”. |
| { body } | The code to run. • Single expression → omit {} and the return keyword (the result is returned implicitly).• Multiple statements → keep {} and use return when a value is expected. |
Example: Old Way vs. Lambda Way
Before Java 8 – Anonymous Inner Class
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button clicked!");
}
});

With a Lambda Expression – Clean & Concise
button.addActionListener(e -> System.out.println("Button clicked!"));

Notice how the lambda cuts out all the ceremonial code and focuses purely on the action.
The “Home” for Lambdas – Functional Interfaces
A functional interface is any interface that declares exactly one abstract method.
It may contain any number of default or static methods, but only one method needs an implementation.
Common built‑in functional interfaces:
RunnableCallableComparator
Java 8 also introduced the java.util.function package, which ships with a rich set of ready‑to‑use functional interfaces.
The Big Four – Essential java.util.function Interfaces
These four are the workhorses you’ll reach for most often.
1️⃣ Predicate – The Tester
- Purpose: Accepts a value of type
Tand returns aboolean. Ideal for filtering or condition checks. - Abstract method:
boolean test(T t)
Example – Check if a number is even
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // true

2️⃣ Function – The Transformer
- Purpose: Takes a value of type
Tand returns a result of typeR. Perfect for mapping one type to another. - Abstract method:
R apply(T t)
Example – Convert a String to its length (Integer)
Function<String, Integer> length = s -> s.length();
System.out.println(length.apply("hello")); // 5

3️⃣ BiFunction – The Combiner
- Purpose: Accepts two arguments (
TandU) and produces a result of typeR. Useful for operations that combine two values. - Abstract method:
R apply(T t, U u)
Example – Add two integers
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
System.out.println(add.apply(3, 7)); // 10

4️⃣ Consumer – The Doer
- Purpose: Takes a value of type
Tand returns nothing (void). It “consumes” the input to perform an action. - Abstract method:
void accept(T t)
Example – Print a message to the console
Consumer<String> printer = msg -> System.out.println(msg);
printer.accept("Hello, Lambda!");

TL;DR
- Lambda expressions let you write anonymous functions with minimal syntax.
- They always target a functional interface—an interface with a single abstract method.
- The
java.util.functionpackage supplies the most useful interfaces, especially the Predicate, Function, BiFunction, and Consumer.
Bonus: The Supplier (The Provider)
While not one of the “Big Four,” the Supplier is equally important.
-
Purpose: Takes no inputs and returns a single result of type
T. It supplies a value. -
Abstract method:
T get();
Example – Generating a random number
Supplier<Integer> randomNum = () -> new Random().nextInt(100);
System.out.println(randomNum.get());

Why Bother with Lambdas?
The benefits are clear:
- Concise code – Less boilerplate, more focus on business logic.
- Readability – Often reads more like plain English, especially when used with Streams.
- Functional programming – Enables a more functional style of programming in Java.
- Stream API integration – Lambdas are the backbone of the powerful Java Stream API, allowing for elegant data processing.