tbsalling tbsalling - 6 months ago 99
Java Question

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.

Answer
Comparator<PositionReport> byTimestamp =
        Comparator.comparingLong(PositionReport::getTimestamp);

Supplier<TreeSet<PositionReport>> supplier =
        () -> new TreeSet<PositionReport>(byTimestamp);

positionReports = positionReports
                    .stream()
                    .filter(p -> p.getTimeStamp() >= oldestKept)
                    .collect(Collectors.toCollection(supplier));