使用Java流上的筛选操作的结果调用函数的最佳方法是什么

使用Java流上的筛选操作的结果调用函数的最佳方法是什么,java,lambda,java-8,java-stream,Java,Lambda,Java 8,Java Stream,我想知道最好的方法是使用新的Java8流API读取文件,通过模式匹配过滤输入流,然后将结果传递给使用匹配中的组的函数。我认为这是不可能的,因为流操作是无状态的,模式匹配器中的组无法传递到流处理器中的下一步 那么,假设我有这个 stream.filter->pattern.matcher.matches()) 是否可以将调用添加到从matches()中获取s或(最好是)组的函数中?差不多 stream.filter->pattern.matcher.matches()).ifTrue->myfun

我想知道最好的方法是使用新的Java8流API读取文件,通过模式匹配过滤输入流,然后将结果传递给使用匹配中的组的函数。我认为这是不可能的,因为流操作是无状态的,模式匹配器中的组无法传递到流处理器中的下一步

那么,假设我有这个

stream.filter->pattern.matcher.matches())

是否可以将调用添加到从matches()中获取s或(最好是)组的函数中?差不多

stream.filter->pattern.matcher.matches()).ifTrue->myfunc

我基本上希望避免将所有匹配项收集到内存中的数据结构,因为我不知道流有多大。假设我有一个巨大的文件,我想构造并序列化一个封装模式匹配器组的对象。我不想在一个数据结构中保存所有匹配项并进行必要的处理,那么对文件进行操作的最佳方式是什么,这样我就可以处理一行并限制内存消耗,同时也允许并行处理文件

对这些行进行迭代并一次一个地处理是否更好?这是否等同于流上forEach()的终端操作?在我的用例中,我可能不关心不能对终端操作进行并行化的副作用,但我很好奇forEach在并行处理过程中出现问题的一般情况

谢谢。

你可以在溪流边

返回一个由该流的元素组成的流,在从结果流中消耗元素时,对每个元素执行提供的操作

这是一个中间操作

流是完整的,但您可以使用lambda表达式(a
使用者
)执行操作


你的要求有点奇怪。如果调用
matches
则意味着整个
字符串都匹配,因此元素就是匹配项

在流上请求
.ifTrue(s->myfunc(s))
方法是没有意义的,事实上,它让我想知道
过滤器的作用。如果在
筛选
之后链接一个操作,它将仅应用于匹配项,因为这是
筛选
的目的

stream.filter(s -> pattern.matcher(s).matches()).peek(s -> myfunc(s))
因此
stream.filter->pattern.matcher.matches()).forEach(s->myfunc(s))
是该作业的正确工具,它既不意味着数据收集,也不意味着多线程问题。如果函数
myfunc
本身没有线程问题,
filter(…).forEach(…)
可以并行运行而不会出现问题


值得注意的是,
模式
有一个方法。它使用
find
而不是
matches
,但这可以通过向模式添加锚来解决:

Stream.of("a", "b", "ab", "bb", "aaa", "bab")
      .filter(Pattern.compile("^a*$").asPredicate())
      .forEach(System.out::println);
将打印

a
aaa
并且将与
并行
一起工作(只有顺序可能会更改)


如果您确实需要
匹配器的状态,则必须提供选项

  • 首先创建
    匹配器
    ,然后应用
    过滤器

    Pattern p=Pattern.compile("b(a+)b");
    Stream.of("a", "b", "bab", "bb", "aa", "baaab")//.parallel()
          .map(p::matcher)
          .filter(Matcher::matches)
          .mapToInt(m->m.end(1)-m.start(1))
          .forEach(System.out::println);
    
  • 使用
    flatMap
    并用结果
    Stream

    Pattern p=Pattern.compile("b(a+)b");
    Stream.of("a", "b", "bab", "bb", "aa", "baaab")//.parallel()
          .flatMap(s-> { Matcher m=p.matcher(s);
              return m.matches()? Stream.of(m.group(1)): Stream.empty(); })
          .mapToInt(String::length)
          .forEach(System.out::println);
    

  • 两者都将打印
    1
    3
    ,并且对
    并行执行是安全的;将
    forEach
    与并行流一起使用可能会改变顺序,仅此而已。如果您对源订单感兴趣,可以使用。

    将已接受的答案更改为该答案,因为我觉得它更准确地讨论了与当前问题相关的流的行为。事实上,我确实使用了forEach()而不是peek(),因为我需要一个终端操作来强制处理文件。我所寻找的是一种处理无限文件流的方法,而使用流API是不可能的。我最终选择了commons io Tailer库,因为它提供了我想要的行为,即处理每一行并执行一个处理程序来处理它。同时,我希望在将新行写入文件时保持管道打开以处理新行。