Reputation: 13
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
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
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
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