Kevin
Kevin

Reputation: 6292

Java Class that can be used to represent null and absent differently

I am wondering if there is a ready made Java class that can be used similarly with Guava's Optional but treats null and absent differently.

I have use case that requires to pass a method parameter with String value, null value or absent (does not provide anything). Null is a purely valid value and carries special meaning.

I tried to use Guava's Optional but found that it cannot differentiate null and absent. Passwing null to Optional means absent.

I am wondering if there is a ready made Java utility that can be used for my usecase: It can carry a value, null value or no value (absent).

many thanks

Upvotes: 0

Views: 3199

Answers (4)

dimo414
dimo414

Reputation: 48864

Null ... carries special meaning.

Whenever you find yourself saying this, it should be a red flag that your design merits re-thinking, as null by definition carries no meaning. Lets step back and look at your requirements (feel free to update the question with better descriptions of your intent if this is inaccurate):

  • Absence: Indicates we've nothing to do here at all
  • null: Indicates a "special value", such as DEFAULT or FALLBACK, which should be handled specially
  • Value: A "normal" value, including the empty string, that can be handled directly

This is not an unusual problem, (particularly when working with nullable database columns, as I think you are) and Optional can quite successfully represent this, but we need to structure it better.

While we can't avoid NULLs in databases, we can strive to restrict their scope to the minimal code surrounding our database access behavior, and expose it no further than that. We conceptually do this by converting nullable fields to Optionals, as you know. So col VARCHAR NULL should always be converted into Java as an Optional<String> col as soon as possible.

But now we need to represent the absence case, such as when we SELECT col FROM table LIMIT 1 and get nothing back from our query. Obviously, this should be handled differently than if we get back a NULL.

We have a couple of choices, but they all boil down to wrapping our Optional<String> in another layer somehow.

In many cases you can simply use a List or other Collection. By passing back a non-null collection we can generally handle the absent case trivially, as our code will simply not enter whatever loop would otherwise process the data if the List is empty. So List<Optional<String>> is one option.

If that's not possible, and you really want to limit the behavior to one-or-none, such as in the LIMIT 1 example above, simply wrap it in another Optional, i.e. Optional<Optional<String>>. This clearly conveys the difference between absence of a result, and absence of a value in a type-safe manner.

A little more work, but even better is to properly represent this structure in its own class (any time you have generics inside generics, consider creating a proper holding class), since really what we're talking about is a optional piece of data, which may itself contain an optional piece of data.

public class Row {
  private final Optional<String> col;
  public Row(@Nullable String col) {
    this.col = Optional.fromNullable(col);
  }
  public Optional<String> getCol() {
    return col;
  }
}

Then you pass around Optional<Row> objects, which very clearly either exists or doesn't, and either contain a result, or not. All type-safe, and no nulls needed.


tl;dr: This can be rationally represented with Optional<Optional<String>>, or see above for additional suggestions.

Upvotes: 0

Olivier Gr&#233;goire
Olivier Gr&#233;goire

Reputation: 35457

You should use Optional.

Optional is you know that something is either present or not. Add the meaning null to Optional by returning... null.

Optional<A> a = Optional.of(new A()); // We know that A is present.
Optional<B> b = Optional.absent();    // We know that B is absent.
Optional<C> c = null;                 // We don't know if C is present or absent.

Working with null isn't bad: it's error-prone. So be careful, document properly what you want to do and how null should be interpreted.

Upvotes: 1

Bohemian
Bohemian

Reputation: 425178

The java language can do it: Use a token object to represent "absent".

Say it's a String type:

private static final String ABSENT = new String(""); // not interned

private String attribute = ABSENT;

public boolean attributeIsSet() {
    return attribute == ABSENT; // identity comparison
}

public String getAttribute() {
    if (attributeIsSet())
        return attribute;
    throw new IllegalStateException(); // or whatever
}

This allows null to be a valid value.

Upvotes: 1

dnellis74
dnellis74

Reputation: 112

Isn't an empty String ("") the same as 'no value' for a string? Obviously this wouldn't work for numbers, but you're specifically talking about a String.

Upvotes: -1

Related Questions