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

Java 如何将字符串拆分为字符串流?,java,regex,split,java-stream,Java,Regex,Split,Java Stream,将字符串拆分为流的最佳方法是什么 我看到了这些变化: Arrays.stream(“b,l,a”.split(“,”) Stream.of(“b,l,a.”分割(“,”) Pattern.compile(“,”).splitAsStream(“b,l,a”) 我的优先事项是: 健壮性 可读性 演出 完整的、可编译的: 导入java.util.array; 导入java.util.regex.Pattern; 导入java.util.stream.stream; 公共类HelloWorld{

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

我看到了这些变化:

  • Arrays.stream(“b,l,a”.split(“,”)
  • Stream.of(“b,l,a.”分割(“,”)
  • Pattern.compile(“,”).splitAsStream(“b,l,a”)
  • 我的优先事项是:

    • 健壮性
    • 可读性
    • 演出
    完整的、可编译的:

    导入java.util.array;
    导入java.util.regex.Pattern;
    导入java.util.stream.stream;
    公共类HelloWorld{
    公共静态void main(字符串[]args){
    stream1().forEach(System.out::println);
    stream2().forEach(System.out::println);
    stream3().forEach(System.out::println);
    }
    私有静态流stream1(){
    返回Arrays.stream(“b,l,a”.split(“,”);
    }
    私有静态流stream2(){
    返回流。of(“b,l,a”。拆分(“,”);
    }
    私有静态流stream3(){
    返回模式.compile(“,”).splitAsStream(“b,l,a”);
    }
    }
    
    关于(1)和(2)应该没有太大区别,因为您的代码几乎相同。
    关于(3),就内存而言(不一定是CPU),这将更有效,但在我看来,更难阅读。

    Arrays.stream
    /
    String.split
    由于返回数组
    String[]
    ,因此我始终建议将
    Arrays.stream
    作为通过数组进行流式处理的标准用法

    String input = "dog,cat,bird";
    Stream<String> stream = Arrays.stream(input.split( "," ));
    stream.forEach(System.out::println);
    
    Pattern.splitAsStream
    具有直接流式传输而不是创建中间阵列的优势。因此,对于大量的子字符串,这会带来性能上的好处。另一方面,如果分隔符很简单,即单个文字字符,
    String.split
    实现将通过一条快速路径,而不是使用正则表达式引擎。因此,在这种情况下,答案并非微不足道

    Stream<String> stream = Pattern.compile(",").splitAsStream(input);
    
    这是
    expression::name
    形式的方法引用的属性,它将在创建函数接口实例时计算表达式并捕获结果,如和中所述

    健壮性

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

    可读性

    我不知道有经验的Java程序员对代码可读性进行过任何可信的科学研究,所以可读性是一个意见问题。即便如此,你也永远不知道,如果有人给出自己的观点,是否在实际可读性、他们所学的可读性以及他们自己的品味之间做出了客观的区分

    所以我会让你自己对可读性做出判断。。。注意到你认为这是一个高优先级。

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

    演出

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

  • 他无法得出一个确定的结论,哪一个是最快的
  • 严格地说,他的分析只适用于他所研究的Java版本。(他的分析的某些方面可能在Android Java或未来的Oracle/OpenJDK版本上有所不同。)
  • 相对性能可能取决于被拆分字符串的长度、字段的数量以及分隔符正则表达式的复杂性
  • 在实际应用程序中,相对性能还可能取决于您对
    对象所做的操作、您选择的垃圾收集器(因为不同版本显然会产生不同数量的垃圾)以及其他问题

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

    你认为有这么大的差别,花时间去琢磨“最好”的方法是有意义的,或者你认为这是你的程序中的一个性能热点,使它至少有点合理,试图找到“最好的”。方法?请注意,
    Stream.of()
    将在内部调用
    Arrays.Stream()
    ,显然这不是“最好的”。嗯,最后一个才是最好的。没有嵌套的paren,很明显它是关于regex的,并且它不会创建所有段的中间列表或数组。但那只是我的意见.我认为我们不能特别判断他想知道这些信息的理由。虽然“最好”是一种观点,但你的意思是“最快”吗?@Prospero OP清楚地阐明了他所追求的:健壮性、可读性和性能。
    .flatMap(Pattern.compile(Pattern)
    为什么模式只需分析一次?是否存在缓存?如果是,这是否写在文档中的某个地方?@Roland:这是
    表达式::名称形式的方法引用的一个属性,表达式将被计算,并由创建的函数实例捕获结果。使用
    模式.compile(模式)::splitAsStream
    ,表达式是
    Pattern.compile(Pattern)
    。这与Pattern.compile(Pattern)根本不同。splitAsStream(string)
    将在每次函数求值时重新计算模式。请参见和…@Benj问题是它甚至调用了
    子序列(…).toString()
    ,因此使用不同的
    CharSequence
    实现(即非复制)只会将复制推迟到后续的
    toString()
    调用。但对于标记化,您更希望使用Java 9的
    Matcher.results()
    Scanner.findAll(…)无论如何,请考虑后备。因为<代码> MatcRESULTS/<代码>提供<代码>开始()(代码)>和<代码>结束()/代码>,您可以在ApOP的基础上构建无拷贝操作。
    
    Stream<String> stream = Stream.of(input.split(","));     // works, but is non-idiomatic
    Stream<String> stream = Stream.of("dog", "cat", "bird"); // intended use case
    
    Stream<String> stream = Pattern.compile(",").splitAsStream(input);
    
    Stream<String> stream = Stream.of("a,b", "c,d,e", "f", "g,h,i,j")
        .flatMap(Pattern.compile(",")::splitAsStream);