Stream#reduce()的System.out.println()意外地在结果周围打印“Optional []”

时间:2016-02-13 19:07:49

标签: java lambda java-8 stdout

我开始学习Java 8的Lambda表达式,并写下以下程序来获取列表中所有数字的总和:

import java.util.Arrays;
import java.util.List;

public class MainClass {

    public static void main(String[] args) {
        List<Integer> number = Arrays.asList(1, 2, 3, 4, 5);

        System.out.println(number.stream().reduce((c,e) -> {
            return c + e;
        }));
    }
}

我期待输出为:

  

15

但我得到了:

  

可选[15]

Java版本: 1.8.0_45

  • 请解释 Optional [] 在输出中的含义是什么?
  • 它在Java 8中有什么意义吗?

5 个答案:

答案 0 :(得分:4)

Java Docs for Stream#reduce(),我们看到reduce操作返回Optional<T>。如果存在值,Optional只会包装一个值,否则为“空”。

Optional上的重要操作包括Optional#isPresent,它可以让您知道可选中是否有Optional#get,其中包含可选项中包含的T如果在Empty上调用则抛出异常,Optional#orElse返回包含在Optional(如果存在)中的T,如果在Empty上调用则返回默认值。

对于您的情况,reduce()返回Optional<Integer>背后的理由是,您尝试减少的列表可能为空。在这种情况下,应该返回的Integer没有明确定义。对于您的具体意图,0是可以接受的(因为空列表中的元素总和为0),因此您可以得到如下总和:

int sum = number.stream().reduce((c,e) -> c + e).orElse(0);

这样,即使列表为空,您仍然会得到一个定义列表总和的结果。

答案 1 :(得分:3)

reduce(BinaryOperator<T> accumulator)

  

返回描述缩减结果的Optional

Optional

  

容器对象,可能包含也可能不包含非null值。如果存在值,isPresent()将返回trueget()将返回该值。

reduce()返回Optional的原因是因为流可能为空,在这种情况下没有任何内容可以减少,也就是没有值,并且会返回Optional.empty()

答案 2 :(得分:1)

为了避免返回中的Optional,您可以调用另一个方法https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#reduce-T-java.util.function.BinaryOperator-在添加lambda表达式之前添加标识:“0”。请注意,现在只有 0 作为reduce调用的第一个参数。

 System.out.println(number.stream().reduce(0,(c,e) -> {
            return c + e;
        }));

只返回

15

答案 3 :(得分:0)

来自java.lang.Object.Optional

  

容器对象,可能包含也可能不包含非null值。如果存在值,则isPresent()将返回true,get()将返回该值。

Optional提供两种不同的主要方法来检索其值。

public T get()只返回Optional中包含的值,但如果NoSuchElementException未包含值,则会抛出Optional

如果other未包含值,则

orElse(T other)会返回Optional或Optional中包含的值。

编辑(感谢@Brian Goetz): 通常,orElse()是更好的选择,因为如果get()包含空值,NoSuchElementException会返回Optional。是的,在这种情况下,您总是会在Optional中收到一个值,但主要使用orElse()仍然是一种好习惯。

所以,在你的情况下,你会改变

System.out.println(number.stream().reduce((c,e) -> {
        return c + e;
}));

为:

System.out.println(number.stream().reduce((c,e) -> {
        return c + e;
}).orElse(0));

将返回所需的15值。

正如@Brian Goetz在评论中所说,如果你真的想简明扼要,可以使用Integer::sum和方法参考:

System.out.println(number.stream.reduce(Integer::sum).orElse(0))

相当于使用较长的lambda。

答案 4 :(得分:0)

知道了,谢谢@Mshnik和@TimoSta。根据Optional&lt;&gt;的源代码覆盖toString方法

@Override
public String toString() {
    return value != null
        ? String.format("Optional[%s]", value)
        : "Optional.empty";
}

上面的代码在我的输出流中添加了Optional[]