Two solutions, in which answer the second is much faster.
Solution 1
Adapting the answer from Ole VV on another question:
Collection<Entry> result = entries.stream().filter(e -> e.getAction() == 5) .collect(Collectors.groupingBy(Entry::getDetail, Collectors.collectingAndThen(Collectors.minBy(Comparator.comparing(Entry::getDate)), Optional::get))) .values();
With your example dataset, you ended up (I chose GMT + 0 as the time zone):
Entry [action=5, date=2017-03-01T00:00Z[GMT], detail=D6] Entry [action=5, date=2017-03-08T00:00Z[GMT], detail=D7] Entry [action=5, date=2017-03-10T00:00Z[GMT], detail=D8] Entry [action=5, date=2016-03-15T00:00Z[GMT], detail=D1] Entry [action=5, date=2016-09-25T00:00Z[GMT], detail=D2] Entry [action=5, date=2016-09-25T00:00Z[GMT], detail=D3]
If you insist on returning the List back:
List<Entry> result = new ArrayList<>(entries.stream() ..... .values());
If you want to return your original order, use the 3-parameter groupingBy :
...groupingBy(Entry::getDetail, LinkedHashMap::new, Collectors.collectingAndThen(...))
Decision 2
Using toMap , which is easier to read and faster (see holi-java comment on this answer and the next section):
List<Entry> col = new ArrayList<>( entries.stream().filter(e -> e.getAction() == 5) .collect(Collectors.toMap(Entry::getDetail, Function.identity(), (a,b) -> a.getDate().compareTo(b.getDate()) >= 0 ? b : a)) .values());
where (a,b) -> a.getDate().compareTo(b.getDate()) >= 0 ? b : a (a,b) -> a.getDate().compareTo(b.getDate()) >= 0 ? b : a can be replaced by:
BinaryOperator.minBy(Comparator.comparing(Entry::getDate))
If you want to return your original order in this solution, use the 4-parameter toMap :
...toMap(Entry::getDetail, Function.identity(), (a,b) -> a.getDate().compareTo(b.getDate()) >= 0 ? b : a, LinkedHashMap::new)
Performance
Using the test data that I created to test my solutions, I checked the execution time of both solutions. The first solution takes an average of 67 ms (runs only 20 times, so do not trust the numbers!), The second solution took an average of 2 ms. If someone wants to make a proper performance comparison, put the results in the comments and I will add it here.