Pracując w Javie 8 mam takie TreeSet
zdefiniowane:
private TreeSet<PositionReport> positionReports =
new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp));
PositionReport
jest raczej prostą klasą zdefiniowaną w ten sposób:
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;
}
}
To działa dobrze.
Teraz chcę usunąć wpisy z miejsca, w TreeSet positionReports
którym timestamp
jest starszy niż jakaś wartość. Ale nie mogę znaleźć poprawnej składni Java 8, aby to wyrazić.
Ta próba faktycznie się kompiluje, ale daje mi nową TreeSet
z niezdefiniowanym komparatorem:
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(Collectors.toCollection(TreeSet::new))
Jak wyrazić, że chcę zebrać do postaci TreeSet
z komparatorem Comparator.comparingLong(PositionReport::getTimestamp)
?
Pomyślałbym coś takiego
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(
Collectors.toCollection(
TreeSet::TreeSet(Comparator.comparingLong(PositionReport::getTimestamp))
)
);
Ale to nie kompiluje / nie wydaje się poprawną składnią dla odwołań do metod.
źródło
.collect(Collectors.toCollection(TreeSet::new));
toCollection in class Collectors cannot be applied to given types
Collectors::toCollection
: a,Supplier
który zwraca aCollection
.Supplier
jest typem z tylko jedną metodą abstrakcyjną, co oznacza, że może być celem wyrażenia lambda, jak w tej odpowiedzi. Wyrażenie lambda nie może przyjmować żadnych argumentów (stąd pusta lista argumentów()
) i zwracać kolekcję z typem elementu, który pasuje do typu elementów w zbieranym strumieniu (w tym przypadku aTreeSet<PositionReport>
).Jest to łatwe, wystarczy użyć następnego kodu:
positionReports = positionReports .stream() .filter(p -> p.timestamp >= oldestKept) .collect( Collectors.toCollection(()->new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp) )));
źródło
Możesz po prostu przekonwertować na SortedSet na końcu (pod warunkiem, że nie masz nic przeciwko dodatkowej kopii).
positionReports = positionReports .stream() .filter(p -> p.getTimeStamp() >= oldestKept) .collect(Collectors.toSet()); return new TreeSet(positionReports);
źródło
compareTo()
jako 0, podczas gdy drugi może nie mieć dla niektórych porównań. Wszystkie te, w którychcompareTo()
jest 0 jest stracony, ponieważ jest to zestaw.)Jest to metoda na Collection za to bez konieczności stosowania strumienie:
default boolean removeIf(Predicate<? super E> filter)
. Zobacz Javadoc .Twój kod może wyglądać tak:
źródło
Problem z TreeSet polega na tym, że komparator, którego potrzebujemy do sortowania elementów, jest również używany do wykrywania duplikatów podczas wstawiania elementów do zestawu. Więc jeśli funkcja komparatora wynosi 0 dla dwóch pozycji, błędnie odrzuca jedną, która uważa ją za duplikat.
Wykrywanie duplikatów powinno odbywać się osobną, poprawną metodą hashCode elementów. Wolę używać prostego HashSet, aby zapobiec duplikatom z hashCode biorąc pod uwagę wszystkie właściwości (identyfikator i nazwę w przykładzie) i zwracać prostą posortowaną listę podczas pobierania elementów (sortowanie tylko według nazwy w przykładzie):
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()); } }
źródło
positionReports = positionReports.stream() .filter(p -> p.getTimeStamp() >= oldestKept) .collect(Collectors.toCollection(() -> new TreeSet<PositionReport>(Comparator.comparingLong(PositionReport::getTimestamp))));
źródło