1. ホーム
  2. java

[解決済み] ストリームを使用してカスタムコンパレータでTreeSetに収集する

2022-10-10 17:36:31

質問

Java 8 で作業しているとき、私は TreeSet はこのように定義されています。

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

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

これは問題なく動作します。

今度は TreeSet positionReports ここで timestamp はある値より古いです。しかし、これを表現するための正しい Java 8 構文がわかりません。

この試みは実際にコンパイルされますが、新しい TreeSet を未定義のコンパレータで返します。

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

に集めたい場合は、どのように表現すればよいのでしょうか? TreeSet のようなコンパレータで Comparator.comparingLong(PositionReport::getTimestamp) ?

私は次のようなものを考えていました。

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

しかし、これはコンパイルできませんし、メソッド参照のための有効な構文でもないように見えます。

どのように解決するのですか?

メソッド参照は、満たそうとしている対象の形状に合ったメソッド(またはコンストラクタ)がある場合に使うことができます。この場合、メソッド参照を使うことはできません。なぜなら、対象としている形状は Supplier で、これは引数を取らないのですが、あなたが持っているのは TreeSet のコンストラクタは引数を取りますが、その引数が何であるかを指定する必要があります。そのため、あまり簡潔ではないアプローチをとって、ラムダ式を使用する必要があります。

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