Say I have the following map:
Map<Member, List<Message>> messages = ... //constructed somehow
I would like to use the java 8 stream api in order to obtain a:
SortedMap<Message, Member> latestMessages = ...
Where the comparator passed into the SortedMap/TreeMap would be based on the message sendDate field.
Furthermore, of the list of sent messages, I would select the latest message which would become the key to the sorted map.
How can I achieve that?
edit 1:
Comparator<Message> bySendDate = Comparator.comparing(Message::getSendDate);
SortedMap<Message, Member> latestMessages = third.entrySet().stream()
.collect(Collectors.toMap(e -> e.getValue().stream().max(bySendDate).get(), Map.Entry::getKey, (x, y) -> {
throw new AssertionError();
}, () -> new TreeMap(bySendDate.thenComparing(Comparator.comparing(Message::getId)))));
I get the following compilation error:
The method collect(Collector<? super T,A,R>) in the type Stream<T> is not applicable for the arguments (Collector<Map.Entry<Member,List<Message>>,?,TreeMap>)
Converting complete Map<Key, Value> into Stream: This can be done with the help of Map. entrySet() method which returns a Set view of the mappings contained in this map. In Java 8, this returned set can be easily converted into a Stream of key-value pairs using Set. stream() method.
Java 8 Stream's map method is intermediate operation and consumes single element forom input Stream and produces single element to output Stream. It simply used to convert Stream of one type to another. Let's see method signature of Stream's map method.
There is no inbuilt API in java for direct conversion between HashSet and HashMap , you need to iterate through set and using Entry fill in map. Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa.
Let’s dissolve this into two parts.
First, transform Map<Member, List<Message>> messages
into a Map<Message, Member> latestMessages
by reducing the messages for a particular communication partner (Member
) to the latest:
Map<Message, Member> latestMessages0 = messages.entrySet().stream()
.collect(Collectors.toMap(
e -> e.getValue().stream().max(Comparator.comparing(Message::getSendDate)).get(),
Map.Entry::getKey));
Here, the resulting map
isn’t sorted but each mapping will contain the latest message shared with that participant.
Second, if you want to have the resulting map sorted by sendDate, you have to add another secondary sort criteria to avoid losing Messages
which happen to have the same date. Assuming that you have a Long
ID that is unique, adding this ID as secondary sort criteria for messages with the same date would be sufficient:
Comparator<Message> bySendDate=Comparator.comparing(Message::getSendDate);
SortedMap<Message, Member> latestMessages = messages.entrySet().stream()
.collect(Collectors.toMap(
e -> e.getValue().stream().max(bySendDate).get(),
Map.Entry::getKey, (x,y) -> {throw new AssertionError();},
()->new TreeMap<>(bySendDate.thenComparing(Comparator.comparing(Message::getId)))));
Since sorting by the unique IDs should solve any ambiguity, I provided a merge function which will unconditionally throw, as calling it should never be required.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With