5

I'm trying to make a basic cache of a boolean value, and I did it like such:

private Boolean _valueCache = null;
private boolean getValue() {
    try {
        if (_valueCache == null) { // if cache was never filled
            return _valueCache = getReader().getMyBooleanProperty(); // fill it and return the new value
        }
        return _valueCache; // else, return the cache
    } catch (NullPointerException ex) { // getReader() returned null
        return false; // that return may not be null in the future, so set nothing
    }
}

Does this go against best practices? (letting a Boolean have 3 values: true, false, and null) I only want to cache this value, so I don't want to make an entire custom HashMap that mimics this behavior with a get-or-default method. That said, I've never done a cache this small so I don't know the downsides to it.

To clarify, I meant "ternary" as in "3-state", as opposed to "binary" as in "2-state". Sorry for any confusion.

Ky -
  • 525
  • 5
  • 17
  • 1
    See this question: http://programmers.stackexchange.com/questions/152094/null-pointers-vs-null-object-pattern and https://en.wikipedia.org/wiki/Null_Object_pattern – Vitaly Olegovitch Mar 05 '15 at 15:57
  • @VitalijZadneprovskij is NOP possible in Java? As far as I know, there's no way to `myMethod(o)` branch to different method definitions at runtime (like `myMethod(Object o)` vs `myMethod(null o)`), or even to make a method take a `null`. Also, the provided question's answer mentions `methodA()->methodB()`, which will throw a `NullPointerException` in Java if `methodA()` returns `null`. – Ky - Mar 05 '15 at 16:04
  • 3
    Related reading: **[Why use a bool over more domain specific abstractions](http://programmers.stackexchange.com/q/275011/22815)**. While the question is not a duplicate, the answers do help address what you are trying to accomplish here. –  Mar 05 '15 at 16:37
  • 2
    What about FILE_NOT_FOUND ? – kevin cline Mar 06 '15 at 05:12
  • 1
    http://thedailywtf.com/articles/What_Is_Truth_0x3f_ – Alexis King Mar 07 '15 at 10:20
  • The overarching question is IMHO: Should you ever catch a `NullPointerException`. The answer is : *NO*. – Marco13 Mar 07 '19 at 13:02
  • @Marco13 Why? If you think you have a good answer to this question, you should post it – Ky - Mar 08 '19 at 23:35
  • @BenLeggiero The intention was not to answer the question. That's why it is only a *comment*, and not an answer. For the NPE part, I'd point to https://stackoverflow.com/questions/18265940/when-is-it-ok-to-catch-nullpointerexception – Marco13 Mar 09 '19 at 13:03

3 Answers3

7

You're not doing ternary logic, you're just using null as a placeholder for a missing value that happens to be of type Boolean. (Not having true nor false isn't quite the same as having one of the two but not knowing which.) Using null this way is a fairly common practice, but I wouldn't call it a good one.

It's unlikely to cause you problems in this particular case because it's only used internally within a very small scope, but in general you would want to use Optional instead. Since any non-primitive variable could have null, it's very difficult to keep track of it in a large code base. The easiest way to avoid the issue is to not use null in the first place.

Doval
  • 15,347
  • 3
  • 43
  • 58
  • 1
    The `Optional` class looks promising! If only I weren't forced to use Java 1.6... – Ky - Mar 05 '15 at 16:14
  • 2
    @BenC.R.Leggiero [Guava](https://github.com/google/guava) has an `Optional` implementation as well and should work with 1.6. It's also not hard to implement yourself. – Doval Mar 05 '15 at 16:18
2

While using null or using an Optional are reasonable choices, one more option would be to add an explicit second field, boolean _hasBeenRead. Your code would look like

private boolean getValue() {
    if (_hasBeenRead)
       return _valueCache;

    else {
       // read the value and, if successful, set both _hasBeenRead and _valueCache.
    }
}

Some would consider this more explicit and therefore clearer. Especially if you are using older style Java without new fangled goodies like Optional.

p.s. Whatever you do, consider whether this method need be synchronized, if the variables need to be volatile, etc...

user949300
  • 8,679
  • 2
  • 26
  • 35
  • Good point about the `volatile` and `synchronized` status! This is for Android, so I'm not entirely sure what threads will need this or when. – Ky - Mar 09 '15 at 13:13
-3

The tenary logic for this should be

private Boolean _valueCache = null;
private boolean getValue() { 
         Boolean readerValue = getReader() == null ? false : reader.getMyBooleanProperty();
         _valueCache = _valueCache == null  ? readerValue : _valueCache; 
         return _valueCache;

   }

By the way, what is the use of the NullPointer exception handled, Does the getReader() return null, Runtime exceptions like this are also not advisable

  • That line of code is too short - somebody might actually understand it. – user949300 Mar 07 '15 at 00:10
  • Thanks for your input! Sorry, I wasn't clear. I don't need help on how to use the ternary operators `?:`, but on whether this 3-state `Boolean` is a good idea. – Ky - Mar 09 '15 at 13:16
  • Also, the `getReader()` method (not made/controlled/modifiable by me) contains a conditional `throw new NullPointerException()` in it, so the `try`/`catch` is necessary, anyway. – Ky - Mar 09 '15 at 13:17