Как сделать уникальный список тегов по именам и исключить дубли
Что проверяют
Умеете ли вы выбрать коллекцию под задачу и понимаете ли, как Java определяет «одинаковость». Уточнение почти всегда такое: а если теги это объекты, и дублем считаются теги с одинаковым именем, но разными id?
Как отвечать
Для списка строк достаточно Set, но выбор реализации важен:
LinkedHashSet: убирает дубли и сохраняет порядок первого появления, обычно ждут именно этого:new ArrayList<>(new LinkedHashSet<>(tags));HashSet: быстрее на миллионах элементов, но порядок не гарантирован;TreeSet: сортирует, а сString.CASE_INSENSITIVE_ORDERзаодно склеит «Java» и «java»;- Stream API:
tags.stream().distinct().toList().distinct()опирается наequalsиhashCodeи на упорядоченном потоке оставляет первое вхождение, аtoList()с Java 16 возвращает неизменяемый список.
Для объектов по имени:
List<Tag> unique = tags.stream()
.collect(Collectors.toMap(
t -> t.name().trim().toLowerCase(Locale.ROOT),
Function.identity(),
(first, second) -> first,
LinkedHashMap::new))
.values().stream().toList();Функция слияния решает, какой из дублей оставить, а LinkedHashMap сохраняет порядок. Если имя и есть идентичность тега, честнее переопределить equals и hashCode по имени, и тогда подойдёт обычный distinct(). Сложность у хэш-решений линейная, у TreeSet O(n log n).
Скажите и про нормализацию: пробелы по краям, регистр, Locale.ROOT в toLowerCase, иначе на турецкой локали «I» превращается в «ı».
Где спотыкаются
Берут HashSet и удивляются, что порядок тегов в интерфейсе не совпадает с исходным и может поменяться после добавления новых элементов.
Вызывают distinct() на объектах без переопределённых equals и hashCode. Сравниваются ссылки, и ни один дубль не уходит.
Пишут Collectors.toMap без функции слияния. На первом же повторяющемся имени летит IllegalStateException.