0

I encounter a specific use case where I often need to wrap objects in Optional if they are empty. Take a look at this code:

List<AbstractCorporateAction> cas = stream.toList();
if (cas.isEmpty()) return Optional.empty();
else return Optional.of(cas);

I check whether the list is empty or not and if it is indeed empty, I return an empty optional and if not, I wrap it. The reason for this is sometimes I get a null value for list itself and sometimes I get an actual list but it is empty.

With this approach, I do not need to double-check the underlying list when the returned optional itself is empty.

But for different data structures, the implementation varies. Is there a built-in way with third party libraries to achieve this? The closest I got is from Guava.MoreObjects#isEmpty but it only checks whether the object is empty or not and does not return an optional in case it is empty.

I could write my own cover for this, but I'm looking for a professional, reliable approach to achieve the required functionality.

Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46
ahrooran
  • 931
  • 1
  • 10
  • 25
  • 7
    I'm going to be annoying and question if `Optional>` is really any better for your use-case than a simple `List`. What's the semantic difference between an absent Optional and an Optional that holds an empty list? If there's no difference (which your question seems to imply), then there's one unnecessary and potentially bug-causing state in this type that you don't need and should make impossible. A simple `List` can already be empty or contain content. – Joachim Sauer Jul 21 '22 at 08:00
  • I have multiple cases where List x = null; similarly other nullable data structures also have this case. – ahrooran Jul 21 '22 at 08:54
  • 2
    I'm not talking about `null` at all here. If you use `Optional` then the assumption is already that you want to avoid having `null` in there at all cost. The specific question is: if you pass around (or return) an `Optional>` is there a defined *meaning* of it being absent versus it being present and containing a list that happens to be empty? Does your code handle those two cases differently? Would one of them be considered a bug? Does it make sense to make that distinction? – Joachim Sauer Jul 21 '22 at 09:09
  • yes. I handle cases of absent vs present list and whether list empty or not differently. Those are design decisions. I could omit enclosing optional if I really want but there are other methods which have similar names and hence the user will naturally expect an Optional to be returned. – ahrooran Jul 21 '22 at 09:43
  • 1
    Then it sounds like you simply have to write all of those helper methods manually. I strongly suspect that the number of those is fairly limited (as `Collection`/`List` will already cover a wide range of container-like objects and the number of alternatives is limited). I don't think streamlining the *code inside* those helper methods is actually worth finding some external thing that may or may not have the same idea of "empty" as you do. – Joachim Sauer Jul 21 '22 at 11:17
  • 4
    The fact that you are creating an empty optional when the list is empty indicates that you are *not* going to treat absent lists and empty lists differently. As afterwards, you have only one of two cases, an empty optional or a non-empty optional containing a non-empty list. Then, there’s obviously no need for the optional, as just having a list also supports to have two cases, an empty list or a non-empty list. Which can easily be tested for using `isEmpty()`. – Holger Jul 21 '22 at 16:12
  • If your clients *really* insist on getting an `Optional` — about which I am still sceptical — just give them an `Optional` containing an empty list if that’s what you have. Then you need no special case and no checking. – Ole V.V. Jul 24 '22 at 09:05

2 Answers2

5

I encounter a specific use case where I often need to wrap objects in Optional if they are empty

List<AbstractCorporateAction> cas = stream.toList();
if (cas.isEmpty()) return Optional.empty();
else return Optional.of(cas);

You're misusing Optional here because stream.toList() will never give you null. You can return the list produced by the stream, it's redundant to wrap it with an optional.

Optional is simply a container for value which may be present or may not, and you can safely interact with it regardless whether it's empty or not. And Collections by their nature are containers of data as well. So you gain nothing apart from inconveniences by wrapping a collection with an optional. It's like placing a box into another box, which would increase the amount of effort to get to the actual contents.

Here is a quote from the answer by Brian Goetz, Java language Architect:

Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result", and using null for such was overwhelmingly likely to cause errors.

For example, you probably should never use it for something that returns an array of results, or a list of results; instead return an empty array or list.

Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46
4

One can use Optional#filter for that:

Optional<List<AbstractCorporateAction>> cas =
    Optional.of(stream.toList())
        .filter(Predicate.not(List::isEmpty));

// Thanks to @Holger

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138