使用自定义比较器将流收集到TreeSet中

tbs*_*ing 78 java collections java-8

在Java 8中工作,我有这样的TreeSet定义:

private TreeSet<PositionReport> positionReports = 
        new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp));
Run Code Online (Sandbox Code Playgroud)

PositionReport 是一个相当简单的类定义如下:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这很好用.

现在我想删除TreeSet positionReportswhere timestamp比某个值更旧的条目.但我无法弄清楚正确的Java 8语法来表达这一点.

这个尝试实际上是编译的,但是给了我一个TreeSet带有未定义比较器的新东西:

positionReports = positionReports
        .stream()
        .filter(p -> p.timestamp >= oldestKept)
        .collect(Collectors.toCollection(TreeSet::new))
Run Code Online (Sandbox Code Playgroud)

我如何表达,我想收集TreeSet比较像Comparator.comparingLong(PositionReport::getTimestamp)

我会想到类似的东西

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

但是这不会编译/看起来是方法引用的有效语法.

gde*_*ohn 104

TreeSet<PositionReport> toTreeSet(Stream<PositionReport> reports, long timestamp) {
    return reports().filter(report -> report.getTimestamp() >= timestamp).collect(
        Collectors.toCollection(
            () -> new TreeSet<>(
                Comparator.comparingLong(PositionReport::getTimestamp)
            )
        )
    );
}
Run Code Online (Sandbox Code Playgroud)

  • 在@xtrakBandit跟进 - 如果你再不需要指定比较器(自然排序) - 你可以把它非常简洁:`.collect(Collectors.toCollection(TreeSet的::新));` (34认同)
  • 需要注意的一点是,如果TreeSet的类型(在本例中为PositionReport)实现了可比性,则不需要比较器. (3认同)

Вла*_*ник 13

这很容易使用下一个代码:

    positionReports = positionReports
        .stream()
        .filter(p -> p.timestamp >= oldestKept)
        .collect(
            Collectors.toCollection(()->new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp)
)));
Run Code Online (Sandbox Code Playgroud)


Dan*_*ott 8

您可以在最后转换为SortedSet(假设您不介意其他副本).

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

return new TreeSet(positionReports);
Run Code Online (Sandbox Code Playgroud)

  • 这样做时你必须小心.这样做时你可能会失去元素.就像上面提到的问题一样,元素的自然比较器与OP想要使用的不同.所以你在初始转换中,因为它是一个集合,它可能会丢失一些其他比较器可能没有的元素(即第一个比较器可能将`compareTo()`返回为0而另一个可能没有用于某些比较. `compareTo()`为0的那个会丢失,因为这是一个集合.) (6认同)

小智 6

Collection上有一个方法,无需使用流:default boolean removeIf(Predicate<? super E> filter).见Javadoc.

所以你的代码可能看起来像这样:

positionReports.removeIf(p -> p.timestamp < oldestKept);
Run Code Online (Sandbox Code Playgroud)