Mapping
Transforming elements with map(), Entity → DTO conversion, method references and primitive mapping with mapToInt/Long/Double.
#Introduction
If filter() answers "Which elements do I want?", then map() answers "What do I want to convert them into?"
This is used everywhere in Spring Boot projects — converting entities to DTOs, formatting data, extracting fields, and much more. By the end of this chapter you'll be able to:
- Understand what
map()does - Use
mapToInt(),mapToLong()andmapToDouble() - Know when to use primitive streams
- Use method references with
map() - Convert one object type into another (Entity → DTO)
- Answer common interview questions on mapping
#What is map()?
map() transforms each element in a stream into another value.
<R> Stream<R> map(Function<T, R> mapper)It takes a Function<T, R>:
R apply(T t);#Basic Examples
Uppercase
List<String> names = Arrays.asList("John", "Alex", "David");
names.stream()
.map(String::toUpperCase)
.forEach(System.out::println);JOHN
ALEX
DAVIDSquare Every Number
List<Integer> numbers = Arrays.asList(2, 3, 4, 5);
numbers.stream()
.map(n -> n * n)
.forEach(System.out::println);4
9
16
25Cube Every Number
numbers.stream()
.map(n -> n * n * n)
.forEach(System.out::println);8
27
64
125Convert to String Length
List<String> names = Arrays.asList("John", "Alexander", "Bob");
names.stream()
.map(String::length)
.forEach(System.out::println);4
9
3Notice String → Integer: the input and output types don't have to be the same.
#Working with Objects
Extract a Field
class Employee {
String name;
double salary;
Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
}
List<Employee> employees = Arrays.asList(
new Employee("John", 50000),
new Employee("David", 70000)
);
employees.stream()
.map(e -> e.name)
.forEach(System.out::println);John
DavidThe stream changes from Stream<Employee> to Stream<String>.
Increase Salary
employees.stream()
.map(e -> e.salary * 1.10)
.forEach(System.out::println);55000.00000000001
77000.00000000001The original employee objects are unchanged, because you're creating a new stream of salary values.
Entity → DTO (Very Common in Spring Boot)
// Entity
class Employee {
int id;
String name;
double salary;
}
// DTO
class EmployeeDTO {
String name;
EmployeeDTO(String name) {
this.name = name;
}
}List<EmployeeDTO> dtoList = employees.stream()
.map(e -> new EmployeeDTO(e.name))
.collect(Collectors.toList());This pattern is extremely common when returning API responses.
#Method References
| Instead of | Use |
|---|---|
.map(e -> e.getName()) | .map(Employee::getName) |
.map(s -> s.toUpperCase()) | .map(String::toUpperCase) |
Cleaner and more readable.
#Primitive Mapping
mapToDouble()
Suppose we need the total salary (a double):
double total = employees.stream()
.mapToDouble(Employee::getSalary)
.sum();Useful for decimal values like salaries, prices and percentages.
mapToInt()
map() would return a Stream<Integer>; mapToInt() returns an IntStream:
int totalLetters = names.stream()
.mapToInt(String::length)
.sum();IntStream has useful methods like sum(), average(), max(), min() and count().
mapToLong()
long totalViews = videos.stream()
.mapToLong(Video::getViewCount) // getViewCount() returns long
.sum();Useful when working with long values.
Why Use Primitive Streams?
Instead of Stream<Integer>, use IntStream. Advantages:
- No boxing/unboxing overhead
- Better performance
- Built-in numeric operations
int sum = numbers.stream()
.mapToInt(Integer::intValue)
.sum();#map() vs filter()
List<Integer> list = Arrays.asList(2, 3, 4, 5);| Operation | Code | Result | Effect |
|---|---|---|---|
filter() | list.stream().filter(n -> n % 2 == 0) | 2, 4 | Some elements are removed |
map() | list.stream().map(n -> n * 10) | 20, 30, 40, 50 | Every element is transformed |
Chaining filter() + map()
employees.stream()
.filter(e -> e.salary > 50000)
.map(Employee::getName)
.forEach(System.out::println);#Real Spring Boot Examples
// Get user emails
List<String> emails = users.stream()
.map(User::getEmail)
.collect(Collectors.toList());
// Convert entity to DTO
orders.stream()
.map(OrderDTO::new)
.collect(Collectors.toList());
// Format product names
products.stream()
.map(Product::getName)
.map(String::toUpperCase)
.forEach(System.out::println);
// Total order amount
double total = orders.stream()
.mapToDouble(Order::getAmount)
.sum();#Interview Questions
Q1What is the difference between map() and flatMap()?
map() transforms one element into one element. flatMap() transforms one element into zero, one or many elements and flattens the result. (Covered in detail in the flatMap chapter.)
Q2Why use mapToInt() instead of map()?
mapToInt() returns an IntStream, which avoids boxing/unboxing and provides numeric operations like sum(), average() and max().
Q3Can map() change the data type?
Yes. For example, Stream<Employee> can become Stream<String> by mapping employees to their names.
Q4Does map() modify the original object?
No. It creates a new stream with transformed values. However, if your mapping function mutates mutable objects, those mutations will affect the original objects — so avoid side effects in map().
#Practice Problems
List<Integer> numbers = Arrays.asList(2, 5, 8, 10, 15);- Square every number.
- Cube every number.
- Multiply every number by 100.
- Convert every number to a
String. - Find the sum using
mapToInt().
class Employee {
int id;
String name;
double salary;
}- Get all employee names.
- Get all employee salaries.
- Increase each salary by 10% (without modifying the original objects).
- Convert employees to
EmployeeDTO. - Calculate the total salary.
- Calculate the average salary.
- Find the maximum salary.
- Find the minimum salary.
Mini Interview Challenge
List<String> result = employees.stream()
.filter(e -> e.getSalary() > 50000)
.map(Employee::getName)
.map(String::toUpperCase)
.collect(Collectors.toList());Be prepared to explain, step by step:
- What type of stream exists after
filter()? →Stream<Employee> - What type of stream exists after the first
map()? →Stream<String> - What does the second
map()do? → Uppercases each name (stillStream<String>) - What is the final result type? →
List<String> - Why is
collect()needed? → It's the terminal operation that triggers the pipeline and gathers results
#Chapter Summary
map()andFunction<T, R>- Type-changing transformations
- Entity → DTO conversion
- Method references
mapToInt(),mapToLong(),mapToDouble()and primitive streamsmap()vsfilter()