Bei der Arbeit in Java 8 habe ich Folgendes TreeSet
definiert:
private TreeSet<PositionReport> positionReports =
new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp));
PositionReport
ist eine ziemlich einfache Klasse, die wie folgt definiert ist:
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;
}
}
Das funktioniert gut.
Jetzt möchte ich Einträge aus dem entfernen , TreeSet positionReports
wo timestamp
älter ist als ein Wert. Aber ich kann nicht die richtige Java 8-Syntax herausfinden, um dies auszudrücken.
Dieser Versuch wird tatsächlich kompiliert, gibt mir aber einen neuen TreeSet
mit einem undefinierten Komparator:
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(Collectors.toCollection(TreeSet::new))
Wie drücke ich aus, dass ich TreeSet
mit einem Komparator wie in einem sammeln möchte Comparator.comparingLong(PositionReport::getTimestamp)
?
Ich hätte so etwas gedacht
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(
Collectors.toCollection(
TreeSet::TreeSet(Comparator.comparingLong(PositionReport::getTimestamp))
)
);
Dies kompiliert / scheint jedoch keine gültige Syntax für Methodenreferenzen zu sein.
quelle
.collect(Collectors.toCollection(TreeSet::new));
toCollection in class Collectors cannot be applied to given types
Collectors::toCollection
: aSupplier
, das a zurückgibtCollection
.Supplier
ist ein Typ mit nur einer abstrakten Methode, was bedeutet, dass er wie in dieser Antwort das Ziel eines Lambda-Ausdrucks sein kann. Der Lambda-Ausdruck darf keine Argumente annehmen (daher die leere Argumentliste()
) und eine Sammlung mit einem Elementtyp zurückgeben, der dem Typ der Elemente in dem Stream entspricht, den Sie sammeln (in diesem Fall aTreeSet<PositionReport>
).Dies ist einfach, verwenden Sie einfach den nächsten Code:
quelle
Sie können am Ende einfach in ein SortedSet konvertieren (vorausgesetzt, die zusätzliche Kopie macht Ihnen nichts aus).
quelle
compareTo()
0 zurück, während der andere möglicherweise nicht für einige Vergleiche verwendet wird. Alle Elemente , bei denencompareTo()
0 ist ist verloren, da dies ein Satz ist.)Hierfür gibt es eine Methode für die Sammlung, ohne Streams verwenden zu müssen :
default boolean removeIf(Predicate<? super E> filter)
. Siehe Javadoc .Ihr Code könnte also so aussehen:
quelle
Das Problem mit TreeSet ist, dass der Komparator, den wir zum Sortieren der Elemente benötigen, auch zum Erkennen von Duplikaten beim Einfügen von Elementen in das Set verwendet wird. Wenn die Komparatorfunktion für zwei Elemente 0 ist, wird eines fälschlicherweise verworfen, wenn es als doppelt betrachtet wird.
Die Erkennung von Duplikaten sollte durch eine separate korrekte hashCode-Methode der Elemente erfolgen. Ich bevorzuge es, ein einfaches HashSet zu verwenden, um Duplikate mit einem HashCode unter Berücksichtigung aller Eigenschaften (ID und Name im Beispiel) zu verhindern und beim Abrufen der Elemente eine einfache sortierte Liste zurückzugeben (im Beispiel nur nach Namen sortieren):
quelle
quelle