Как подсчитать количество слов и отфильтровать по длине
Что проверяют
Простую задачу дают, чтобы посмотреть на крайние случаи и на владение Stream API. Интервьюер ждёт встречных вопросов: что считать словом, как быть с пунктуацией, нужна ли частота каждого слова. Следом обычно просят посчитать повторы и вывести самые частые слова.
Как отвечать
Сначала уточните условия, потом пишите код. Разбиение text.split("\\s+") ломается в двух случаях: строка с ведущим пробелом даёт первым элементом пустую строку, а пустой ввод даёт массив из одного "", то есть «одно слово». Надёжнее делить по всему, что не буква и не цифра, и отбрасывать пустые куски:
- разбиение:
Pattern.compile("[^\\p{L}\\p{N}]+")иsplitAsStream(text), затем.filter(w -> !w.isEmpty()). Класс\\p{L}покрывает кириллицу, а\\wбез флагаUNICODE_CHARACTER_CLASSеё не видит; - нормализация:
toLowerCase(Locale.ROOT), чтобы «Слово» и «слово» считались одним словом; - количество:
.count()на потоке; - фильтр по длине:
.filter(w -> w.length() >= min). Уточните, что значит «длиннее N»:>или>=; - частоты:
Collectors.groupingBy(Function.identity(), Collectors.counting())даётMap<String, Long>, для топа сортируйте записи по значению; - результат:
Stream.toList()с Java 16 возвращает неизменяемый список, аCollectors.toList()изменяемость не гарантирует.
Назовите сложность: один проход, O(n) по длине текста, память под словарь уникальных слов. Большой файл читайте построчно через Files.lines() в try-with-resources, а не грузите целиком в одну строку.
Где спотыкаются
Не проверяют пустую строку и null. Метод на пустом вводе возвращает 1, и это всплывает на первом же тесте интервьюера.
Не знают, что length() считает UTF-16 единицы, а не символы. Для кириллицы разницы нет, но для эмодзи нужен codePointCount.
Вызывают String.split с регулярным выражением в цикле, и Pattern компилируется заново на каждой итерации. Вынесите его в статическое поле.