【问题标题】:How to use Stream instead for each loop如何为每个循环使用 Stream
【发布时间】:2017-04-28 10:26:51
【问题描述】:

我有一个更新字符串对象的循环:

String result = "";
for (SomeObject obj: someObjectList) {
    result = someMetohd(obj, result);
}

someMethod 的实现是无关紧要的:

private String someMethod(SomeObject obj, String result) {
    result = result.concat(obj.toString());
    return result;
}

我想使用 Stream 而不是循环。如何用 Stream 实现?

【问题讨论】:

  • 为什么您认为基于流的实现会更好?
  • 我只想知道流
  • 然后阅读tutorial
  • @Jorn Vernee:在这里没有帮助,因为someMethod 不是关联的。如果操作确实是concat,它会,但这只是一个例子……

标签: java lambda java-8 java-stream


【解决方案1】:
@SuppressWarnings("OptionalGetWithoutIsPresent")
String result = Stream.concat(Stream.of(""), someObjectList.stream())
        .reduce(this::someMethod)
        .get();
  • 您的 someMethod 应该是文档中指定的关联,但这仅对并行流很重要,而您的代码是显式顺序的
  • 由于您总是添加到 result,您可以将其视为流的第一个元素,然后使用 reduce 方法,该方法将始终合并前两个元素 - 当前结果和下一个元素
  • result 必须是someMethod 的第一个参数
  • 因为流中的所有元素都必须是同一类型,而您有 String resultSomeObject 元素,您需要更改 someMethod 的签名以接受两个 Objects(并执行在方法内部强制转换):private String someMethod(Object result, Object obj)。这是此解决方案中最丑陋的部分。
  • 您可以内联结果的初始值 - 无需预先定义result
  • 您可能希望根据声明此方法的位置更改 this::someMethod
  • 最后,您不必担心处理Optional 结果,因为流总是至少有一个元素,所以调用get() 是安全的

【讨论】:

    【解决方案2】:
    final StringBuilder resultBuilder = new StringBuilder();
    
    someObjectList.stream().map(SomeObject::toString).forEach(resultBuilder::append);
    
    final String result = resultBuilder.toString();
    

    想了解更多关于Streams的信息,可以查看这个页面:http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/,我觉得很有帮助。

    【讨论】:

      【解决方案3】:

      尽管您在此处尝试实现的功能等效可以通过流实现,但值得提醒您的是,功能和迭代的思维方式不一定兼容。

      通常您会单独考虑每个元素,并且您无法看到其他元素,除非您使用的是 reduce 等特殊功能。

      这里的东西可以满足您的要求:

        final List<Object> objectList = Arrays.asList("a", "b", "c", "d");
      
        String concatString = objectList.stream()
                  .map(e -> e.toString())
                  .reduce((result, element) -> result.concat(e))
                  .get();
      

      Map 将整个流转换为一个列表,但对每个元素单独调用 toString 函数。减少更复杂。可以用积累来形容。它在结果和当前元素之间执行一个函数。在这种情况下,它采用第一个元素,并将其连接到第二个元素。然后它采用第一个/第二个连接,并将相同的功能应用于第三个。以此类推。

      除了处理 lambda,您还可以直接传入方法,以稍微收紧您的代码:

      String result = objectList.stream()
                          .map(Object::toString)
                          .reduce(String::concat)
                          .get();
      

      【讨论】:

        猜你喜欢
        • 2021-12-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-11
        • 1970-01-01
        • 1970-01-01
        • 2020-04-05
        • 2021-11-30
        相关资源
        最近更新 更多