7

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.

Community
  • 1
  • 1
Yona Appletree
  • 8,801
  • 6
  • 35
  • 52

1 Answers1

8

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.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • 2
    A little OT, but I'm wondering why `Optional.asSet()` returns `Set` instead of `ImmutableSet` since it's documented to return immutable one. Is it because `Optional` is shipped in `c.g.c.base` and not in `c.g.c.collect`? – Grzegorz Rożniecki Dec 08 '12 at 12:59
  • 1
    That's exactly it. (Google's build system more or less forbids cyclic package dependencies.) – Louis Wasserman Dec 08 '12 at 18:20
  • That's perfectly reasonable. I often struggle with the inherent conflict between doing things in what feels like a clean functional way, and Java's lack of closures. That being said, I use IntelliJ which automatically collapses anonymous inner classes into the JDK 8-style closure syntax. Along those lines, are there plans to revisit anonymous-class-verbosity-based design decisions when Java 8 is closer to shipping? – Yona Appletree Dec 11 '12 at 01:49
  • Revisit? Perhaps. Google is still in the process of moving to JDK7, let alone 8; we have many users who will be on JDK 5 for the forseeable future. We'll see what happens. – Louis Wasserman Dec 11 '12 at 02:08
  • JDK 5? That's too bad. Guava's tagline is "Guava: Google Core Libraries for Java 1.6+" :) – Piotr Findeisen Dec 16 '12 at 22:30
  • We maintain a separate backport for JDK5 users nowadays. (But e.g. many of our users are Android apps which need Froyo compatibility, which is comparable to JDK5.) – Louis Wasserman Dec 16 '12 at 22:31