Java 8에서 작업하면서 TreeSet
다음과 같이 정의했습니다.
private TreeSet<PositionReport> positionReports =
new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp));
PositionReport
다음과 같이 정의 된 다소 간단한 클래스입니다.
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;
}
}
이것은 잘 작동합니다.
지금은에서 항목을 제거 할 TreeSet positionReports
경우 timestamp
어떤 값보다 이전 버전입니다. 그러나 이것을 표현하는 올바른 Java 8 구문을 알아낼 수 없습니다.
이 시도는 실제로 컴파일되지만 TreeSet
정의되지 않은 비교기 로 새로운 것을 제공합니다 .
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(Collectors.toCollection(TreeSet::new))
수집하고 싶은 것을 TreeSet
비교기 로 어떻게 표현 Comparator.comparingLong(PositionReport::getTimestamp)
하나요?
나는 다음과 같은 것을 생각했을 것이다.
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(
Collectors.toCollection(
TreeSet::TreeSet(Comparator.comparingLong(PositionReport::getTimestamp))
)
);
그러나 이것은 컴파일되지 않거나 메소드 참조에 대한 유효한 구문으로 보입니다.
답변
메서드 참조는 충족하려는 대상의 모양에 이미 맞는 메서드 (또는 생성자)가있는 경우를위한 것입니다. 이 경우에는 메서드 참조를 사용할 수 없습니다. 왜냐하면 대상으로하는 셰이프는 Supplier
인수를 사용하지 않고 컬렉션을 반환하는 것이기 때문 입니다. 그러나 현재 TreeSet
가지고있는 것은 인수를받는 생성자이므로 해당 인수를 지정해야합니다. 이다. 따라서 덜 간결한 접근 방식을 취하고 람다 식을 사용해야합니다.
TreeSet<Report> toTreeSet(Collection<Report> reports, long timestamp) {
return reports.stream().filter(report -> report.timestamp() >= timestamp).collect(
Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparingLong(Report::timestamp))
)
);
}
답변
다음 코드를 사용하면 쉽습니다.
positionReports = positionReports
.stream()
.filter(p -> p.timestamp >= oldestKept)
.collect(
Collectors.toCollection(()->new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp)
)));
답변
마지막에 SortedSet으로 변환 할 수 있습니다 (추가 복사본이 마음에 들지 않는 경우).
positionReports = positionReports
.stream()
.filter(p -> p.getTimeStamp() >= oldestKept)
.collect(Collectors.toSet());
return new TreeSet(positionReports);
답변
스트림을 사용하지 않고도 Collection에 대한 메소드가 있습니다 default boolean removeIf(Predicate<? super E> filter)
. Javadoc을 참조하십시오 .
따라서 코드는 다음과 같이 보일 수 있습니다.
positionReports.removeIf(p -> p.timestamp < oldestKept);
답변
TreeSet의 문제점은 항목을 정렬하기 위해 원하는 비교기가 항목을 세트에 삽입 할 때 중복을 감지하는데도 사용된다는 것입니다. 따라서 비교기 기능이 두 항목에 대해 0이면 중복으로 간주하여 잘못 버립니다.
중복 검색은 항목의 별도의 올바른 hashCode 메서드로 수행해야합니다. 모든 속성 (예제의 ID 및 이름)을 고려하여 hashCode로 중복을 방지하고 항목을 가져올 때 간단한 정렬 된 목록을 반환하기 위해 간단한 HashSet을 사용하는 것을 선호합니다 (예제에서는 이름으로 만 정렬).
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))));
답변
