Streams
Performance Tips
Creating Streams in a Non-Optimal Way
Avoid creating a stream from a collection every time you need to process it. Instead, create it once and reuse it.
Avoid stateful operations
Stateful operations, such as sorted() or distinct(), can cause performance issues. So use them wisely.
Remove duplicates
If not explicitly required, remove duplicates.
List<String> systems = Arrays.asList("c64", "amiga", "amiga", "lynx");
List<String> uniqueItems = systems.stream()
.distinct()
.collect(Collectors.toList());
// Result: c64, amiga, lynx
Filter before map
List<String> systems = Arrays.asList("c64", "amiga", "lynx");
List<String> filteredList = list.stream()
.filter(s -> "lynx".compareTo(syste)!="lynx")
.map(String::toUpperCase)
.collect(Collectors.toList());
First remove all not important elements and only map the reduced entities
General Tips
Avoid Nullpointer Exceptions
You can avoid NPE by filtering them out.
List<String> filteredNames = list.stream()
.flatMap(Stream::ofNullable)
.collect(Collectors.toList());
List<String> filteredNames = list.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
Sequence generator
Easy way to generate sequences.
Stream.iterate(1, n -> n + 3)
.limit(6)
.forEach(System.out::println);
// Result: 1, 4, 7, 10, 13, 16
Post processing of streams
You can process a stream, collect the result and made some post processing with collectAndThen
long carSales = cars.stream()
.collect(Collectors.collectingAndThen(
Collectors.averagingDouble(cars::getSalePrice),
Math::round));
takeWhile, dropWhile
With take while, dropWhile you can slice your collection. The difference to filter is, that filter will evaluate each member of the stream. takeWhile, dropWhile will abort the stream on the first occurrence of an item which does not satisfy the condition. So it can massivly improve the performance on sorted lists. But beware.
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8);
List<Integer> taken = numbers.stream()
.takeWhile(n -> n < 5)
.collect(Collectors.toList());
// Result [1, 2, 3, 4]
List<Integer> numbers = List.of(1, 2, 6, 7, 8);
List<Integer> taken = numbers.stream()
.dropWhile(n -> n < 5)
.collect(Collectors.toList());
// Result [1, 2]
Collectors.teeing
The Collectors.teeing() method is useful when we want to simultaneously process a stream in two different ways and then combine their results. If not using the teeing() method, we would have processed the stream two times
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8);
String result = numbers.stream().collect(
Collectors.teeing(
Collectors.averagingInt(Integer::intValue),
Collectors.summingInt(Integer::intValue),
(average, sum) -> String.format("Average: %.2f, Sum: %d", average, sum)
)
);