Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

Diagnosing Java Code: The Null Flag bug pattern

Avoid using null pointers as flags for exceptions

Eric Allen, Software Engineer, Cycorp, Inc.
Eric Allen has an A.B. in computer science and mathematics from Cornell University. He is currently the lead Java software developer at Cycorp, Inc., and a part-time graduate student in the programming languages team at Rice University. His research concerns the development of formal semantic models and extensions of the Java language, both at the source and bytecode levels. Currently, he is implementing a source-to-bytecode compiler for the NextGen programming language, an extension of the Java language with generic run-time types.

Summary:  Often, our efforts to develop robust programs by substituting null pointers for exceptional conditions actually limits control flow to the ordinary paths of method invocation and return, and buries evidence of where an exceptional condition occured. In this column, Eric Allen shows how this bug pattern, which he calls the Null Flag bug pattern, produces unexpected results that are difficult to debug. As with the other bug patterns that we have discussed, you can minimize occurrences of this pattern by applying certain programming techniques.

View more content in this series

Date:  01 Mar 2001
Level:  Introductory

Comments:  

The Null Flag bug pattern

In my last article, I showed how the substitution of null pointers for various base types of data is one of the most common causes of NullPointerExceptions. This time, I will show how substituting null pointers for exceptional conditions also tends to cause problems. Exceptional conditions in Java programs are ordinarily dealt with by throwing exceptions and catching them at an appropriate point of control. But you will often see methods that indicate such a condition by returning a null-pointer value (and, perhaps, printing a message to System.err). If the calling method does not explicitly check for a null pointer, it may attempt to dereference the return value and trigger a null-pointer exception.

As you might have guessed, I call this pattern the Null Flag bug pattern because it is caused by inconsistently using null pointers as flags for exceptional conditions.


The cause

Let's consider the following simple bridge class from BufferedReaders to Iterators:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Iterator;


public class BufferedReaderIterator implements Iterator {

  private BufferedReader internal;

  public BufferedReaderIterator(BufferedReader _internal) {
    this.internal = _internal;
  }

  public boolean hasNext() {
    try {
    
      boolean result = true;

      // Let's suppose that lines in the underlying input stream are known
      // to be no greater than 80 characters long.
      internal.mark(80);

      if (this.next() == null) {
        result = false;
      }
      internal.reset();
      return result;
    }
    catch (IOException e) {
      System.err.println(e.toString());
      return false;
    }
  }

  public Object next() {
    try {
      return internal.readLine();
    }
    catch (IOException e) {
      System.err.println(e.toString());
      return null;
    }
  }

  public void remove() {

    // This iterator does not support the remove operation.
    throw new UnsupportedOperationException();
  }

}

Because this class serves as a bridge implementation of the Iterator interface, the code must catch IOExceptions from BufferedReader. Each of the methods handles IOExceptions by returning some default value. In the case of hasNext, the value false is returned. This is reasonable because, if an IOException is thrown, the client should not expect that another element can be retrieved from the Iterator. On the other hand, next simply returns null, both in the case of an IOException and, because it relies on the return value of internal.readLine(), in the case when internal is empty. But this is not what the client of an Iterator object would expect. Normally, when next is called on an Iterator with no more elements, it throws a NoSuchElementException. If a client of our Iterator is relying on this behavior, it may very likely attempt to dereference a null pointer returned from a call to next, resulting in a NullPointerException.

Whenever a NullPointerException occurs, check for scenarios like the one described above. Occurrences of this bug pattern are very common.


Prevention

Despite their common occurrence, the use of null flags is very often unwarranted (as in the case above). Let's rewrite next so that it throws NoSuchElementException as expected:

  public Object next() {
    try {
      String result = internal.readLine();
      if (result == null) {
	throw new NoSuchElementException();
      }
      else {
	return result;
      }
    }
    catch (IOException e) {
    
      // The original exception is included in the message to notify the 
      // client that an IOException has occurred.
      throw new NoSuchElementException(e.toString());
    }
  }


Note that, to make the rest of the code work with this altered method, we would also have to:

  1. Import java.util.NoSuchElementException.
  2. Fix hasNext so that it no longer calls next to test. The simplest way to do this would be to simply call internal.readLine() directly.

An alternative to our handling of IOExceptions would be to catch them and throw RuntimeExceptions in their stead. Base your decision to do this on an assessment of how frequently IOExceptions are expected to occur on the target platform. If they will be frequent, then you might want to try recovering from them.

Any code that calls this new next method may have to deal with thrown NoSuchElementExceptions. Of course, the code may simply choose to ignore them and allow the program to abort. If so, the resultant error message and the place where the exception was thrown would be much more informative than a NullPointerException thrown by the original code. If the exception thrown were a checked exception (such as IOException) it would be even more helpful, because no client code for the class would compile unless it handled the exception. That way, we could eliminate even the possibility of certain errors occurring before the program is ever run. But, in this example, we couldn't throw such a checked exception without violating the Iterator interface. So, we've sacrificed some static checking for the sake of reusing code that operates on Iterators. Tensions such as these, between the goals of static checking and reuse, are quite common.


Wrapup

Before I leave this topic, I should address the concerns of many programmers who use null flags regularly. Many programmers argue that it makes their programs more "robust." After all, they might say, a robust system handles varied situations gracefully rather than throwing exceptions at every little problem that comes up. But this argument overlooks the fact that exceptions are a great tool to increase the robustness of code, by allowing control to pass quickly during an exceptional condition to the place most appropriate for controlling it. The use of null flags, on the other hand, limits control flow to the ordinary paths of method invocation and return (until the whole program crashes, of course). Additionally, by using null flags in this way, the programmer effectively buries the evidence of where the exceptional condition occurred. Who knows how far that null pointer was passed from method to method before it was ever dereferenced? This simply makes it harder to diagnose errors and determine how to fix them. Experience has shown that code breaks often. Our primary concern should be to avoid such obfuscation and make diagnosis as easy as possible. Therefore, as a matter of principle, I strive to write code that signals exceptional conditions as soon as possible and attempts to recover only from exceptional conditions that do not indicate bugs in the program.

Even if you try to avoid using null flags in your own code, you will inevitably have to deal with legacy code that uses them. In fact, many of the Java library classes themselves, such as the Hashtable class and the BufferedReader class that we used above, use null flags. When using such classes, you can avoid bugs by explicitly checking whether an operation will return null before performing it. For example, with Hashtables, I always test with containsKey before calling get. But, even with such preventative measures, this bug pattern is one of the most common patterns encountered.

Here's the breakdown of this week's bug pattern:

  • Pattern: Null Flag
  • Symptoms: A code block that uses null pointers as flags for exceptional conditions is signalling a NullPointerException.
  • Cause: The calling methods are not checking for null pointers as return values.
  • Cures and preventions: Throw exceptions to signal exceptional conditions.

In the next article, I will discuss bug patterns related to class cast exceptions.


Resources

  • Be sure to read Eric Allen's previous Diagnosing Java Code columns on bug patterns:

  • One way to prevent inconsistent handling of exceptional conditions is aspect-oriented programming: a style of programming that modularizes the parts of a program that ordinarily cut across module boundaries. Check out AspectJ, an aspect-oriented extension of the Java language, with an implementation that supports many popular Java IDEs.

  • An approach to statically determining possible null-pointer exceptions is a technique known as set-based analysis. The Carnegie Mellon School of Computer Science Web site provides a short introduction to this approach, along with links to several technical publications on the topic.

  • The Division of Software Engineering at DePaul University has done some work on automated theorem provers to detect null-pointer exceptions in Java code.

  • Visit the Patterns Home Page for a good introduction to design patterns and how they are used.

  • Check out JUnit and catch more errors by making your code "test-infested."

About the author

Eric Allen has an A.B. in computer science and mathematics from Cornell University. He is currently the lead Java software developer at Cycorp, Inc., and a part-time graduate student in the programming languages team at Rice University. His research concerns the development of formal semantic models and extensions of the Java language, both at the source and bytecode levels. Currently, he is implementing a source-to-bytecode compiler for the NextGen programming language, an extension of the Java language with generic run-time types.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=10520
ArticleTitle=Diagnosing Java Code: The Null Flag bug pattern
publish-date=03012001
author1-email=
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).