🏷 Streams API
12 patterns
Topic: Streams API
All Java patterns related to Streams API — java.evolved
Collections
Collectors.teeing()
Old
long count = items.stream().count();
double sum = items.stream()
.mapToDouble(Item::price)
.sum();
var result = new Stats(count, sum);
Modern
var result = items.stream().collect(
Collectors.teeing(
Collectors.counting(),
Collectors.summingDouble(Item::price),
Stats::new
)
);
hover to see modern →
JDK 12+
learn more →
Collections
Typed stream toArray
Old
List<String> list = getNames();
List<String> filtered = new ArrayList<>();
for (String n : list) {
if (n.length() > 3) {
filtered.add(n);
}
}
String[] arr = filtered.toArray(new String[0]);
Modern
String[] arr = getNames().stream()
.filter(n -> n.length() > 3)
.toArray(String[]::new);
hover to see modern →
JDK 8+
learn more →
Collections
Unmodifiable collectors
Old
List<String> list = stream.collect(
Collectors.collectingAndThen(
Collectors.toList(),
Collections::unmodifiableList
)
);
Modern
List<String> list = stream.toList();
hover to see modern →
JDK 16+
learn more →
Strings
String chars as stream
Old
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (Character.isDigit(c)) {
process(c);
}
}
Modern
str.chars()
.filter(Character::isDigit)
.forEach(c -> process((char) c));
hover to see modern →
JDK 9+
learn more →
Streams
Collectors.flatMapping()
Old
// Flatten within a grouping collector
// Required complex custom collector
Map<String, Set<String>> tagsByDept =
// no clean way in Java 8
Modern
var tagsByDept = employees.stream()
.collect(groupingBy(
Emp::dept,
flatMapping(
e -> e.tags().stream(),
toSet()
)
));
hover to see modern →
JDK 9+
learn more →
Streams
Predicate.not() for negation
Old
List<String> nonEmpty = list.stream()
.filter(s -> !s.isBlank())
.collect(Collectors.toList());
Modern
List<String> nonEmpty = list.stream()
.filter(Predicate.not(String::isBlank))
.collect(Collectors.toList());
hover to see modern →
JDK 11+
learn more →
Streams
Stream gatherers
Old
// Sliding window: manual implementation
List<List<T>> windows = new ArrayList<>();
for (int i = 0; i <= list.size()-3; i++) {
windows.add(
list.subList(i, i + 3));
}
Modern
var windows = stream
.gather(
Gatherers.windowSliding(3)
)
.toList();
hover to see modern →
JDK 24+
learn more →
Streams
Stream.iterate() with predicate
Old
Stream.iterate(1, n -> n * 2)
.limit(10)
.forEach(System.out::println);
// can't stop at a condition
Modern
Stream.iterate(
1,
n -> n < 1000,
n -> n * 2
).forEach(IO::println);
// stops when n >= 1000
hover to see modern →
JDK 9+
learn more →
Streams
Stream.mapMulti()
Old
stream.flatMap(order ->
order.items().stream()
.map(item -> new OrderItem(
order.id(), item)
)
);
Modern
stream.<OrderItem>mapMulti(
(order, downstream) -> {
for (var item : order.items())
downstream.accept(
new OrderItem(order.id(), item));
}
);
hover to see modern →
JDK 16+
learn more →
Streams
Stream.ofNullable()
Old
Stream<String> s = val != null
? Stream.of(val)
: Stream.empty();
Modern
Stream<String> s =
Stream.ofNullable(val);
hover to see modern →
JDK 9+
learn more →
Streams
Stream takeWhile / dropWhile
Old
List<Integer> result = new ArrayList<>();
for (int n : sorted) {
if (n >= 100) break;
result.add(n);
}
// no stream equivalent in Java 8
Modern
var result = sorted.stream()
.takeWhile(n -> n < 100)
.toList();
// or: .dropWhile(n -> n < 10)
hover to see modern →
JDK 9+
learn more →
Streams
Stream.toList()
Old
List<String> result = stream
.filter(s -> s.length() > 3)
.collect(Collectors.toList());
Modern
List<String> result = stream
.filter(s -> s.length() > 3)
.toList();
hover to see modern →
JDK 16+
learn more →