В Java 8 как я могу отфильтровать коллекцию с помощью Stream API, проверяя четкость свойства каждого объекта?
Например, у меня есть список Person объектов, и я хочу удалить людей с одинаковыми именами,
persons.stream().distinct();
Будет использоваться проверка равенства по умолчанию для Person объекта, поэтому мне нужно что-то вроде,
persons.stream().distinct(p -> p.getName());
К сожалению, distinct() метод не имеет такой перегрузки. Можно ли сделать это кратко, не изменяя проверку на равенство внутри Person класса?
Переведено автоматически
Ответ 1
Считайте, что distinct это фильтр с отслеживанием состояния. Вот функция, которая возвращает предикат, который поддерживает состояние относительно того, что он видел ранее, и которая возвращает, был ли данный элемент замечен впервые:
publicstatic <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) { Set<Object> seen = ConcurrentHashMap.newKeySet(); return t -> seen.add(keyExtractor.apply(t)); }
Обратите внимание, что если поток упорядочен и выполняется параллельно, это сохранит произвольный элемент из числа дубликатов, а не первый, как это происходит distinct().
Альтернативой было бы разместить людей на карте, используя имя в качестве ключа:
persons.collect(Collectors.toMap(Person::getName, p -> p, (p, q) -> p)).values();
Обратите внимание, что Person которое сохраняется, в случае повторяющегося имени, будет первым встреченным.
Ответ 3
Вы можете обернуть объекты person в другой класс, который сравнивает только имена персон. После этого вы разворачиваете обернутые объекты, чтобы снова получить поток person. Потоковые операции могут выглядеть следующим образом: