0

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.

5
  • if objis null, then obj.doSomething() will throw a NPE. We should use x -> x.doSomething() or, even better, use a method reference: ...map(MyObject::doSomething).... Commented Jun 26, 2024 at 12:47
  • 1
    @Turing85 it isn't throwing an NPE, that is what surprised me Commented Jun 26, 2024 at 12:50
  • 1
    using obj is slightly larger than using x Commented Jun 26, 2024 at 12:53
  • 2
    Nah, wouldn't get an NPE as the map is only invoked on obj is non null. As you suggest, the lambda is weird - x -> x.doSomething() makes more sense. Commented Jun 26, 2024 at 12:53
  • 3
    One creates a closure, the other doesn't. Best to use a method reference. And bestest to not use Optionals for flow control at all. Optionals should be reserved for return values of methods to signal the absence of a value. Commented Jun 26, 2024 at 12:54

1 Answer 1

4

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

}
Sign up to request clarification or add additional context in comments.

8 Comments

but obj must be final or effectively final - it cannot be changed before the map call
@user85421 Did anyone say it would be a local variable? I didn't see anything about that.
public void method(MyObject obj) { ...
Good catch. I've edited my answer.
@rzwitserloot What about "Code smell"?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.