Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unwrapping a Guava Optional in a single expression

Tags:

java

guava

As a Scala developer who also works in GWT, I welcome the addition of Optional to Guava.

One of our most common use cases of Optional is when returning optional values from methods (as suggested by the answer to What's the point of Guava's Optional class.

In scala, I often write code like this:

def someExpensiveOperation(params: Type): Option[ResultType] = ...
someExpensiveOperation(params).foreach({ val =>
  doSomethingWithVal (val)
})

Guava's Option does not seem to allow anything more elegant than something like this:

Optional<MyType> optionalResponse = someExpensiveOperation(params);
if (optionalResponse.isPresent()) {
    doSomethingWithVal(optionalResponse.get())
}

The local variable is redundant, and it requires repeating a pattern which could be abstracted (the if (optional.isPresent()) { doSomethingWith(optional.get()) } ).

The other option would be to call the method which returns an Optional twice:

if (someExpensiveOperation(params).isPresent()) {
    doSomethingWithVal(someExpensiveOperation(params).get())
}

But that is clearly undesirable, since it invoked an expensive operation multiple times unnecessarily.

I'm curious how other people have handled this very-common case (perhaps by writing a static utility method like <T>useIfPresent(Optional<T> val, Closure<? super T> closure)?) or if anyone has found more elegant solutions.

Also, if anyone knows why a method like Optional.foreach(Closure<? super T> closure) (but hopefully better named) was omitted, I would be curious to hear the rationale.

like image 586
Yona Appletree Avatar asked Dec 08 '12 01:12

Yona Appletree


1 Answers

It's not there because we feel the anonymous class awkwardness of writing a Closure is more awkward and less readable -- at least in Java, not necessarily in Scala -- than the local variable and the if statement that you've already written.

That said, another alternative is

for (Foo x : someExpensiveOperation().asSet()) {
  // do stuff with x
}

Note that asSet is necessary here -- Optional very deliberately does not itself implement Iterable.

like image 116
Louis Wasserman Avatar answered Nov 02 '22 21:11

Louis Wasserman