Tom
Tom

Reputation: 13

Usage of Optional and Function

I am having troubles understanding the use of the Optional class in Java 8. I want to create an instance of a class (so I would use a Supplier) and then use .map() (so I need an Optional) to get another thing. My purpose is to write in a more “functional” way. For example, I have this code:

public class ParentClass {

    public static Supplier<Optional<Something>> createSomething = () -> {
        Something sth = new Something();
        sth.setAttribute(“value”);
        return Optional.of(sth);
    }

    public static Function<Optional<Something>, Optional<Something>> doSomething = var -> {
        Something sth = var.get();
        sth.setAnotherAttribute(“anotherValue”);
        return Optional.of(sth);
    }
}

And I would like to use it like this:

public class ChildClass extends ParentClass{

    public Optional<Something> method(){
        Optional<Something> sth = ParentClass.createSomething.get()
            .map(ParentClass::doSomething);
        return sth;

    }
}

There is an error:

The method map(ParentClass::doSomething) is undefined for the type Something

which I don’t understand why it happens. I tried removing the Optional wrapper but I still get the error message. Also tried writing the Function doSomething in the same ChildClass file but nothing happened. Can you see what I am doing wrong? Thank you

Upvotes: 0

Views: 163

Answers (3)

Michael Katt
Michael Katt

Reputation: 643

Your ParentClass does not contain any methods but two static field member and that is a little bit confusing.

For this you can not use doSomething by method reference. You have to call the doSomething.apply(Optional<Something>)

For this reason ChildClass has to look like

public class ChildClass extends ParentClass {

   public Optional<Something> method() {
      Optional<Something> sth = ParentClass.doSomething.apply(ParentClass.createSomething.get());
      return sth;
   }
}

SUPPLEMENT

According to your further question you could use this solution. It looks a little bit weird but works.

public class ParentClass {

    public static Optional<Something> createSomething() {
        Something something = new Something();
        something.setAttribute("value");
        return Optional.of(something);
    }

    public static Something doSomething(Something something) {
        something.setAnotherAttribute("anotherValue");
        return something;
    }

    public static Something doMoreSomething(Something something) {
        something.setAnotherAttribute("anotherValue");
        return something;
    }
}

ChildClass does not need to inherit from ParentClass, if you are using static methods.

public class ChildClass {

    public Optional<Something> method() {

        Optional<Something> something = ParentClass.createSomething().map(ParentClass::doSomething)
                .map(ParentClass::doMoreSomething);

        return something;
    }
}

Your doSomething methods have to use Something and not Optional<Something> because Optional.map uses the wrapped value of the Optional inside. If you have an empty Optional, map is not executed. Be aware the map could return other Optional than Optional<Something> according to the return of your doSomething method, but it will be an Optional.

SUPPLEMENT 2

Here ChildClass using Inheritance for ParentClass non-static methods.

public class ChildClass extends ParentClass {

    public Optional<Something> method() {

        Optional<Something> something = createSomething().map(this::doSomething).map(this::doMoreSomething);

        return something;
    }
}

Upvotes: 0

shmosel
shmosel

Reputation: 50716

As Luiggi points out, doSomething is already a Function; you don't need the method reference syntax. Also, map() expects a function on Something, not Optional<Something>. If you want to use a method reference, it would look like this:

public static Something doSomething(Something sth) {
    sth.setAnotherAttribute("anotherValue");
    return sth;
}

Upvotes: 1

Martin Dendis
Martin Dendis

Reputation: 623

Example usage of Optional::map

Map using lambda

class Test {
  private Function<Integer, String> convert = value -> value.toString();

  public static void main(String[] args) {
    var result = Optional.of(1).map(convert);
    // result now contains Optional with string "1"

    // Or alternatively
    var alternative = Optional.of(1).map(value -> value.toString());
  }
}

Map using method reference

class Test {
  public static String convert(Integer value) {
    return value.toString();
  }

  public static void main(String[] args) {
    var result = Optional.of(1).map(Test::convert);
    // result now contains Optional with string "1"

    // Or alternatively
    var alternative = Optional.of(1).map(Objects::toString);
  }
}

Notice that both lambda function and method are not consuming nor producing value wrapped in Optional.

Optional::map then works that way, that if value stored within Optional is not null then it will apply on it provided function and its result will wrap again to Optional which will return.

Upvotes: 0

Related Questions