Trabalhando em Java 8, tenho um TreeSet
definido assim:
private TreeSet<PositionReport> positionReports =
new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp));
PositionReport
é uma classe bastante simples definida assim:
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;
}
}
Isso funciona bem.
Agora quero remover as entradas de TreeSet positionReports
onde timestamp
é mais antigo que algum valor. Mas não consigo descobrir a sintaxe correta do Java 8 para expressar isso.
Essa tentativa realmente compila, mas me dá uma novidade TreeSet
com um comparador indefinido:
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(Collectors.toCollection(TreeSet::new))
Como posso expressar que desejo coletar em um TreeSet
com um comparador como Comparator.comparingLong(PositionReport::getTimestamp)
?
Eu teria pensado algo como
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(
Collectors.toCollection(
TreeSet::TreeSet(Comparator.comparingLong(PositionReport::getTimestamp))
)
);
Mas isso não compila / parece ser uma sintaxe válida para referências de método.
fonte
.collect(Collectors.toCollection(TreeSet::new));
toCollection in class Collectors cannot be applied to given types
Collectors::toCollection
: aSupplier
que retorna aCollection
.Supplier
é um tipo com apenas um único método abstrato, o que significa que pode ser o destino de uma expressão lambda como nesta resposta. A expressão lambda não deve ter argumentos (daí a lista de argumentos vazia()
) e retornar uma coleção com um tipo de elemento que corresponda ao tipo dos elementos no fluxo que você está coletando (neste caso, aTreeSet<PositionReport>
).Isso é fácil, basta usar o próximo código:
positionReports = positionReports .stream() .filter(p -> p.timestamp >= oldestKept) .collect( Collectors.toCollection(()->new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp) )));
fonte
Você pode simplesmente converter em um SortedSet no final (desde que você não se importe com a cópia adicional).
positionReports = positionReports .stream() .filter(p -> p.getTimeStamp() >= oldestKept) .collect(Collectors.toSet()); return new TreeSet(positionReports);
fonte
compareTo()
como 0, enquanto o outro pode não retornar para algumas comparações. Todos aqueles em quecompareTo()
é 0 está perdido, pois este é um conjunto.)Existe um método de coleção para este sem ter que usar correntes:
default boolean removeIf(Predicate<? super E> filter)
. Veja Javadoc .Portanto, seu código pode ter a seguinte aparência:
fonte
O problema com TreeSet é que o comparador que queremos para classificar os itens também é usado para detectar duplicatas ao inserir itens no conjunto. Portanto, se a função comparadora for 0 para dois itens, ela descartará um, considerando-o como duplicado.
A detecção de duplicatas deve ser feita por um método hashCode correto separado dos itens. Eu prefiro usar um HashSet simples para evitar duplicatas com um hashCode considerando todas as propriedades (id e nome no exemplo) e retornar uma lista ordenada simples ao obter os itens (classificação apenas por nome no exemplo):
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()); } }
fonte
positionReports = positionReports.stream() .filter(p -> p.getTimeStamp() >= oldestKept) .collect(Collectors.toCollection(() -> new TreeSet<PositionReport>(Comparator.comparingLong(PositionReport::getTimestamp))));
fonte