map()

Transform each element into exactly one new value, such as an entity into a response DTO, and use the primitive variants to avoid boxing.

Signature
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
  • Added in Java Java 8

Parameters

ParameterTypeDescription
$mapperFunction<? super T, ? extends R>A non-interfering, stateless function applied to each element. Its return value becomes the element of the new stream; returning null puts a null in the stream.

Return value

Stream<R>A new stream of the results of applying the mapper to each element, one output per input, in the same encounter order.

Errors

Nothing directly. Exceptions thrown by the mapper surface when the terminal operation runs. Passing a null mapper throws NullPointerException.

map applies a function to every element and returns a stream of the results. It is strictly one in, one out: the new stream has the same number of elements, in the same order, and the element type can change from T to R.

The everyday back-end use

Most map calls in a service turn one shape into another: an entity into a response DTO, a row into a domain record, a string into a parsed number. Doing this in a mapping step is how you keep fields such as password hashes and internal flags out of JSON responses:

List<UserResponse> body = users.stream()
    .map(u -> new UserResponse(u.id(), u.email()))
    .toList();

Method references keep simple mappings short: map(String::trim), map(Integer::parseInt), map(UserResponse::from). A static factory such as from on the DTO is a common way to keep the mapping in one place.

Primitive variants

map always produces objects, so mapping to numbers boxes every value into an Integer or Long. mapToInt, mapToLong and mapToDouble return IntStream, LongStream and DoubleStream, which offer sum(), average() and summaryStatistics() and avoid the boxing. Go back with boxed() or mapToObj.

What map is not for

  • Zero or many results per element. If the function returns a list or a stream, map gives you a stream of lists. Use flatMap, or mapMulti (Java 16) to push zero or more values imperatively.
  • Side effects. Calling a remote API or saving to the database inside map hides I/O in what reads like a pure transformation, and laziness means it may not run for every element. Use a loop for work whose effects matter.
  • Changing the element in place. map(u -> { u.setActive(true); return u; }) mutates objects that other code may still hold. Prefer creating a new value, which records make easy.

Nulls and checked exceptions

If the mapper returns null, the stream carries a null and a later step may throw NullPointerException; map(cache::get) is a common source of this. Filter them out, or map to Optional and flatten. A Function cannot throw checked exceptions, so a mapper that parses JSON or reads a file has to catch and wrap the exception, typically in an UncheckedIOException or your own runtime exception.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Turn JPA entities or JDBC rows into response records so internal fields never reach the JSON body.
  • Parse a comma-separated query parameter into a list of numeric IDs before querying the database.
  • Sum line totals in pence with mapToLong when calculating an order total for an invoice.

Frequently asked questions

What is the difference between map and flatMap in Java streams?

map turns each element into exactly one result, so a function that returns a List gives you a Stream<List<X>>. flatMap expects the function to return a Stream and joins all of those streams into one flat Stream<X>.

How do I convert a list of objects into a list of one of their fields?

Map with a getter or record accessor and collect: users.stream().map(User::email).toList(). For numeric fields you want to total, use mapToInt or mapToLong and call sum().

Can I throw a checked exception inside Stream.map?

Not directly: java.util.function.Function does not declare checked exceptions, so the code will not compile. Catch the exception in the lambda and rethrow it wrapped in an unchecked exception such as UncheckedIOException, or use a plain loop if the error handling is central to the code.

More examples

mapToInt for totals without boxing

mapToInt returns an IntStream, which has sum() and summaryStatistics() built in. Keeping money as whole pence in an int or long avoids floating-point rounding in totals.

Example · java
record Line(String sku, int qty, int unitPence) {}

void main() {
    List<Line> cart = List.of(
        new Line("A", 2, 450),
        new Line("B", 1, 1299),
        new Line("C", 3, 100));

    int totalPence = cart.stream()
        .mapToInt(l -> l.qty() * l.unitPence())
        .sum();
    IO.println(totalPence);

    IntSummaryStatistics qty = cart.stream()
        .mapToInt(Line::qty)
        .summaryStatistics();
    IO.println(qty.getMin() + " " + qty.getMax() + " " + qty.getAverage());
}
// Output:
// 2499
// 1 3 2.0

Parsing input, and where nulls come from

Chained maps read as a series of small conversions. A lookup that misses returns null, and map passes that null straight through, so filter it out before anything calls a method on it.

Example · java
void main() {
    String query = "ids=4, 8 ,15";
    List<Integer> ids = Arrays.stream(query.substring(4).split(","))
        .map(String::trim)
        .map(Integer::parseInt)
        .toList();
    IO.println(ids);

    Map<String, String> names = Map.of("u1", "Ada", "u2", "Linus");
    List<String> resolved = Stream.of("u1", "u9", "u2")
        .map(names::get)
        .toList();
    IO.println(resolved);
}
// Output:
// [4, 8, 15]
// [Ada, null, Linus]

mapMulti when one element gives zero or more results

map must produce exactly one value per element, so it cannot skip or duplicate. mapMulti (Java 16) hands you a sink to push zero or more values into, here doing a type check and cast in one step.

Example · java
void main() {
    List<Object> raw = List.of(1, "two", 3, 4.5, 5);

    List<Integer> ints = raw.stream()
        .<Integer>mapMulti((o, sink) -> {
            if (o instanceof Integer i) {
                sink.accept(i);
            }
        })
        .toList();
    IO.println(ints);
}
// Output:
// [1, 3, 5]

Discussion

  • Be the first to comment on this lesson.