System.out.println() of Stream#reduce() unexpectedly prints “Optional[]” around result

蓝咒 提交于 2020-02-22 07:34:06

问题


I started to learn Lambda expressions of Java 8, and wrote below program to get sum of all numbers in the list:

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;
        }));
    }
}

I was expecting the output to be:

15

but I got:

Optional[15]

Java version: 1.8.0_45

  • Please explain what does Optional[] means in the output?
  • Does it has any significance in Java 8?

回答1:


From the Java Docs for Stream#reduce(), we see that the reduce operation returns an Optional<T>. An Optional simply wraps a value if there is a value present, otherwise is "empty".

Important operations on Optional include Optional#isPresent, which lets you know if there is something in the Optional or not, Optional#get, which returns the T wrapped in the Optional and throws an exception if called on Empty, and Optional#orElse which returns the T wrapped in the Optional if present, or the returns the default value provided if called on Empty.

For your case, the rationale behind reduce() returning an Optional<Integer> is that the list you're trying to reduce may be empty. In that case, the Integer that should be returned is not well defined. For your specific intention 0 would be acceptable (As the sum of the elements in an empty list is 0), thus you can get the sum as follows:

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

That way, even if the list is empty, you will still get a result that defines the sum of the list.




回答2:


reduce(BinaryOperator<T> accumulator):

Returns an Optional describing the result of the reduction

Optional:

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

The reason reduce() returns an Optional, is because the stream might be empty, in which case there would be nothing to reduce, aka no value, and an Optional.empty() would be returned.




回答3:


In order to avoid Optional in the return you can call to this other method https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#reduce-T-java.util.function.BinaryOperator- Just add the identity: "0" before adding the lambda expression. Note that now there is only a 0 as a fist parameter to the reduce call.

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

returns just

15



回答4:


Got it, thanks @Mshnik and @TimoSta. According to source code of Optional<> which overrides toString method

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

Above code adds that Optional[] in my output stream.




回答5:


From java.lang.Object.Optional:

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

Optional offers two different primary methods for retrieving its value.

public T get() simply returns the value enclosed in the Optional, but throws a NoSuchElementException if the Optional does not wrap a value.

orElse(T other) returns the value enclosed in the Optional or other if the Optional does not enclose a value.

EDIT (thanks @Brian Goetz): Generally, orElse() is a better choice since get() returns a NoSuchElementException if the Optional contains a null value. True, in this case you will always recieve a value in Optional but it's still good practice to primarily use orElse().

So, in your case, you would change

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

to:

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

which will return the desired value of 15.

And as @Brian Goetz said in the comments, if you really wanted to make it succinct you could use Integer::sum and a method reference:

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

which is equivalent to using the longer lambda.



来源:https://stackoverflow.com/questions/35384145/system-out-println-of-streamreduce-unexpectedly-prints-optional-around

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!