Как удалить пустые строки из стрима после разделения по регулярному выражению в Java
Что проверяют
Знаете ли вы тонкости String.split и Stream API, а не только базовый filter. Следом просят заодно убрать строки из одних пробелов или спрашивают, откуда в результате взялся пустой первый элемент.
Как отвечать
Базовое решение:
List<String> parts = Arrays.stream(input.split("\\R"))
.filter(Predicate.not(String::isBlank))
.toList();Дальше разберите детали:
- поведение
split: с лимитом по умолчанию он отбрасывает пустые строки только в конце. Пустые в начале и в середине остаются:" a b".split("\\s+")вернёт массив с пустым первым элементом.split(regex, -1)сохраняет вообще всё; isEmptyиisBlank:isEmpty()ловит только строку нулевой длины,isBlank()(Java 11) ещё и строку из пробелов.trim()режет лишь символы доU+0020, аisBlank()иstrip()понимают юникодные пробелы;\\R: в регулярке означает любой перевод строки. С\\nу строк из Windows-файлов в конце останется\r, и они перестанут быть пустыми дляisEmpty;Pattern.splitAsStream:Pattern.compile("\\R").splitAsStream(input)сразу даёт стрим без промежуточного массива, а скомпилированныйPatternможно хранить вstatic finalи не компилировать заново на каждом вызове;String.lines(): для разбиения именно по переводам строки есть готовый метод (Java 11), он понимает\n,\r\nи\r;toList(): с Java 16 возвращает неизменяемый список.Collectors.toList()на практике отдаётArrayList, но спецификация изменяемость не гарантирует.
Где спотыкаются
Считают, что split сам удаляет все пустые элементы. На тестовой строке с пустыми строками в конце всё выглядит чисто, а на входе с разделителем в начале пустой элемент остаётся.
Забывают, что аргумент split это регулярное выражение. split(".") вернёт пустой массив, split("|") разобьёт строку по символам. Спецсимволы экранируют или оборачивают в Pattern.quote.
Пытаются добавить элемент в список после .toList() и ловят UnsupportedOperationException.