Thursday 23 November 2017

java - Avoiding != null statements

itemprop="text">

I use object !=
null
a lot to avoid href="https://docs.oracle.com/javase/9/docs/api/java/lang/NullPointerException.html"
rel="noreferrer">NullPointerException.



Is
there a good alternative to this?



For
example:



if (someobject != null)
{

someobject.doCalc();

}


This
avoids a NullPointerException, when it is unknown if the object
is null or not.



Note
that the accepted answer may be out of date, see href="https://stackoverflow.com/a/2386013/12943">https://stackoverflow.com/a/2386013/12943
for a more recent approach.


itemprop="text">
class="normal">Answer



This to me
sounds like a reasonably common problem that junior to intermediate developers tend to
face at some point: they either don't know or don't trust the contracts they are
participating in and defensively overcheck for nulls. Additionally, when writing their
own code, they tend to rely on returning nulls to indicate something thus requiring the
caller to check for nulls.



To put this another
way, there are two instances where null checking comes
up:





  1. Where
    null is a valid response in terms of the contract;
    and


  2. Where it isn't a valid
    response.




(2)
is easy. Either use assert statements (assertions) or allow
failure (for example, href="http://docs.oracle.com/javase/6/docs/api/index.html?java/lang/NullPointerException.html"
rel="noreferrer">NullPointerException). Assertions are a highly-underused
Java feature that was added in 1.4. The syntax
is:



assert




or



assert
:



where
is a boolean expression and
is an object whose
toString() method's output will be included in the
error.



An assert
statement throws an Error
(AssertionError) if the condition is not true. By default, Java
ignores assertions. You can enable assertions by passing the option
-ea to the JVM. You can enable and disable assertions for
individual classes and packages. This means that you can validate code with the
assertions while developing and testing, and disable them in a production environment,
although my testing has shown next to no performance impact from
assertions.




Not using assertions in
this case is OK because the code will just fail, which is what will happen if you use
assertions. The only difference is that with assertions it might happen sooner, in a
more-meaningful way and possibly with extra information, which may help you to figure
out why it happened if you weren't expecting
it.



(1) is a little harder. If you have no
control over the code you're calling then you're stuck. If null is a valid response, you
have to check for it.



If it's code that you do
control, however (and this is often the case), then it's a different story. Avoid using
nulls as a response. With methods that return collections, it's easy: return empty
collections (or arrays) instead of nulls pretty much all the
time.



With non-collections it might be harder.
Consider this as an example: if you have these
interfaces:



public interface
Action {
void
doSomething();

}

public interface Parser
{
Action findAction(String
userInput);
}


where
Parser takes raw user input and finds something to do, perhaps if you're implementing a
command line interface for something. Now you might make the contract that it returns
null if there's no appropriate action. That leads the null checking you're talking
about.



An alternative solution is to never
return null and instead use the href="https://en.wikipedia.org/wiki/Null_Object_pattern" rel="noreferrer">Null Object
pattern:




public
class MyParser implements Parser {
private static Action DO_NOTHING = new
Action() {
public void doSomething() { /* do nothing */ }

};

public Action findAction(String userInput) {
//
...
if ( /* we can't find any actions */ ) {
return
DO_NOTHING;

}

}
}


Compare:



Parser
parser = ParserFactory.getParser();
if (parser == null) {
// now
what?

// this would be an example of where null isn't (or
shouldn't be) a valid response
}
Action action =
parser.findAction(someInput);
if (action == null) {
// do
nothing
} else {

action.doSomething();
}



to



ParserFactory.getParser().findAction(someInput).doSomething();


which
is a much better design because it leads to more concise
code.



That said, perhaps it is entirely
appropriate for the findAction() method to throw an Exception with a meaningful error
message -- especially in this case where you are relying on user input. It would be much
better for the findAction method to throw an Exception than for the calling method to
blow up with a simple NullPointerException with no
explanation.



try
{


ParserFactory.getParser().findAction(someInput).doSomething();
}
catch(ActionNotFoundException anfe) {

userConsole.err(anfe.getMessage());
}


Or
if you think the try/catch mechanism is too ugly, rather than Do Nothing your default
action should provide feedback to the
user.



public Action
findAction(final String userInput) {
/* Code to return requested Action if
found */

return new Action() {
public void
doSomething() {
userConsole.err("Action not found: " + userInput);

}
}
}


No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...