Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

This noncompliant code example defines an isName() method that takes a String argument and returns true if the given string is a valid name. A valid name is defined as two capitalized words separated by one or more spaces. Rather than checking to see whether the given string is null, the method catches NullPointerException and returns false.

Code Block
bgColor#ffcccc

boolean isName(String s) {
  try {
    String names[] = s.split(" ");

    if (names.length != 2) {
      return false;
    }
    return (isCapitalized(names[0]) && isCapitalized(names[1]));
  } catch (NullPointerException e) {
    return false;
  }
}

...

This compliant solution explicitly checks the String argument for null rather than catching NullPointerException.

Code Block
bgColor#ccccff

boolean isName(String s) {
  if (s == null) {
    return false;
  }
  String names[] = s.split(" ");
  if (names.length != 2) {
    return false;
  }
  return (isCapitalized(names[0]) && isCapitalized(names[1]));
}

...

This compliant solution omits an explicit check for a null reference and permits a NullPointerException to be thrown.

Code Block
bgColor#ccccff

boolean isName(String s) /* throws NullPointerException */ {
  String names[] = s.split(" ");
  if (names.length != 2) {
    return false;
  }
  return (isCapitalized(names[0]) && isCapitalized(names[1]));
}

...

This noncompliant code example is derived from the logging service null object design pattern described by Henney [Henney 2003]. The logging service is composed of two classes: one that prints the triggering activity's details to a disk file using the FileLog class and another that prints to the console using the ConsoleLog class. An interface, Log, defines a write() method that is implemented by the respective log classes. Method selection occurs polymorphically at runtime. The logging infrastructure is subsequently used by a Service class.

Code Block
bgColor#FFcccc

public interface Log {
  void write(String messageToLog);
}

public class FileLog implements Log {
  private final FileWriter out;

  FileLog(String logFileName) throws IOException {
    out = new FileWriter(logFileName, true);
  }

  public void write(String messageToLog) {
    // write message to file
  }
}

public class ConsoleLog implements Log {
  public void write(String messageToLog) {
    System.out.println(messageToLog); // write message to console
  }
}

class Service {
  private Log log;

  Service() {
    this.log = null; // no logger
  }

  Service(Log log) {
    this.log = log; // set the specified logger
  }

  public void handle() {
    try {
      log.write("Request received and handled");
    } catch (NullPointerException npe) {
      // Ignore
    }
  }

  public static void main(String[] args) throws IOException {
    Service s = new Service(new FileLog("logfile.log"));
    s.handle();

    s = new Service(new ConsoleLog());
    s.handle();
  }
}

...

This compliant solution modifies the no-argument constructor of class Service to use the do nothing behavior provided by an additional class, Log.NULL; it leaves the other classes unchanged.

Code Block
bgColor#ccccff

public interface Log {

  public static final Log NULL = new Log() {
    public void write(String messageToLog) {
      // do nothing
    }
  };

  void write(String messageToLog);
}

class Service {
  private final Log log;

  Service(){
    this.log = Log.NULL;
  }

  // ...
}

...

This noncompliant code example assumes that the original version of the division() method was declared to throw only ArithmeticException. However, the caller catches the more general Exception type to report arithmetic problems rather than catching the specific exception ArithmeticException type. This practice is risky because future changes to the method signature could add more exceptions to the list of potential exceptions the caller must handle. In this example, a revision of the division() method can throw IOException in addition to ArithmeticException. However, the compiler will not diagnose the lack of a corresponding handler because the invoking method already catches IOException as a result of catching Exception. Consequently, the recovery process might be inappropriate for the specific exception type that is thrown. Furthermore, the developer has failed to anticipate that catching Exception also catches unchecked exceptions.

Code Block
bgColor#FFcccc

public class DivideException {
  public static void division(int totalSum, int totalNumber)
    throws ArithmeticException, IOException  {
    int average  = totalSum / totalNumber;
    // Additional operations that may throw IOException...
    System.out.println("Average: " + average);
  }
  public static void main(String[] args) {
    try {
      division(200, 5);
      division(200, 0); // Divide by zero
    } catch (Exception e) {
      System.out.println("Divide by zero exception : " 
                         + e.getMessage());
    }
  }
}

...

This noncompliant code example attempts to solve the problem by specifically catching ArithmeticException. However, it continues to catch Exception and consequently catches both unanticipated checked exceptions and unanticipated runtime exceptions.

Code Block
bgColor#FFcccc

try {
  division(200, 5);
  division(200, 0); // Divide by zero
} catch (ArithmeticException ae) {
  throw new DivideByZeroException();
} catch (Exception e) {
  System.out.println("Exception occurred :" + e.getMessage());
}

...

This compliant solution catches only the specific anticipated exceptions (ArithmeticException and IOException). All other exceptions are permitted to propagate up the call stack.

Code Block
bgColor#ccccff

import java.io.IOException;

public class DivideException {
  public static void main(String[] args) {
    try {
      division(200, 5);
      division(200, 0); // Divide by zero
    } catch (ArithmeticException ae) {
      // DivideByZeroException extends Exception so is checked
      throw new DivideByZeroException();  
    } catch (IOException ex) {
      ExceptionReporter.report(ex);
    }
  }

  public static void division(int totalSum, int totalNumber)
                              throws ArithmeticException, IOException  {
    int average  = totalSum / totalNumber;
    // Additional operations that may throw IOException...
    System.out.println("Average: "+ average);
  }
}

...

Java SE 7 allows a single catch block to catch multiple exceptions of different types, which prevents redundant code. This compliant solution catches the specific anticipated exceptions (ArithmeticException and IOException) and handles them with one catch clause. All other exceptions are permitted to propagate to the next catch clause of a try statement on the stack.

Code Block
bgColor#ccccff

import java.io.IOException;

public class DivideException {
  public static void main(String[] args) {
    try {
      division(200, 5);
      division(200, 0); // Divide by zero
    } catch (ArithmeticException | IOException ex) {
      ExceptionReporter.report(ex);
    }
  }

  public static void division(int totalSum, int totalNumber)
                              throws ArithmeticException, IOException  {
    int average  = totalSum / totalNumber;
    // Additional operations that may throw IOException...
    System.out.println("Average: "+ average);
  }
}

...

ERR08-EX0: A catch block may catch all exceptions to process them before rethrowing them (filtering sensitive information from exceptions before the call stack leaves a trust boundary, for example). Refer to rulerule ERR01-J. Do not allow exceptions to expose sensitive information and weaknesses CWE 7 and CWE 388 for more information. In such cases, a catch block should catch Throwable rather than Exception or RuntimeException.

This code sample catches all exceptions and wraps them in a custom DoSomethingException before rethrowing them.

Code Block
bgColor#ccccff

class DoSomethingException extends Exception {
  public DoSomethingException(Throwable cause) {
    super(cause);
  }

  // other methods

};

private void doSomething() throws DoSomethingException {
  try {
    // code that might throw an Exception
  } catch (Throwable t) {
    throw new DoSomethingException(t);
  }
}

...

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ERR08-J

medium

likely

medium

P12

L1

 

      06. Exceptional Behavior (ERR)