No Null Beyond Method Scope

Problem

When catching a NullPointerException in Java the StackTrace? doesn't lead you to the real bug. It tells where a method call on a NullValue failed, but not where this NullValue came from. Tracking this down can take long debugger sessions - you lose hours or even days.

Solution

Never return null. Never accept null as parameter.

If NullValues exist only within method scope, you make sure that the creation of a NullValue and failing method calls are in the same method body. You don't need a debugger to get from the failed method call to the NullValue creation. Further more it's possible to avoid any NullPointerExceptions at all, since within a short of piece code like a method body one may keep track of NullValues avoid any method calls on them.

To check for null parameters UseAssertions or even better use AspectOrientedProgramming. In aspect oriented languages like AspectJavaLanguage tests for null parameters and return values can be done in a very convenient way.

Instead of null as return value use the NullObject pattern, or if you can't do so throw a RuntimeException. If you throw an exception you should provide a possibility to check if the critical method can be executed without causing an exception. Hence..

	try {

		obj.get(foo);

	}

	catch (RuntimeException e) { ... }

..should be rewritten as..

	if (obj.contains(foo)) {

		// we are now sure that get(foo) doesn't throw an exception

		obj.get(foo);

	}

If this needs to be ThreadSafe you'll need to lock obj before contains() and release the lock after get()

If you can't avoid to return null choose a method name that makes this clear, e.g. getFooOrNull().

See also CheckDontCatch and DontCatchRuntimeExceptions.

I find that it is often better to have a parameter, such as 'bool IsRequired'. If the search/query method cannot find the object desired, then it checks IsRequired. If IsRequired is true, then the method throws an exception. If IsRequired is false, then the method returns null. This allows me to have a single method that can be used for the most common case (which, for my projects, has always been IsRequired == true), and yet still avoid the necessity to either query twice (contains, then query, which is extremely inefficient), or to require that an exception be thrown and caught, in a very common, expected case. -- ArlieDavis

Based on my experience you can save most of your debugging time when applying this idiom. -- AdrianKuhn?


This doesn't seem to be a problem to me. Sure, I get NullPointerExceptions in my code all the time, but they don't seem to be that difficult to track down. Since I try to observe LawOfDemeter, it's not too hard to figure out which value in a statement is the NullValue, and since I try to make sure my methods are never that long, it's not that hard to figure where the value is coming from.

I agree with this. I find that people do an awful lot of up-front checking for null values that needn't be done. I have never had a problem tracking down a NullPointerException. DontCatchRuntimeExceptions. -- IainLowe

In fact, NullPointerExceptions are the easiest bugs to resolve. The NoNullBeyondMethodScope approach, by hiding NullPointerExceptions, can make debugging more difficult. Still, for methods that return collections, it does seem more intuitive to return an empty collection instead of a NullPointer.

The NoNullBeyondMethodScope does NOT mean "hide null pointers", indeed, it means don't MAKE them and don't ACCEPT them. Not accepting them means throwing an exception at the earliest possible point that the null is discovered. -- JeffBay

NullPointerExceptions can be *very* difficult to solve in certain cases. If the system religiously observes the LawOfDemeter, it is not very common, however, even then they can be difficult to track down. The main problem children in the null pointer world are when a value is written to/ a setter is called from multiple places, and then the value is used in another place. There exist algorithms where the setters may be called from multiple locations is a common, desired and necessary structure. However, not preventing the assignment of null into the value means that the NullPointerException occurs at a point far away from the real error. In this case, you may spend endless hours playing "hunt the null pointer wumpus". -- JeffBay


You can get a lot of the benefit simply by applying the "don't return null" part. If you never return nulls, and convert what would be nulls into instances of the NullObject pattern, you shouldn't ever get them in. In addition, you code reads a lot nicer, because you don't have any "if (objectX == null) {...}" guff.

If you deal with APIs, the "don't accept nulls" should only go up at the entry interfaces. -- RobertWatkins

I don't agree that returning nulls is necessarily a bad idea, so long as you are following DesignByContract principles (whether your language formally supports DesignByContract or not). It is a question of the contract of the API. If the contract says that it returns null in such-and-such a condition, then it is the responsibility of the callers to deal with that return value. It should also be possible to pass nulls to arguments if the meaning of doing so is clearly defined in the contract. The issue here is really about communicating to the caller what their responsibilities are. Javadoc should be sufficient to define the contract in Java for this purpose, for example. -- BruceAtherton

* It still can be viewed as often times a bad idea, but of course there are exceptions. The fact that you document it in a contract does not mean you could not have designed better contracts instead, rather than document the usage of nulls. --CostinCozianu

I HaveThisPattern -- ChristianTaubman

See also SamuraiPrinciple.


I agree with Iain about needless up-front checking for null values - it's noise that detracts from the communication value of the code. Plus, if you use this idiom and you need to indicate to the caller of a querying method that the sought object isn't available, what do you do? Throw an exception? DontUseExceptionsForFlowControl. Use a ResultObject? Maybe, by why go to the trouble when you could DoTheSimplestThingThatCouldPossiblyWork by returning null. In my experience, most NullPointerExceptions are caused by uninitialized instance variables, which are corrected by applying well-known creation and initialization idioms, perhaps in combination with assertions, etc. I agree that if a method can return null its name or documentation should say so - but that's just normal communication. If a programmer of a client of that method assumes the return value is always non-null, shame on him. IMHO clear communication is the better way to reduce programmer error; not more code, which interferes with communication. -- RandyStafford

I'm with you on this Randy... if a function is always capable of returning a meaningful value, then it should, of course, never return null. If a function sometimes DOESN'T have a meaningful value to return, then you've got to do something. Throwing an exception makes sense sometimes, but not always. Returning a NullObject is a good idea if the code that uses this result can be simplified by that pattern. But if the code that uses this result simply needs to skip over the values that aren't meaningful, then we need a special NullObject with no methods or fields (or, in order to FailFast, which throws an exception whenever you try calling a method or accessing a field). This special NullObject is called "null". --MichaelChermside


I HaveThisPattern. I've used it to great success on a number of projects. The primary benefit is that null reference exceptions are particularly nasty to track down otherwise. Many applications I've seen will return null if passed a slightly out-of-bounds parameter, including null. Combine this with the habit of some applications to return null instead of throwing an exception, and you've got a situation in which the null exception stack trace is nowhere near the actual cause of the problem.

In my applications, returning null or passing in null is assumed to be an error except in specific situations. Every method would throw a null exception if one of its parameters was null. Fortunately, this wasn't as cumbersome as it sounds, because in Java, you get most null exceptions for free. Example:

 public void foo(Object a, Object b) {

   Assert.NotNull?(a);

   b.bar(a);

 }

We didn't have to assert b was not null because it was being dereferenced and we could count on Java throwing the exception for us. Having the Assert class helped too.

--JimShore

WRT Jim's comments, I'm not sure that relying on the runtime to throw NPE for you is a good idea, especially in class constructors. What happens if b.bar(a) is refactored into a class method that is called after the class constructor? Now you have a deferred NPE, which is exactly what this pattern is intended to avoid.

See this bug, for example: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4667036

--NiallSmart?

In the future, you might be able to let the compiler solve this problem for you in Java, like you can in some other languages. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5030232

NeverIsNeverNever.


EditText of this page (last edited September 22, 2005)
FindPage by browsing or searching

This page mirrored in JavaIdioms as of October 22, 2005