0

I have a Record class as follows

class Record {
  String name;
  Object value;
  public void setValue(Object value) { this.value = value; }
}

If no value was set to the value field then it would be null. It is also possible that null was explicitly set using the setter i.e new Record().setValue(null).

Since explicitly setting the value as null has meaning in my application, I want to track whether the null value was explicitly set by user or is just an implicit null. What is the best way and the proper way to do it?

The solutions I came up with were,

  • A boolean flag
  • Use a marker class. Set value as Object value = new Undefined(); and perform instance check later. Here Undefined is an internal dummy class.
  • Use Optional<Object> value; and have the setter as public void setValue(Object value) { this.value = Optional.ofNullable(value); }

If this was JavaScript, it has undefined built in the language itself. What is the best way to do this Java?

Amrish Kumar
  • 308
  • 3
  • 12
  • 2
    Third seems to be the best. Why is the value an *Object* and a specific type? You can try to explore the [Null Object Pattern](https://en.wikipedia.org/wiki/Null_object_pattern) – Thiyagu Jul 04 '20 at 13:29
  • Choose the third option. Not sure if it is the best way to do so, but looks very elegant while reading the code. – Ajay Kr Choudhary Jul 04 '20 at 13:32
  • Just a suggestion: whenever it is possible, don't allow uninitialized fields. In your example I'd create constructor `Record(Object value) { this.value = value; }` which requires the initialization of the field when object is created. – Piotr Aleksander Chmielowski Jul 04 '20 at 13:33
  • If value must be set (mandatory) you can use a Builder where you force the value to be provided. In that case, you can get rid of worrying about unset field – Thiyagu Jul 04 '20 at 13:33

2 Answers2

2

What is the best way and the proper way to do it?

There is no single "best" or "proper" way to do this, though it is probably a bad idea to try to distinguish different causes or kinds of null.

Here are some of the alternatives.

  1. Avoid the problem by making null an illegal value; e.g.

     public void setValue(Object value) { 
         if (value == null) {
             throw new NullPointerException("Value cannot be null");
         } else {
             this.value = value; 
         }
     } 
    
  2. Use Optional<Object>.

  3. Use the Null Object Pattern.

  4. Use zero length arrays and (immutable) empty collections rather than null arrays and collections. (The "null means empty" optimization is a bad idea. It makes your code more complicated and more NPE prone and the space saving is minuscule.)

  5. Avoid the problem by insisting that the field is initialized to a non-null value. This could be done using the Builder Pattern, or using a constructor that insists that the supplied value for value not null.

  6. Use a special value to mean "this field has not been initialized"; e.g.

     private static final Object UNINITIALIZED = new Object();
     private Object value = UNINITIALIZED;
    
     public void getValue() {
         if (value == UNINITIALIZED) {
             throw new UninitializedFieldException("Value is uninitialized");
         } else {
             return value;
         }
     }
    

    Notes:

    • This is a variation of the Null Object Pattern.
    • You don't need a special class to do this.
    • It is best to keep the instance (or class) hidden. Therefore the value field needs to be private and the getter needs to throw an exception if the field is "uninitialized.
  7. Use a boolean to denote that the field has not been initialized.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Most of your alternatives suggest to avoid non initialization. The basis here is that user would be sending a new record object to update to his old record based on some key (For simplicity assume the key is name field here). It would be too verbose to ask the user to set every field even the ones he does not wish to modify/update. I am considering to use the uninitialized method. – Amrish Kumar Jul 04 '20 at 15:36
  • My bad, thought that "explicitly setting the value as null has meaning in my application" would have sufficed, it has not. – Amrish Kumar Jul 04 '20 at 15:49
  • 1
    I addressed that with "it is probably a bad idea to try to distinguish different causes or kinds of null." :-) – Stephen C Jul 05 '20 at 02:39
  • Just to be more clear, I am not trying to distinguish all causes or kinds of null, but only 2 of them. A property that does not exists (Not set) vs a property that has been set and has no value. Basically I am trying to achieve this behaviour https://stackoverflow.com/questions/461966/why-is-there-a-null-value-in-javascript in Java. – Amrish Kumar Jul 05 '20 at 07:10
  • 1
    Just to be clear, "different kinds" includes "just two kinds". But if you want to **update your question** to include the specific use-case you are interested, perhaps someone will write a better answer for you. (I think I implied that already. Now I am stating it clearly.) – Stephen C Jul 05 '20 at 07:16
0

I think considering null value as user entry isn't the best solution since later on, you can't differentiate a null coming from the user from a null field that wasn't set programmatically. (i.e. If your client needs to update the record, you will not be able to distinguish whether he sets the value to null or he doesn't want to update it, hence you can overwrite a previous value).

So, if I were in you place, I would replace the null with some meaningful object value.

Katy
  • 1,023
  • 7
  • 19