The last step of a multi-list pipeline is usually a human reading it. printf with explicit widths and Locale.ROOT keeps the columns lined up and the decimal separator stable wherever the JVM runs.
record Region(String code, String name) {}
record Sale(String regionCode, double amount) {}
var regions = List.of(new Region("E", "East"), new Region("W", "West"), new Region("N", "North"));
var sales = List.of(new Sale("E", 1200.0), new Sale("W", 850.5), new Sale("E", 300.0));
Map<String, Double> totals = sales.stream()
.collect(Collectors.groupingBy(Sale::regionCode, TreeMap::new,
Collectors.summingDouble(Sale::amount)));
System.out.printf(Locale.ROOT, "%-8s %10s%n", "REGION", "TOTAL");
regions.stream()
.sorted(Comparator.comparing(Region::name))
.forEach(r -> System.out.printf(Locale.ROOT, "%-8s %10.2f%n",
r.name(), totals.getOrDefault(r.code(), 0.0)));
REGION TOTAL
East 1500.00
North 0.00
West 850.50
Run this yourself in the Online Java Compiler, spin up a live REST API in the API Sandbox, or practise with Java interview questions.
Published 2026-09-20