I came across the below code:
public void method(MyObject obj) {
String value = Optional.ofNullable(obj)
.map(x -> obj.doSomething())
.orElse(MyObject.DEFAULT_VALUE);
}
I am curious to know the usage of x -> obj.doSomething()
instead of x -> x.doSomething()
in map
method.
Here even if obj
is null
, a NullPointerException
would NOT be thrown because we are invoking the ofNullable
method before the map
and hence the mapping function would be invoked only when obj
is not null.
So in terms of the results, both x -> obj.doSomething()
or x -> x.doSomething()
would be equivalent in the case of Optional
. (Obviously the result would be different in case of a Stream
or when using Optional.of
).
Are there any other differences? And in terms of usage, I think x -> x.doSomething()
should be preferred rather than using the actual object itself.
This is probably a mistake/not intended and doing something like that can cause issues during refactoring. When you see something like that, you should probably replace it with something using the lambda parameter (or a method reference).
For example, you could decide you want to perform some transformations returning a different object before:
String value = Optional.ofNullable(obj)
.map(x -> createOtherObjectOfSameTypeForFurtherProcessing(x))
.map(x -> obj.doSomething())
.orElse(MyObject.DEFAULT_VALUE);
In this case, obj.doSomething()
will still operate on the old object.
Alternatively, if obj
is actually a field and not a parameter or local variable like in your example (thanks to user85421 in the comments for pointing out this isn't the case in this example), it would be possible that obj
is modified before the map
call:
//WARNING: questionable code
String value = Optional.ofNullable(obj)
.filter(x -> {
obj = null;//weird stuff done here, probably better don't do that in production
return true;
})
.map(x -> obj.doSomething())
.orElse(MyObject.DEFAULT_VALUE);
Something like that could also happen to another thread (which can (not always) be reasonable if obj
is e.g. immutable and volatile
)
And as obj
is a parameter in your example, you can also not use your code if obj
was modified at some point (as also pointed out by this comment), your code wouldn't compile.
//DOES NOT COMPILE
public void method(MyObject obj) {
if(someEdgeCase()){
obj = null;//makes obj not effectively final
}
String value = Optional.ofNullable(obj)
.map(x -> obj.doSomething())//compiler error because obj is not effectively final
.orElse(MyObject.DEFAULT_VALUE);
}