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

问题描述 投票:0回答:3

将字符串拆分为流的最佳方法是什么?

我看到了这些变化:

  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");
    }

}
java regex split java-stream
3个回答
132
投票

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 表达式是什么中所述使用方法引用而不是 lambda 表达式会抛出 java.lang.NullPointerException


2
投票

稳健性

我认为这三种方法的稳健性没有差异。

可读性

我不知道有任何涉及经验丰富的 Java 程序员的关于代码可读性的可信科学研究,因此可读性是一个见仁见智的问题。即便如此,你永远不知道发表意见的人是否在实际可读性、他们所学到的可读性以及他们自己的个人品味之间做出了客观的区分。

因此,我将让您对可读性做出自己的判断...请注意,您确实认为这是一个高优先级。

FWIW,唯一对此事发表意见的人是你和你的团队。

性能

我认为答案是仔细对三种替代方案进行基准测试。 Holger 根据他对 Java 某些版本的研究提供了分析。但是:

  1. 他无法得出哪个最快的明确结论。
  2. 严格来说,他的分析仅适用于他所查看的 Java 版本。 (他的分析的某些方面可能在(例如)Android Java 或某些未来的 Oracle / OpenJDK 版本上有所不同。)
  3. 相对性能可能取决于被分割的字符串的长度、字段的数量以及分隔符正则表达式的复杂性。
  4. 在实际应用程序中,相对性能还可能取决于您对
    Stream
    对象执行的操作、您选择的垃圾收集器(因为不同版本显然会生成不同数量的垃圾)以及其他问题。

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


2
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.