如何为每个循环使用Stream

时间:2017-04-28 10:26:52

标签: java lambda java-8 java-stream

我有一个更新String对象的循环:

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实现它?

3 个答案:

答案 0 :(得分:1)

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/,我认为这非常有用。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

一般情况下,您自己会考虑每个元素,除非您使用像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函数。减少更复杂。它可以被描述为积累。它在结果和当前元素之间执行一个函数。在这种情况下,它接受第一个元素,并将其连接到第二个元素。然后它采用第一个/第二个连接,并将相同的函数应用于第三个。等等。

您可以直接传递方法,而不是处理lambdas,以便稍微收紧一下代码:

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