Travaillant en Java 8, j'ai TreeSet
défini comme ceci:
private TreeSet<PositionReport> positionReports =
new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp));
PositionReport
est une classe assez simple définie comme ceci:
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;
}
}
Cela fonctionne très bien.
Maintenant, je veux supprimer les entrées de TreeSet positionReports
où timestamp
est plus ancienne qu'une certaine valeur. Mais je ne peux pas comprendre la syntaxe Java 8 correcte pour exprimer cela.
Cette tentative compile en fait, mais me donne un nouveau TreeSet
avec un comparateur non défini:
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(Collectors.toCollection(TreeSet::new))
Comment exprimer ce que je souhaite collecter dans un TreeSet
avec un comparateur comme Comparator.comparingLong(PositionReport::getTimestamp)
?
J'aurais pensé à quelque chose comme
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(
Collectors.toCollection(
TreeSet::TreeSet(Comparator.comparingLong(PositionReport::getTimestamp))
)
);
Mais cela ne compile pas / ne semble pas être une syntaxe valide pour les références de méthode.
la source
.collect(Collectors.toCollection(TreeSet::new));
toCollection in class Collectors cannot be applied to given types
Collectors::toCollection
: aSupplier
qui renvoie aCollection
.Supplier
est un type avec une seule méthode abstraite, ce qui signifie qu'il peut être la cible d'une expression lambda comme dans cette réponse. L'expression lambda ne doit prendre aucun argument (d'où la liste d'arguments vide()
) et retourner une collection avec un type d'élément qui correspond au type des éléments dans le flux que vous collectez (dans ce cas aTreeSet<PositionReport>
).C'est facile, utilisez simplement le code suivant:
positionReports = positionReports .stream() .filter(p -> p.timestamp >= oldestKept) .collect( Collectors.toCollection(()->new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp) )));
la source
Vous pouvez simplement convertir en un SortedSet à la fin (à condition que la copie supplémentaire ne vous dérange pas).
positionReports = positionReports .stream() .filter(p -> p.getTimeStamp() >= oldestKept) .collect(Collectors.toSet()); return new TreeSet(positionReports);
la source
compareTo()
comme 0 tandis que l'autre pourrait ne pas avoir pour certaines comparaisons. Tous ceux oùcompareTo()
vaut 0 est perdu car il s'agit d'un ensemble.)Il existe une méthode de collecte pour cela sans avoir à utiliser les flux:
default boolean removeIf(Predicate<? super E> filter)
. Voir Javadoc .Votre code pourrait donc ressembler à ceci:
la source
Le problème avec TreeSet est que le comparateur que nous voulons pour trier les éléments est également utilisé pour détecter les doublons lors de l'insertion d'éléments dans l'ensemble. Donc, si la fonction de comparaison est 0 pour deux éléments, elle en écarte à tort un en la considérant comme dupliquée.
La détection des doublons doit être effectuée par une méthode de hashCode correcte distincte des éléments. Je préfère utiliser un simple HashSet pour éviter les doublons avec un hashCode en tenant compte de toutes les propriétés (id et nom dans l'exemple) et renvoyer une simple liste triée lors de l'obtention des éléments (tri uniquement par nom dans l'exemple):
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()); } }
la source
positionReports = positionReports.stream() .filter(p -> p.getTimeStamp() >= oldestKept) .collect(Collectors.toCollection(() -> new TreeSet<PositionReport>(Comparator.comparingLong(PositionReport::getTimestamp))));
la source