Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Java's Optional doesn't call Consumer in ifPresent()?

public class TestSupplier {

Optional<Integer> opt1;

public static void main(String[] args) {
    // TODO Auto-generated method stub

    TestSupplier ts1 = new TestSupplier();

    ts1.opt1 = ts1.average(100,20,30,80);
    Consumer<Integer> cns1 = (x) -> x += 3;
    ts1.opt1.ifPresent(cns1);
    System.out.println(ts1.opt1.get());

}


private Optional<Integer> average(int... n1) {
    if (n1.length == 0) return Optional.empty();
    int sum = 0;
    for(int score: n1) sum += score; 
    return Optional.of(sum/n1.length);

}

}

when I run the code the result is 57 (that is the correct result of 100, 20, 30, 80 average) but I create a Consumer that should increment the result by 3... but it seems to not work.

Can someone help me?

like image 383
AleMal Avatar asked Nov 04 '16 09:11

AleMal


People also ask

How do I use optional ifPresent?

The ifPresent method of the Optional class is an instance method that performs an action if the class instance contains a value. This method takes in the Consumer interface's implementation whose accept method will be called with the value of the optional instance as the parameter to the accept method.

What is optional ofNullable?

What is the ofNullable() method of the Optional class? The ofNullable() method is used to get an instance of the Optional class with a specified value. If the value is null , then an empty Optional object is returned.

What is the use of optional class in Java?

Optional is a container object used to contain not-null objects. Optional object is used to represent null with absent value. This class has various utility methods to facilitate code to handle values as 'available' or 'not available' instead of checking null values.


Video Answer


2 Answers

The Consumer action is actually being run but the body you provided modifies only a local instance which eventually gets lost. The ifPresent() method should be used for performing side-effects(actions) only.

If you want to perform a calculation on a value held by an Optional instance, use map() instead.

ts1.opt1
  .map(x -> x + 3).orElseThrow(...)

Remember to be careful when using get() on an Optional instance. Before you decide to use it, have a look at orElse, orElseGet, and orElseThrow.

like image 190
Grzegorz Piwowarek Avatar answered Oct 31 '22 08:10

Grzegorz Piwowarek


Consumer<Integer> cns1 = new Consumer<Integer>() {
    public @Override void accept(Integer x) {
        // x is a local variable
        x += 3; // unboxing, adding, boxing 
        // the local variable has been changed
    }
};

It is that case when turning a lambda into an anonymous class perfectly makes this all clear to understand.

The best possible way here is

ts1.opt1.map(x -> x + 3).ifPresent(System.out::println);

You could use an instance of a mutable class (e.g. the AtomicInteger class):

Consumer<AtomicInteger> cns1 = x -> x.addAndGet(3);

which changes its state after accepting the Consumer<AtomicInteger> (although it is not recommended, look at @pivovarit's answer).

Furthermore, the line

IntStream.of(100, 20, 30, 80).average().ifPresent(System.out::println);

might replace all your routine work.

like image 34
Andrew Tobilko Avatar answered Oct 31 '22 07:10

Andrew Tobilko