Reputation: 6292
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
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):
null
: Indicates a "special value", such as DEFAULT
or FALLBACK
, which should be handled speciallyThis 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 NULL
s 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 Optional
s, 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 null
s needed.
tl;dr: This can be rationally represented with Optional<Optional<String>>
, or see above for additional suggestions.
Upvotes: 0
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
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
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