Definition
- Function
maps an input to an output. - .andThen(after) composes two functions so the first runs and its result feeds the second.
- f.andThen(g) runs f first, then g. f.compose(g) runs g first, then f.
- The composed function is itself a
Function, usable inmap()and other APIs. - Types must align: the output of the first function must match the input of the second.
Priya at the National Bank of India first pulls the name off an employee file, then runs that name through a capitaliser. Two steps on an assembly line: get the name, then make it uppercase.
Understanding the Concepts
How do you compose two functions with andThen?
Define the first function, call andThen with the second, and the result is a single composed function.
package com.bank.hr;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class FunctionComposition {
public static void main(String[] args) {
List<Employee> employees = List.of(
new Employee("Rajesh", "Loans"),
new Employee("Priya", "IT"),
new Employee("Amit", "Finance")
);
Function<Employee, String> getName = Employee::getName;
Function<Employee, String> getUpperName =
getName.andThen(String::toUpperCase);
List<String> upperNames = employees.stream()
.map(getUpperName)
.collect(Collectors.toList());
System.out.println(upperNames);
}
}
[RAJESH, PRIYA, AMIT]
What is the difference between andThen and compose?
| Method | Execution order | Read as |
|---|---|---|
| f.andThen(g) | f first, then g | "f and then g" |
| f.compose(g) | g first, then f | "f after g" |
Function<String, String> trim = String::trim;
Function<String, String> upper = String::toUpperCase;
// andThen: trim first, then uppercase
String result1 = trim.andThen(upper).apply(" hello ");
// "HELLO"
// compose: uppercase first, then trim
String result2 = trim.compose(upper).apply(" hello ");
// "HELLO" (same here, but order matters for other functions)
How do you chain more than two functions?
Function<Employee, String> pipeline =
((Function<Employee, String>) Employee::getName)
.andThen(String::trim)
.andThen(String::toUpperCase);
// Applied in order: getName → trim → toUpperCase
What are common mistakes?
Mistake: null intermediate value causing NullPointerException.
// WRONG: if getName returns null, toUpperCase throws NPE
Function<Employee, String> unsafe =
((Function<Employee, String>) Employee::getName)
.andThen(String::toUpperCase);
// CORRECT: guard with a null-safe step
Function<Employee, String> safe =
((Function<Employee, String>) Employee::getName)
.andThen(name -> name != null ? name.toUpperCase() : "UNKNOWN");
What should a senior engineer know?
- Composition builds a pipeline of small, individually testable transformations.
- andThen reads naturally left to right, matching the data flow direction.
- The composed function is a new Function instance; the originals are unchanged.
- For more complex pipelines, consider a dedicated method or class rather than long chains.
What are common interview follow-up questions?
- "Can you compose with a Predicate?" Not directly; Predicate has and/or/negate, not andThen. Convert to a Function
if needed. - "What about Function.identity()?" Returns a function that returns its input unchanged, useful as a default.
- "Can you compose BiFunction?" BiFunction has andThen (for the result) but not compose.
Visual Overview
Employee("Rajesh")
│
│ getName
▼
"Rajesh"
│
│ toUpperCase (andThen)
▼
"RAJESH"
Pipeline: Employee → getName → toUpperCase → String
Key Takeaway
Function.andThen chains two functions left to right: the first function runs, and its result feeds into the second. Define getName as a Function
The composed function is itself a Function, so pass it directly to map() in a stream. At the National Bank of India, the uppercase-name report used this composition instead of writing one large lambda.
Composition builds pipelines of small, testable transformations. Types must align: the output of the first function must match the input of the second. Guard against null intermediate values to prevent NPE.
Remember one sentence: f.andThen(g) runs f first then g, composing small functions into a readable pipeline.
---