6

Why does Java frequently throw null pointer exception if I try to access null values while Objective C does not?

Java:

public class SubscribeEmailActivity {
    String status;

    public static void main(String[] args){

        if(Status.equals(null)||status.equals(""){

            // i am getting error here

        }
     }

}

Objective C:

//in .h file
NSString *exp;

//in .m file
if ([exp isEqualToString:NULL] ||[exp isEqualToString:@""])
{
    // i am not getting any error
}
Pete B.
  • 3,188
  • 6
  • 25
  • 38
Ruban
  • 1,514
  • 2
  • 14
  • 21
  • 9
    Because they are different languages? There is no absolute rule on how a language has to handle calling methods on `null`. It's a decision the developers of the language made for different reasons. – DrummerB Aug 08 '13 at 13:38
  • i have the same doubt – ArunMak Aug 08 '13 at 13:38
  • 4
    I dont know Objective-c, but [exp isEqualToString:NULL] doesn't sound to me like a check for null, but rather a check for "NULL" and your Java check of null makes no sense. – Stefan de Bruijn Aug 08 '13 at 13:38
  • http://stackoverflow.com/questions/4501061/java-null-check-why-use-instead-of-equals – Maroun Aug 08 '13 at 13:44
  • 1
    `[exp isEqualToString:NULL]` doesn't do what you seem to think it does. It will _never_ be true. Messages to `nil` always evaluate to 0, so if `exp` is `nil`, you'll get `NO`, and if it's a valid string, then it can't be equal to `NULL` (note, you should be using `nil` here, which is `NULL` for object types), so you'll again get `NO`. – jscs Aug 08 '13 at 19:31

7 Answers7

7

The problem is in your evaluation in java, it should be:

if(status == null||status.equals("")) {
    //Do not try to dereference status....

It should be noted that this only works because Java, and other languages, allow short cuts in logical evaluations. Some simple boolean algebra in this case:

true || ??? => true

Once the first term evaluates to true, we know that the OR conditional will also evaluate to true, there is no need to examine the second term.

Additionally you can use Apache Commons isEmpty() or roll your own:

public static final boolean isEmpty(String arg0) {
    if(arg0 == null) return true;
    if(arg0.trim().length() < 1) return true;
    return false;
}

The version shown is akin to isBlank in Apache Commons.

Kukanani
  • 718
  • 1
  • 6
  • 22
Pete B.
  • 3,188
  • 6
  • 25
  • 38
  • status.equals("") can also be written as status.isEmpty() – Carnal Aug 08 '13 at 13:41
  • Actually you can avoid both calls by calling `"".equals(status)`. This way the `.equals()` method will *never* be called on a null object, and at the same time you are testing if the string is empty when `status` is not null. – tomacco Jan 17 '17 at 11:52
6

Ultimately, the only way to completely solve this problem is by using a different programming language:

  • In Objective-C, you can do the equivalent of invoking a method on nil, and absolutely nothing will happen. This makes most null checks unnecessary but can make errors much harder to diagnose.
  • In Nice, a Java-derivated language, there are two versions of all types: a potentially-null version and a not-null version. You can only invoke methods on not-null types. Potentially-null types can be converted to not-null types through explicit checking for null. This makes it much easier to know where null checks are necessary and where they aren't.
asteri
  • 11,402
  • 13
  • 60
  • 84
ArunMak
  • 398
  • 2
  • 12
4

This probably won't answer your question, but one rule to avoid a null pointer exception, and in the same time avoid a null check, is to inverse the check like this:

Status status = null;
if("".equals(status)){
  //....
}

which will return false.

while using:

if(status.equals("")){
}

will throw a NPE Exception.

Andy Res
  • 15,963
  • 5
  • 60
  • 96
4

In Objective C method calls are considered to be equivalent to sending message, and sending a message to nil does nothing. This means that you don't have to write the null-checks that would be required in Java, which is more convenient to the programmers who can write more compact code.

On the other hand, it can also be a source of error: if you were expecting to send a message to a real object but send it to nil instead, in Objective C you won't get a warning. In Java this operation causes a NullPointerException to be thrown, making it clear that you have a bug.

Since the language designers have to make a tradeoff between convenience and safety, neither option is objectively better. The designers of Objective C decided it's better to implement nil as a black hole: it swallows anything you throw at it. The designers of Java decided that it's better if dealing with null generated an explicit error. Nothing more to it really.

Joni
  • 108,737
  • 14
  • 143
  • 193
2

If the variable status is null in Java, then trying to call status.equals() will throw a NullPointer exception. isEqualToString is not a member function of Objective-C strings, it simply compares a string and an object.

Kukanani
  • 718
  • 1
  • 6
  • 22
2

It's just a matter of how the language has been designed. You can take a look here if you are brave enough, to see how objc_msgSend works and why you can send messages to nil objects.

Vik
  • 1,897
  • 12
  • 18
2

In your code

if(Status.equals(null)||status.equals("") you are comparing a String to null (null is not a String).

It is not possible to compare String to a non-String. In case of iOS coding i believe that

[exp isEqualToString:NULL]

converts argument to nothing as null or nil are same and then compare it, therefore it works.

Ashwani
  • 3,463
  • 1
  • 24
  • 31