我开始学习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
答案 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
容器对象,可能包含也可能不包含非null值。如果存在值,
isPresent()
将返回true
,get()
将返回该值。
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)
容器对象,可能包含也可能不包含非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[]
。