tags:

views:

474

answers:

5

Hi,

I am creating an application which retrieves images from the web. In case the image cannot be retrieved another local image should be used.

While trying to execute the following lines:

Drawable drawable = Common.getDrawableFromUrl(this, product.getMapPath());
                if(drawable.equals(null)){
                    drawable = getRandomDrawable();
                }

The line if(drawable.equals(null)) throws an exception if drawable is null.

Does anyone know how should the value of drawable be checked in order not to throw an exception in case it is null and retrieve the local image (execute drawable = getRandomDrawable())?

+19  A: 
if (drawable == null) {
  ...
}

The equals() method checks for value equality, which means that it compares the contents of two objects. Since null is not an object, this crashes when trying to compare the contents of your object to the contents of null.

The == operator checks for reference equality, which means that it looks whether the two objects are actually the very same object. This does not require the objects to actually exist; two nonexistent objects (null references) are also equal.

Thomas
I want to add a very valuable tip: If you have strings or constants to compare, *always* put them first in the equals clause.(if ("coyote".equals(myDogString))) is much better than (if (myDogString.equals("coyote"))) because in the second case myDogString may be null and throws an NPE while in the first case it doesn't matter if myDogString is null.
Thorsten S.
+2  A: 

You could beautify this with a static method:

public static <T> T replaceIfNull(T objectToCheck, T defaultValue) {
  return objectToCheck==null ? defaultValue : objectToCheck;
}

Instead of

Drawable drawable = Common.getDrawableFromUrl(this, product.getMapPath());
if(drawable == null){
  drawable = getRandomDrawable();
}

you would write this:

Drawable drawable = 
  replaceIfNull(Common.getDrawableFromUrl(this, product.getMapPath()), getRandomDrawable());

If you perform the initialization of drawable in one step, you could even make it final.

Maybe the method name replaceIfNull is not the best. Suggestions are welcome!

deamon
Probably not a good idea - you're going back to Fortran 60 where both sides of the conditional are evaluated, then only one gets used. This is bad if the unused branch has any computation, which is true most the time, so it isn't a generally useful method. I'd move the condition to the `Common` class, and allow you to supply a fallback URL, and keep the responsibilities together.
Pete Kirkham
You're right. This can lead to needless evaluation. It would be better to move that into `Common` class, as you've said.
deamon
Ah C# is so nice `return objectToCheck ?? defaultValue;`.
ChaosPandion
+1  A: 
drawable.equals(null)

The above line calls the "equals(...)" method on the drawable object.

So, when drawable is not null and it is a real object, then all goes well as calling the "equals(null)" method will return "false"

But when "drawable" is null, then it means calling the "equals(...)" method on null object, means calling a method on an object that doesn't exist so it throws "NullPointerException"

To check whether an object exists and it is not null, use the following

if(drawable == null) {
    ...
    ...
}

In above condition, we are checking that the reference variable "drawable" is null or contains some value (reference to its object) so it won't throw exception in case drawable is null as checking

null == null

is valid.

Yatendra Goel
+1  A: 

I use this approach:

if (null == drawable) {
  //do stuff
} else {
  //other things
}

This way I find improves the readability of the line - as I read quickly through a source file I can see it's a null check.

With regards to why you can't call .equals() on an object which may be null; if the object reference you have (namely 'drawable') is in fact null, it doesn't point to an object on the heap. This means there's no object on the heap on which the call to equals() can succeed.

Best of luck!

I too prefer the if(<constant> == <variable>) construct as a way to protect myself from accidental assignment.
Scott
A: 

It's probably slightly more efficient to catch a NullPointerException. The above methods mean that the runtime is checking for null pointers twice.

Tom R
Where is the double check in `if x == null` solution?
deamon
After the if statement, the runtime will check again for a null pointer when the object is used. I don't know whether or not this is optimised by the compiler, though.
Tom R
This goes against conventional wisdom, using exceptions as control flow.
James