How can I collect only the elements of the greatest length with Java Streams?
Try this:
List<String> strings = Arrays.asList("long word", "short", "long wwww", "llll wwww", "shr");
List<String> longest = strings.stream()
.collect(groupingBy(String::length, TreeMap::new, toList()))
.lastEntry()
.getValue();
System.out.println(longest);
Output:
[long word, long wwww, llll wwww]
Well, I don't know if this will be more elegant but it should do what you want:
List<String> strings = Arrays.asList("long word", "short", "long wwww", "llll wwww", "shr");
List<String> longest = strings.stream()
.collect(Collectors.groupingBy(String::length)) // Build Map<Length, List<Strings>>
.entrySet().stream() // EntrySet stream of said map
.max(Map.Entry.comparingByKey()) // Keep max length
.map(Map.Entry::getValue) // Get value of max length
.orElse(Collections.emptyList()); // Or return an empty list if there's none
System.out.println(longest);
Output:
[long word, long wwww, llll wwww]
You may consider it uglier, but a custom collector is definitely correct, more efficient, and even parallelizes nicely:
Collector<String, List<String>, List<String>> collector = Collector.of(
ArrayList::new,
(list, elem) -> {
if (list.isEmpty() || elem.length() == list.get(0).length()) {
list.add(elem);
} else if (elem.length() > list.get(0).length()) {
list.clear();
list.add(elem);
}
},
(list1, list2) -> {
int len1 = list1.isEmpty() ? -1 : list1.get(0).length();
int len2 = list2.isEmpty() ? -1 : list2.get(0).length();
if (len1 < len2) {
return list2;
} else if (len1 > len2) {
return list1;
} else {
list1.addAll(list2);
return list1;
}
});
return strings.stream().collect(collector);