yangxu998 / guava-libraries

Automatically exported from code.google.com/p/guava-libraries
Apache License 2.0
0 stars 0 forks source link

Optional.or(Supplier) #671

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
While the idea of both `Optional` itself as well as `.or(defaultValue)` are 
nice, I find it quite common that the default value requires at least a little 
assembly. However, as long as no default value is required, I'd like to avoid 
its creation (as it might involve database access or anything else that's 
costly).

Thus, I suggest the introduction of a way to create such a fallback value 
lazily. Using a function comes to mind:

  public String getUsername(final int userId) {
    Optional<User> optUser = userService.findUser(userId);
    return optUser.or(new Function<Object, String>() {
      public String apply(Object obj) {
        return "[unknown user #" + userId + ']';
      }
    });
  }

Of course, without anonymous first-class functions, this is the usual Java PITA 
- but at least it's lazy.

As a final value from the enclosing scope is used instead of a parameter and a 
placeholder would have to be passed to call it, the `Function` interface seems 
not too appropriate here. `Callable` and `Supplier` might fit technically, but 
have questionable semantics for this case.

Another approach could be to pass the input argument for the function 
separately and thus use it as intended:

  public String getUsername(int userId) {
    Optional<User> optUser = userService.findUser(userId);
    return optUser.or(new Function<Integer, String>() {
      public String apply(Integer userId) {
        return "[unknown user #" + userId + ']';
      }
    }, userId);
  }

Or, for more complicated cases (I don't like it, due to arrays and lost type 
safety, but for the sake of completeness), this could be done using varargs:

  public String getUsername(int userId) {
    Optional<User> optUser = userService.findUser(userId);
    return optUser.or(new Function<Integer, String>() {
      public String apply(Object[] args) {
        return "[unknown user #" + args[0] + "] (last checked at " + args[1] + ')';
      }
    }, userId, new Date());
  }

Any ideas?

Original issue reported on code.google.com by j...@nwsnet.de on 27 Jul 2011 at 11:19

GoogleCodeExporter commented 9 years ago
I don't think the semantics of Supplier would be questionable at all here. What 
you want is something that has the ability to supply a value to return if 
necessary. Function doesn't make sense given that there's nothing that the 
Optional itself can provide as the input. For example, all of your examples 
would be well served by a supplier that does message formatting:

  return optUser.or(new MessageFormattingSupplier("[unknown user #{0}] (last checked at {1})", userId, new Date()));

It would even be possible to create a Supplier<T> that takes a Function<F, T> 
and an input F if you really wanted.

All that said, I imagine this falls in with filter/transform methods for 
Optionals which have been avoided so far, probably because of the difficulties 
associated with functional stuff in Java. If it were just a matter of putting 
{} around the argument expression it would be an obvious win.

Original comment by cgdec...@gmail.com on 27 Jul 2011 at 12:15

GoogleCodeExporter commented 9 years ago
It does seem logically consistent with the two or overloads we already have.

Original comment by fry@google.com on 28 Jul 2011 at 5:38

GoogleCodeExporter commented 9 years ago

Original comment by kurt.kluever on 29 Jul 2011 at 9:15

GoogleCodeExporter commented 9 years ago

Original comment by cpov...@google.com on 1 Sep 2011 at 9:22

GoogleCodeExporter commented 9 years ago
This issue has been migrated to GitHub.

It can be found at https://github.com/google/guava/issues/<id>

Original comment by cgdecker@google.com on 1 Nov 2014 at 4:15

GoogleCodeExporter commented 9 years ago

Original comment by cgdecker@google.com on 3 Nov 2014 at 9:09