Travailler dans Java 8, j’ai un 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 bien.
Maintenant, je veux supprimer des entrées du TreeSet positionReports
Où timestamp
est plus ancien qu'une valeur. Mais je ne peux pas comprendre la syntaxe correcte Java 8 pour exprimer cela.
Cette tentative compile, mais me donne un nouveau TreeSet
avec un comparateur indéfini:
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(Collectors.toCollection(TreeSet::new))
Comment puis-je exprimer ce que je veux rassembler 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.
Comparator<PositionReport> byTimestamp =
Comparator.comparingLong(PositionReport::getTimestamp);
Supplier<TreeSet<PositionReport>> supplier =
() -> new TreeSet<PositionReport>(byTimestamp);
positionReports = positionReports.stream()
.filter(p -> p.getTimeStamp() >= oldestKept)
.collect(Collectors.toCollection(supplier));
C'est simple, utilisez le code suivant:
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(
Collectors.toCollection(()->new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp)
)));
Vous pouvez simplement convertir 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);
Il existe une méthode sur Collection pour cela sans avoir à utiliser de flux: default boolean removeIf(Predicate<? super E> filter)
. Voir Javadoc .
Donc, votre code pourrait ressembler à ceci:
positionReports.removeIf(p -> p.timestamp < oldestKept);
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 un doublon.
La détection des doublons doit être effectuée par une méthode distincte, hashCode, des éléments. Je préfère utiliser un simple HashSet pour éviter les doublons avec un hashCode prenant en compte toutes les propriétés (id et name dans l'exemple) et renvoyer une simple liste triée lors de l'extraction 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());
}
}
positionReports = positionReports.stream()
.filter(p -> p.getTimeStamp() >= oldestKept)
.collect(Collectors.toCollection(() -> new
TreeSet<PositionReport>(Comparator.comparingLong(PositionReport::getTimestamp))));