У меня есть Collection<Event>. Event выглядит примерно так
public class Event {
private Integer id;
private LocalDateTime localDateTime;
// getters, setters omitted
}
Каждый Event в этом Collection должен иметь уникальные id и localDateTime. Как я могу выполнить эту проверку с помощью потокового API и вернуть true, если условие выполнено?
^^ иметь уникальные id и localDateTime... уникальные значения каждого из них или обоих в комбинации?
Поиск того, имеет ли итерируемый объект 2 одинаковых элемента, имеет ту же сложность, что и его сортировка O (n log n). Таким образом, либо вы держите помощника HashSet для проверки членства, пока вы выполняете итерацию по нему, чтобы достичь амортизированной сложности O (n), либо вы просто сортируете его и выполняете итерацию, «застегивая» каждый элемент на следующий и проверяя на равенство.
@Naman уникальные значения каждого из них.
@downvoter Не могли бы вы пояснить, почему мой вопрос бесполезен?




import java.util.concurrent.atomic.AtomicInteger;
public class Event {
private static final AtomicInteger idGenerator = new AtomicInteger(1000);
private Integer id;
private LocalDateTime localDateTime;
public Event(){
id = idGenerator.getAndIncrement();
}
// getters, setters omitted
}
Тест кода
public class Test {
public static void main(String[] args) {
for(int i = 0; i < 10; ++ i){
System.out.println(new Event().getId());
}
}
}
Выход
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
Прежде всего, переопределите методы equals() и hashcode() и напишите так:
@Override
public boolean equals(Object o){
if (o instanceof Event){
Event e = (Event) o;
return e.id.equals(this.id) && e.localDateTime.equals(this.localDateTime);
}
else return false;
}
@Override
public int hashCode(){
return Objects.hash(id,localDateTime); //this is the default implementation, up to you to implement it in a better way
}
Затем вы можете использовать такой поток, чтобы проверить наличие дубликатов:
public boolean checkAllUnique(Collection<Event> col){
return col.stream().allMatch(new HashSet<>()::add);
}
Вы правы, про актерский состав забыл, сейчас поправлю
Вы можете использовать два HashSet в качестве резервных коллекций для хранения уникальных элементов и перебирать список событий следующим образом:
public boolean duplicateExists(List<Event> eventList) {
Set<Integer> ids = new HashSet<>();
Set<LocalDateTime> localDateTimes = new HashSet<>();
return eventList.stream()
.anyMatch(event -> !ids.add(event.getId()) ||
!localDateTimes.add(event.getLocalDateTime()));
}
Поскольку Integer и LocalDateTime никогда не могут конфликтовать, здесь не нужны два HashSet, достаточно одного HashSet<Object>. Но я бы использовал петлю вместо Stream здесь.
Это класс Event, который вам понадобится;
class Event {
private Integer id;
private LocalDateTime localDateTime;
public Integer getId() {
return id;
}
public LocalDateTime getLocalDateTime() {
return localDateTime;
}
public void setId(Integer id) {
this.id = id;
}
public void setLocalDateTime(LocalDateTime localDateTime) {
this.localDateTime = localDateTime;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Event event = (Event) o;
return id.equals(event.id) &&
localDateTime.equals(event.localDateTime);
}
@Override
public int hashCode() {
return Objects.hash(id, localDateTime);
}
public static boolean hasDuplicates(List<Event> events) {
/*
return events
.stream()
.noneMatch(e -> events
.stream()
.filter(ev -> ev.equals(e)).count() > 1);
*/
return events.stream()
.distinct()
.count() != events.size(); // Kudos to @Holger for this approach.
}
}
Эта hasDuplicates является static функцией, поэтому она никак не повлияет на создание вашего объекта. Однако вы можете использовать его как вспомогательный метод для проверки дубликатов. Вам понадобится только одна строка проверки.
Большое спасибо, что нашли время для фрагмента. Я был немного незнаком с этим методом. Теперь, я думаю, у меня есть некоторое понимание того, как это работает.
Я думаю, у вас есть эта путаница из-за реализации .equals и .hashCode. Обратитесь к этому, чтобы иметь некоторое понимание -> journaldev.com/21095/java-equals-hashcode. Большинство основных реализаций Java основано на этих двух методах. Если вы переопределили эти два метода (переопределить обе функции являются обязательными, поэтому равенство — контракт хэш-кода), вы можете просто вызвать event1.equals(event2) для своих объектов. Поэтому здесь также работает функция containes().
Этот код ерунда. Вы просматриваете элементы в списке, чтобы убедиться, что ни один из этих элементов не содержится в этом списке, что является противоречием. Единственный раз, когда hasDuplicates вернет true, это когда ему дан пустой список.
Потоковая передача по List для повторной передачи по списку для каждого элемента приведет к ужасной производительности (также известной как квадратичная временная сложность). Почему вы не используете return events .stream() .distinct() .count() != events.size();?
@Holger, вау, это отличный подход. Это никогда не приходило мне в голову.
Как реализованы
equals()иhashCode()? Они полагаются исключительно на эти два свойства?