Java 使用流通过自定义比较器收集到 TreeSet 中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21697349/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 10:08:11  来源:igfitidea点击:

Using streams to collect into TreeSet with custom comparator

javacollectionsjava-8

提问by tbsalling

Working in Java 8, I have a TreeSetdefined like this:

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

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

PositionReportis a rather simple class defined like this:

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;
    }
}

This works fine.

这工作正常。

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

现在我想从比某个值旧的TreeSet positionReportswhere 中删除条目timestamp。但我无法找出正确的 Java 8 语法来表达这一点。

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

这种尝试实际上可以编译,但给了我一个TreeSet带有未定义比较器的 new :

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

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

我如何表达,我想TreeSet用一个比较器收集到一个中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.

但这不能编译/似乎是方法引用的有效语法。

采纳答案by gdejohn

TreeSet<PositionReport> toTreeSet(Collection<PositionReport> reports, long timestamp) {
    return reports.stream().filter(report -> report.getTimestamp() >= timestamp).collect(
        Collectors.toCollection(
            () -> new TreeSet<>(
                Comparator.comparingLong(PositionReport::getTimestamp)
            )
        )
    );
}

回答by Daniel Scott

You can just convert into a SortedSet at the end (provided that you don't mind the additional copy).

您可以在最后转换为 SortedSet (前提是您不介意额外的副本)。

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

return new TreeSet(positionReports);

回答by Michael Damone

There is a method on Collection for this without having to use streams: default boolean removeIf(Predicate<? super E> filter). See Javadoc.

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

So your code could just look like this:

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

positionReports.removeIf(p -> p.timestamp < oldestKept);

回答by Владимир Дворник

This is easy just use next code:

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

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

回答by Daniel Mora

The problem with TreeSet is that the comparator that we want for sorting the items is used also for detecting duplicates when inserting items into the set. So if the comparator function is 0 for two items it wrongly discards one considering it as duplicate.

TreeSet 的问题在于,我们想要对项目进行排序的比较器也用于在将项目插入集合时检测重复项。因此,如果两个项目的比较器函数为 0,它会错误地丢弃一个,将其视为重复项。

The duplicates detection should be done by a separate correct hashCode method of the items. I prefer to use a simple HashSet to prevent duplicates with a hashCode considering all properties (id and name in the example) and return a simple sorted List when getting the items (sorting only by name in the example):

重复项检测应通过项目的单独正确 hashCode 方法完成。考虑到所有属性(示例中的 id 和名称),我更喜欢使用简单的 HashSet 来防止使用 hashCode 重复,并在获取项目时返回一个简单的排序列表(示例中仅按名称排序):

public class ProductAvailableFiltersDTO {

    private Set<FilterItem> category_ids = new HashSet<>();

    public List<FilterItem> getCategory_ids() {
        return category_ids.stream()
            .sorted(Comparator.comparing(FilterItem::getName))
            .collect(Collectors.toList());
    }

    public void setCategory_ids(List<FilterItem> category_ids) {
        this.category_ids.clear();
        if (CollectionUtils.isNotEmpty(category_ids)) {
            this.category_ids.addAll(category_ids);
        }
    }
}


public class FilterItem {
    private String id;
    private String name;

    public FilterItem(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof FilterItem)) return false;
        FilterItem that = (FilterItem) o;
        return Objects.equals(getId(), that.getId()) &&
                Objects.equals(getName(), that.getName());
    }

    @Override
    public int hashCode() {

        return Objects.hash(getId(), getName());
    }
}

回答by Cyril Sojan

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