Is Java object containing null variables an anti-pattern? If so which one? [closed]

StackOverflow https://stackoverflow.com/questions/18060043

  •  23-06-2022
  •  | 
  •  

Вопрос

If I query for an object say for an Animal and the returned object is not null but contains null variables is that wrong? For instance I can call animal.getDeathDate(); and since it's not dead yet it returns null. For a Turtle getFlightSpeed() would return null since it's unable to fly until it has the Turtle rocket pack added. Etc, etc.

I thought that this was a bad way to do things as it will often cause the need for a lot of null checks while calling the methods of the object to verify that they contain non-null values. Are there any links to information about this that could inform both myself and my coworkers further?

Это было полезно?

Решение

null is often ambiguous. Was the field uninitialized yet or it just has no value?

It's often better to have some predefined constant for uninitialized / irrelevant fields.

Even better is to have one class have only one responsibility. Methods like getFlightSpeed() should not be inherited, rather come from implementing an interface (methods like getDeathDate(), though, should have a predefined constant returned when Animal is still alive).

As brought by google-guava docs:

Doug Lea (author of java.util.concurrent package) said that Null s**ks.

Also sir C. A. R. Hoare, inventor of the null reference said: I call it my billion-dollar mistake.

That's some wide shoulder to lay upon.

Другие советы

Returning null for the death date for an alive animal is perfectly reasonable, but in cases like this I find it better to offer a boolean death check:

public boolean isDead() {
    return deathDate != null;
}

This offers a reasonable way of checking the death-ness of an instance without a clumsy null check of the attribute:

// this is ugly and exposes the choice of the value of the field when alive
if (animal.getDeathDate() != null) {
    // the animal is dead
}

With the isDead() method in place, you would be within your rights to do this:

public Date getDeathDate() {
    if (deathDate == null)
        throw new IllegalStateException("Death has not occurred");
    return deathDate;
}

Regarding the turtle's flying speed, you could apply the same approach, although I would argue that there's a problem in your class design - not all animals fly, so the Animal class shouldn't have a getFlyingSpeed() method.

Instead, use something like this:

interface Flyer {
    Integer getFlightSpeed();
}

class Animal {}

class Turtle extends Animal {}

class Eagle extends Animal implements Flyer {
    public Integer getFlightSpeed() {
         //
    }
}

Null can sometimes be a perfectly reasonable way of representing that an object lacks a particular property.

However, it's useful to allow a single check.

For an array or a List, it's frequently better to have a variable that is always non-null, but can point to an empty list. Otherwise, it becomes necessary to check both that the variable is non-null and that the list has members.

A major null check rule i have is never to place null instead of a list or an array.

Empty lists and arrays are much better to express what they really are.

I don't think it's wrong. As an analogy, think of the semantics of NULL in SQL:

A good way to remember what NULL means is to remember that in terms of information, "lack of a value" is not the same thing as "a value of zero"; similarly, "lack of an answer" is not the same thing as "an answer of no".

It's perfectly valid to apply the same logic in Java.

In order to make primitive types nullable, check out the nullable types in C#. It should be easy to implement Nullable as a Java generic.

This is just my opinion, but your example does sound like an anti pattern (as a degenerate null object), as you would need to do null checks on what the methods on the "null object" return. If you don't invoke those getters at all, then your example would be correct.

The idea with null objects is that you don't need to perform null checks at all, so it might work if your getters return other null objects, or the methods use a tell-don't-ask approach (and just return void).

Null are perfectly fine, but you should try to avoid them using default values as much as possible

For example empty list should be returned instead of null enum data types should contains UNKNOWN

Above assumption makes life of API consumer easy

in your example I would return null from animal.getDeathDate as I cant think of any suitable default value.

I will provide convenience method animal.isDead returning true/false

For getFlightSpeed() I would return 0 for your case

Null Object pattern indeed can be used in case of null variables. In case of Turtle.getFlightSpeed() , you can abstract out SPEED concept (may be interface or abstract class) , and have one NULL object implementing "unable to fly" scenario. This will help assigning default behavior to Turtle classes. Returning null in case of animal.getDeathDate() seems fine

I think that for animal.getDeathDate() returning null if the animal is alive is the correct way to do things. You will always need special code to handle the 2 cases: animal alive, and animal dead, and there is no usefull date you can return if the animal is alive.

For getFlightSpeed() things might be different. I don't know exactly what it returns but let's just for an example imagine it just return the speed as m/s

In that case returning 0(Or an object with the same effect) will make perfect sense, because it does describe the flight speed.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top