Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using streams to collect into TreeSet with custom comparator

Working in Java 8, I have a TreeSet defined like this:

private TreeSet<PositionReport> positionReports =          new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp)); 

PositionReport is a rather simple class defined like this:

public static final class PositionReport implements Cloneable {     private final long timestamp;     private final Position position;      public static PositionReport create(long timestamp, Position position) {         return new PositionReport(timestamp, position);     }      private PositionReport(long timestamp, Position position) {         this.timestamp = timestamp;         this.position = position;     }      public long getTimestamp() {         return timestamp;     }      public Position getPosition() {         return position;     } } 

This works fine.

Now I want to remove entries from the TreeSet positionReports where timestamp is older than some value. But I cannot figure out the correct Java 8 syntax to express this.

This attempt actually compiles, but gives me a new TreeSet with an undefined comparator:

positionReports = positionReports         .stream()         .filter(p -> p.timestamp >= oldestKept)         .collect(Collectors.toCollection(TreeSet::new)) 

How do I express, that I want to collect into a TreeSet with a comparator like Comparator.comparingLong(PositionReport::getTimestamp) ?

I would have thought something like

positionReports = positionReports         .stream()         .filter(p -> p.timestamp >= oldestKept)         .collect(             Collectors.toCollection(                 TreeSet::TreeSet(Comparator.comparingLong(PositionReport::getTimestamp))             )         ); 

But this does not compile / appear to be valid syntax for method references.

like image 489
tbsalling Avatar asked Feb 11 '14 09:02

tbsalling


Video Answer


1 Answers

Method references can be used when you have a method (or constructor) that fits the shape of the target you're trying to satisfy. You can't use a method reference in this case because the shape you're targeting is a Supplier, which takes no arguments, but what you have is a TreeSet constructor, which does take an argument, and you need to specify what that argument is. So you have to take the less concise approach and use a lambda expression:

TreeSet<Report> toTreeSet(Collection<Report> reports, long timestamp) {     return reports.stream().filter(report -> report.timestamp() >= timestamp).collect(         Collectors.toCollection(             () -> new TreeSet<>(Comparator.comparingLong(Report::timestamp))         )     ); } 
like image 80
gdejohn Avatar answered Sep 23 '22 23:09

gdejohn