Definition
map(String::length)transforms aStreaminto aStream, boxing each int.mapToInt(String::length)produces a primitiveIntStreamwith no boxing, more efficient.- IntStream terminals:
sum(),average(),max(),summaryStatistics()work directly on primitives. - Boxed conversion:
IntStream.boxed()converts back toStreamfor collecting into a List. - UTF-16 caveat:
length()counts code units, not visual characters.
The forms officer at the National Bank of India is designing name boxes on a printed cheque and needs to know how many characters each name has so the boxes fit. She counts the letters in each name and writes the count.
Understanding the Concepts
What does mapping to length do?
The String.length() method returns the number of characters in the string as an int. Applying it through map, as map(String::length), transforms a stream of names into a stream of lengths, one length per name. It is a one-to-one transformation, so the result has the same number of elements as the input.
How do you get a list of name lengths?
package com.bank.hr;
import java.util.List;
import java.util.stream.Collectors;
public class NameLengths {
public static void main(String[] args) {
List<String> names = List.of("Rajesh", "Priya", "Amit", "Kavita");
// Using map (boxes each int into Integer)
List<Integer> lengths = names.stream()
.map(String::length)
.collect(Collectors.toList());
System.out.println(lengths);
}
}
[6, 5, 4, 6]
How is map different from mapToInt for this case?
| Method | Result type | Boxing? | Numeric terminals? |
|---|---|---|---|
| map(String::length) | Stream
| mapToInt(String::length) | IntStream | No boxing | sum(), average(), max() |
import java.util.IntSummaryStatistics;
// mapToInt: no boxing, direct numeric operations
IntSummaryStatistics stats = names.stream()
.mapToInt(String::length)
.summaryStatistics();
System.out.println("Max: " + stats.getMax());
System.out.println("Min: " + stats.getMin());
System.out.println("Avg: " + stats.getAverage());
Max: 6
Min: 4
Avg: 5.25
How do you collect IntStream into a List?
IntStream cannot be collected directly with Collectors.toList() because toList expects objects. Call boxed() first to convert each primitive int back to an Integer.
List<Integer> lengths = names.stream()
.mapToInt(String::length)
.boxed()
.collect(Collectors.toList());
What are common mistakes?
Mistake: trying to collect an IntStream directly with Collectors.toList().
// WRONG: IntStream has no collect(Collector) overload
// names.stream().mapToInt(String::length)
// .collect(Collectors.toList()); // compilation error!
// CORRECT: box first
List<Integer> lengths = names.stream()
.mapToInt(String::length)
.boxed()
.collect(Collectors.toList());
What about the UTF-16 code unit caveat?
For text with characters outside the basic range, like emoji or certain scripts, length() counts UTF-16 code units, not visual characters. A single emoji can report length 2.
String emoji = "\uD83D\uDE00"; // smiley face
System.out.println(emoji.length()); // 2 (two code units)
System.out.println(emoji.codePointCount(0, emoji.length())); // 1 (one code point)
For employee names in English or Hindi this rarely matters, but a senior engineer knows the distinction.
What about using the lengths for further processing?
// Find the longest name
names.stream()
.max(java.util.Comparator.comparingInt(String::length))
.ifPresent(n -> System.out.println("Longest: " + n));
Longest: Rajesh
What should a senior engineer know?
- Prefer
mapToIntovermapfor primitive results to avoid boxing overhead on large datasets. - IntStream offers
sum(),average(),max(),min(), andsummaryStatistics()for free. length()is O(1) for String because the length is stored as a field, so mapping to lengths does not add significant overhead.- The distinction between code units and code points matters when correctness over arbitrary Unicode is required.
What are common interview follow-up questions?
- "When would you use mapToInt instead of map?" When the result is a primitive int, to avoid boxing.
- "How do you get statistics from the lengths?" Use
mapToInt(String::length).summaryStatistics(). - "What does length() actually count?" UTF-16 code units, not visual characters.
Visual Overview
List<String>
["Rajesh", "Priya", "Amit", "Kavita"]
│
│ .mapToInt(String::length)
▼
IntStream
[6, 5, 4, 6] ← primitive ints, no boxing
│
│ .boxed().collect(toList())
▼
List<Integer> [6, 5, 4, 6]
Or directly:
│ .summaryStatistics()
▼
IntSummaryStatistics{count=4, sum=21, min=4, avg=5.25, max=6}
Key Takeaway
To turn each name into its character count I map with the String length method. For efficiency I prefer mapToInt(String::length), which produces a primitive IntStream with no boxing, whereas ordinary map(String::length) wraps every length in an Integer. The IntStream also unlocks numeric terminals like sum, average, and summaryStatistics.
In my banking project at the National Bank of India this was for printing personalised cheque books. The design team needed each account holder's name length to size the printed name field: a very long name needs a smaller font.
To collect an IntStream into a Listboxed() first, since IntStream has no collect(Collector) overload. I also note that length() counts UTF-16 code units, not visual characters, so a single emoji reports length 2, but for ordinary employee names this distinction is purely academic.
Remember one sentence: mapToInt(String::length) produces a boxing-free IntStream of character counts with access to sum, average, and statistics.
---