如何将字符串拆分为字符串流?

什么是 最好的方法拆分一个字符串到一个流?

我看到了这些变化:

  1. Arrays.stream("b,l,a".split(","))
  2. Stream.of("b,l,a".split(","))
  3. 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");
}


}
76955 次浏览

关于(1)和(2)应该没有太大区别,因为您的代码几乎是相同的。
关于(3) ,它在内存方面(不一定是 CPU)更有效,但在我看来,有点难读。

Arrays.stream/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/String.split

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.splitAsStream

Pattern.compile(",").splitAsStream(string) 的优点是直接流而不是创建中间数组。因此,对于大量的子字符串,这可能有一个性能优势。另一方面,如果分隔符很简单,比如只有一个文本字符,那么 String.split实现将通过一个快速路径而不是使用正则表达式引擎。所以在这种情况下,答案并非微不足道。

Stream<String> stream = Pattern.compile(",").splitAsStream(input);

如果流发生在另一个流中,例如 .flatMap(Pattern.compile(pattern) ::splitAsStream),这样做的好处是只需要分析模式一次,而不是对外部流的每个字符串进行分析。

Stream<String> stream = Stream.of("a,b", "c,d,e", "f", "g,h,i,j")
.flatMap(Pattern.compile(",")::splitAsStream);

这是形式 expression::name的方法引用的一个属性,它将计算表达式并在创建函数接口的实例时捕获结果,如 System.out: : println 的等效 lambda 表达式是什么使用 method-reference 而不是 lambda 表达式抛出 java.lang. NullPointerException所解释的

稳健性

我看不出这三种方法的稳健性有什么不同。

可读性

我不知道有任何关于代码可读性的可靠的科学研究涉及到有经验的 Java 程序员,所以可读性是一个观点问题。即便如此,你也永远不会知道,有些人给出的意见是否客观地区分了实际的可读性、他们所学到的关于可读性的知识以及他们自己的个人品味。

所以我会留给你自己判断可读性... ... 注意到你确实认为这是一个高优先级。

FWIW,在这件事上唯一有意见的人是你和你的团队。

表演

我认为这个问题的答案是仔细衡量这三种选择。Holger 根据他对 Java 的一些版本的研究提供了一个分析。但是:

  1. 他无法得出一个最快的明确结论。
  2. 严格地说,他的分析只适用于他所研究的 Java 版本。(他分析 可以的某些方面在 Android Java 或某些未来的 Oracle/OpenJDK 版本上有所不同。)
  3. 相对性能可能取决于要拆分的字符串的长度、字段的数量以及分隔符 regex 的复杂性。
  4. 在实际的应用程序中,相对性能还可能取决于您如何处理 Stream对象、选择了哪个垃圾收集器(因为不同的版本显然会产生不同数量的垃圾)以及其他问题。

因此,如果您(或其他任何人)真正关心性能,那么您应该编写一个微基准,并在您的生产平台上运行它。然后进行一些特定于应用程序的基准测试。您应该考虑不涉及流的解决方案。