Как разбить строку на поток строк?
Что такое лучший метод разделения строки на поток?
Я видел эти варианты:
-
Arrays.stream("b,l,a".split(","))
-
Stream.of("b,l,a".split(","))
-
Pattern.compile(",").splitAsStream("b,l,a")
Мои приоритеты:
- Надёжность
- читабельность
- Производительность
Полный, компилируемый пример:
import java.util.Arrays;
import java.util.regex.Pattern;
import java.util.stream.Stream;
public class HelloWorld {
public static void main(String[] args) {
stream1().forEach(System.out::println);
stream2().forEach(System.out::println);
stream3().forEach(System.out::println);
}
private static Stream<String> stream1() {
return Arrays.stream("b,l,a".split(","));
}
private static Stream<String> stream2() {
return Stream.of("b,l,a".split(","));
}
private static Stream<String> stream3() {
return Pattern.compile(",").splitAsStream("b,l,a");
}
}
Ответы
Ответ 1
String.split
Ну, поскольку String.split
возвращает массив String[]
, я всегда рекомендую Arrays.stream
в качестве канонической идиомы для потоковой передачи по массиву.
String input = "dog,cat,bird";
Stream< String > stream = Arrays.stream( input.split( "," ) );
stream.forEach( System.out :: println );
Stream.of
Stream.of
- это метод varargs, который просто принимает массив, из-за того, что методы varargs реализованы через массивы, и были проблемы с совместимостью, когда varargs были введены в Java и существующие методы были модифицированы для приема переменных аргументов.
Stream< String > stream = Stream.of( input.split( "," ) ); // works, but is non-idiomatic
Stream< String > stream = Stream.of( "dog", "cat", "bird" ); // intended use case
Pattern.compile
Pattern.compile(",").splitAsStream(string)
имеет преимущество прямой потоковой передачи, а не создания промежуточного массива. Таким образом, для большого количества подстрок это может иметь преимущество в производительности. С другой стороны, если разделитель является тривиальным, то есть одним литеральным символом, реализация String.split
пройдет быстрый путь вместо использования механизма регулярных выражений. Так что в этом случае ответ не тривиален.
Если потоковая передача происходит внутри другого потока, например, .flatMap(Pattern.compile(pattern) ::splitAsStream)
есть преимущество в том, что шаблон должен анализироваться только один раз, а не для каждой строки внешнего потока.
Stream< String > stream = Pattern.compile( "," ).splitAsStream( input );
Ответ 2
Относительно (1) и (2) не должно быть большой разницы, так как ваш код почти одинаковый.
Что касается (3), это было бы гораздо более эффективным в плане использования памяти (не обязательно CPU), но, на мой взгляд, немного сложнее читать.
Ответ 3
Надёжность
Я не вижу разницы в надежности трех подходов.
Читаемость
Мне не известны какие-либо заслуживающие доверия научные исследования в области читабельности кода с участием опытных программистов на Java, поэтому читаемость - это вопрос мнения. Даже тогда вы никогда не узнаете, проводит ли кто-то, высказывающий свое мнение, объективное различие между фактической читаемостью, тем, чему его учили о читабельности, и собственным вкусом.
Поэтому я оставлю вам право самостоятельно оценивать удобочитаемость... отмечая, что вы считаете это высоким приоритетом.
FWIW, единственные люди, чье мнение по этому вопросу, это вы и ваша команда.
Производительность
Я думаю, что ответом на это является тщательный сравнительный анализ трех альтернатив. Хольгер дает анализ, основанный на его изучении некоторых версий Java. Но:
- Он не смог прийти к определенному выводу, который был самым быстрым.
- Строго говоря, его анализ относится только к тем версиям Java, на которые он смотрел. (Некоторые аспекты его анализа могут отличаться в (скажем) Android Java или в некоторых будущих версиях Oracle/OpenJDK.)
- Относительная производительность, скорее всего, зависит от длины разделяемой строки, количества полей и сложности регулярного выражения разделителя.
- В реальном приложении относительная производительность также может зависеть от того, что вы делаете с объектом
Stream
, какой сборщик мусора вы выбрали (поскольку разные версии, по-видимому, генерируют различное количество мусора) и другие проблемы.
Поэтому, если вы (или кто-то еще) действительно обеспокоены производительностью, вы должны написать микро-тест и запустить его на своей производственной платформе (-ах). Затем сделайте некоторые тесты для конкретного приложения. И вы должны рассмотреть возможность поиска решений, которые не включают потоки.