Zaid Fanek
Zaid Fanek

Reputation: 23

Is there a way that i can make my object never null?

I was given a task and I'm not sure how to get it to work. All the test cases must pass.

Assertions.assertDoesNotThrow(() -> p3.equals(null));
Assertions.assertFalse(p3.equals(null), "equals to null should return false");
  

I figured out the first one, the one that is tricking me is the Assertions.assertfalse(p3.equals(null)). I created the object p3 from Point as such:

Point p3 = new Point(x+1, y-1);

In my Point class I have an equals method which I override as such:

@Override
public boolean equals(Object obj) {
    Point p = (Point) obj;
    try {
        if (x != p.x) {
            return false;
        }

        if (y != p.y) {
            return false;
        }
    } catch (NullPointerException e) {
        System.err.println("null");
    }
    return true;
}

I used this to pass other tests not mentioned.

public Point(int x, int y) {
    this.x = x;
    this.y = y;
}

public int x() {
    return x;
}

public int y() {
    return y;
}

Where x and y are random integers between 0-30.

When I run the test, it always returns p3 equal to null which is confusing me. I know it is something to do with checking if the object passed through is of same type (Point) & downcasting, but I am not sure.

Upvotes: 1

Views: 248

Answers (1)

Nathan Hughes
Nathan Hughes

Reputation: 96454

If you look at the signature of the equals method you are implementing you'll see it takes an argument of type Object. That means the thing passed in can be any reference type. It can be null. Currently your equals method blindly casts whatever it gets to a Point, so if it gets anything other than a Point then an exception gets thrown. Then later, if the thing passed in is null, referencing an instance member (like p.x) will cause a NullPointerException.

There are at least four tests you need to write for your equals method:

  1. Pass in another Point with the same x and y values,

  2. Pass in a Point with different x and y values.

  3. Pass in some object with a totally different type, like String or Integer.

  4. Pass in null.

These need to be in different test methods, so that they can fail independently of each other. Cramming them into the same test means that when one assertion fails, the ones after it don't run; fixing tests turns into a whack-a-mole situation where you fixed one problem but now another one pops up.

You can use instanceof to check that what you are getting is the right type and is non-null. Since your current code catches a NPE, it lets execution continue from the catch block to the line with return true; , which isn't what you want.

So start your equals method with something like

if (!(object instanceof Point)) {
    return false;
}

before you cast. Once you know the object is a non-null Point then you can continue with

Point p = (Point)object;
return x == p.x && y == p.y;

Since && short-circuits this doesn't do any more work than the posted code, they both stop checking if the first check evaluates to false.

Upvotes: 2

Related Questions