11 Mistakes JAVA Developers make when using EXCEPTIONS

The problem: If you use Exceptions in the wrong way, bugs will be very difficult to find. If you always use generic Exceptions, how can other developers know what error has occurred? You have to understand why we use Exceptions and how to use them effectively!

See the 11 mistakes Java Developers make when using Exceptions.

First, let’s see the hierarchy of the Exception classes.

Checked Exceptions / Unchecked Exceptions

1 – Using only the Exception class

It’s a common mistake that developers specifically catch the Exception class for any error. It’s much more difficult to identify the error if you see only an Exception being caught. The solution to this problem is to create specific Exceptions – but watch out, not too specific!

2 – Creating lots of specific Exceptions

Don’t create Exceptions for everything. Your application will be full of classes, useless repetition and you will create unnecessary work. Instead, create Exceptions for really important business requirements. For example, if you are developing a bank system one possible Exception would be when trying to withdraw money and the balance is zero: BalanceNotAvailableException. Another Exception would be transferring money to another person and the account does not exist, you can create: BankAccountNotFoundException and show an understandable Exception message to the user.

RuntimeException could be used when the bank’s server is out of service. Here you can use, for example: ServerNotAvailableException. The system must crash for this kind of error. There is no recovery.

3 – Creating a log for every catch

Logging every Exception catch will pollute your code. To prevent this, just log once and throw your Exception in the last catch. You won’t lose your Stacktrace if you wrap the Exception. If you are working with web applications, you should create a catch on your controller layer and log the error.

4 – Not knowing the difference between Checked and Unchecked Exceptions

When should Checked Exceptions be used? Use Checked when there is a recoverable error or an important business requirement.

The most common Checked Exception is the Exception class. Two related classes from Exception are FileNotFoundException and SQLException.You are obligated to handle or declare these exceptions. You must throw or catch the Exception or else it won’t compile.

When should Unchecked Exceptions be used? Use Unchecked when there is no recovery. For example, when the memory of the server is overused.

RuntimeException is used for errors when your application can not recover. For example, NullPointerException and ArrayOutOfBoundsException. You can avoid a RuntimeException with an ‘if’ command. You should not handle or catch it.

There is also the class Error. It is an Unchecked Exception too. Never try to catch or handle this kind of Exception. They are errors from the JVM and are the most serious kind of Exception in Java. You must analyze the cause of Exceptions like this and change your code.

5 –  Silencing Exceptions

Never catch the Exception and do nothing, for example:

1
2
3
4
5
try {
    System.out.println("Never do that!");
} catch (AnyException exception) {
    // Do nothing
}

The catch will be useless. It’s impossible to know what happened and the Exception will be silenced. The developer will be obliged to debug the code and see what happened. If we create a good log, the time-consuming analysis won’t be necessary.

6 – Not following the principle “throw early, catch late”

If you have to handle Exception, for example, in your Service, you should do two things:

  1. Wrap your Exception
  2. Throw the Exception to the last catch and handle it.

7 – Not using clear messages on the Exceptions

Always use clear messages on your Exceptions. Doing this will help a lot when finding errors. Even better, create a Properties File with all Exception messages. You can use the file on your View layer and show users messages about the business requirements.

8- Not cleaning up after handling the Exception

After using resources like files and database connection, clean them and close them so that you won’t harm the system’s performance. You can use the finally block to do it.

9 – Not documenting Exceptions with javadoc

To avoid headaches, always Document why the Exception is being thrown in your method. Document your Exception and explain why you created it.

10 – Never lose the Stacktrace

When wrapping an Exception in another one, don’t just throw the other Exception, keep the Stacktrace.

Bad code:

1
2
3
4
5
try {
    // Do the logic
} catch (BankAccountNotFoundException exception) {
    throw new BusinessException();
}

Good code:

1
2
3
4
5
try {
    // Do the logic
} catch (BankAccountNotFoundException exception) {
    throw new BusinessException(exception);
}

11 – Not organizing the hierarchy of specific Exceptions

If you don’t organize the hierarchy of your Exceptions, the relationship will be difficult between the parts of the system. You will have lots of problems.

You should use an hierarchy similar to this one:

Exception

BusinessException

AccountingException

HumanResourcesException
BillingCodeNotFoundException

  EmployeeNotFoundException

Exceptions and Assertions

Handling Exceptions:

  • Exceptions come in two flavors: checked and unchecked.
  • Checked exceptions include all subtypes of exception, excluding the classes that extend Runtime exception.
  • Checked exceptions are subject to the handle or declare rule: any method that might throw a checked exception (including methods that invoke methods that can through a checked exception) must either declare the exception using throws, or handle the exception with an appropriate try/catch block.
  • Subtypes of error and Runtime Exceptions are unchecked.so the compiler dosent enforce the handle or declare rule, you are free to handle them, or to declare them, but the compiler dosent care one way or the other.
  • If you us optional finally block, it will always be invoked, regardless of whether an exception in the corresponding try is thrown or not, and regardless of whether a thrown exception is caught or not.
  • The only exception to the finally will always be called rule is that a finally will not be invoked if the JVM shuts down. That could happen if code from try or catch block calls system.exit();
  • Just because of finally is invoked does not mean it will complete. Code in finally block could itself raise exception or issue a system.exit().
  • Uncaught exceptions propagate back through the call catch, starting from the method where the exception is thrown and ending with either the first method that has a corresponding catch for that exception type or a JVM shutdown (which happens if the exception gets to main(), and main() is “ducking” the exception by declaring it).
  • You can create your exception, normally by extending Exception or one of its subtypes, your exception will be considered a checked exception, and the compiler will enforce the handle or declare a rule for that exception.
  • All catch blocks must be ordered from most specific to most general.
  • If you have catch clause for both IOException and
    Exception you must put the catch for IOException first in your code otherwise the IOException would be caught by catch (Exception e), because a catch argument can catch the specified exception or any of its subtypes the same exceptions are created by programmers, same by the JVM.

Working with the Assertion Mechanism:

  • Assertion gives a way to test your assumptions during development and debugging.
  • Assertions are typically enables during testing but disables during deployment.
  • You can use assert as a key word (as of version 1.4) or an identifier, but not both together. To compile older code that use assert as an identifier ( for example, a method name) , uses the -source 1.3 command line flag to javac.
  • Assertions are disabled at runtime by default. To enable them, use a command line flaf –ea of –enableassertions.
  • Selectively disable assertions by using the –da or –disableassertions.
  • If you enable or disable assertions using the flag without any arguments, you are enabling or disabling assertions in general, you can combine enabling and disabling switched to have assertions enabled for classes and /or packages, but not other.
  • You can enable and disable assertions on a class-by-class using the following syntax.

Java –ea –aMyClass TestClass

  • You can enable and disable assertions on a package-by-package basis , an a any package you specify also includes any sub package(packages further down the directory hierarchy)
  • Do not use assertions to validate arguments to public methods.
  • Do not uses assert expressions that cause side effects? Assertions aren’t guaranteed to always run, and you don’t want behavior that changes depending weather assertion are enabled.
  • Do not use assertions even in public methods to validate that a particular code block will never be reached.
  • You can use assert false; for code that should never be reached, so that an assertion error is thrown immediately if the assert statement is executed.

Difference Between NoClassDefFoundError And ClassNotFoundException

ClassNotFoundException and NoClassDefFoundError occur when a particular class is not found at runtime. However, they occur at different scenarios.

ClassNotFoundException is an exception that occurs when you try to load a class at run time using Class.forName() or loadClass() methods and mentioned classes are not found in the classpath.

NoClassDefFoundError is an error that occurs when a particular class is present at compile time, but was missing at run time.

ClassNotFoundException

ClassNotFoundException is a runtime exception that is thrown when an application tries to load a class at runtime using the Class.forName() or loadClass() or findSystemClass() methods ,and the class with specified name are not found in the classpath. For example, you may have come across this exception when you try to connect to MySQL or Oracle databases and you have not updated the classpath with required JAR files. Most of the time, this exception occurs when you try to run an application without updating the classpath with required JAR files.

For example, the below program will throw ClassNotFoundException if the mentioned class “oracle.jdbc.driver.OracleDriver” is not found in the classpath.

public class MainClass {
   public static void main(String[] args){
   try {
      Class.forName("oracle.jdbc.driver.OracleDriver");
      } catch (ClassNotFoundException e){
                  e.printStackTrace();
      }
   }
}

If you run the above program without updating the classpath with required JAR files, you will get an exception akin to:

java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at pack1.MainClass.main(MainClass.java:17)

NoClassDefFoundError

NoClassDefFoundError is an error that is thrown when the Java Runtime System tries to load the definition of a class, and that class definition is no longer available. The required class definition was present at compile time, but it was missing at runtime. For example, compile the program below.

class A {
 // some code
}
 
public class B {
 public static void main(String[] args) {
  A a = new A();
 }
}

When you compile the above program, two .class files will be generated. One is A.class and another one is B.class. If you remove the A.class file and run the B.class file, Java Runtime System will throw NoClassDefFoundError like below:

Exception in thread "main" java.lang.NoClassDefFoundError: A
at MainClass.main(MainClass.java:10)
Caused by: java.lang.ClassNotFoundException: A
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

Recap

ClassNotFoundException NoClassDefFoundError
It is an exception. It is of type java.lang.Exception. It is an error. It is of type java.lang.Error.
It occurs when an application tries to load a class at run time which is not updated in the classpath. It occurs when java runtime system doesn’t find a class definition, which is present at compile time, but missing at run time.
It is thrown by the application itself. It is thrown by the methods like Class.forName(), loadClass() and findSystemClass(). It is thrown by the Java Runtime System.
It occurs when classpath is not updated with required JAR files. It occurs when required class definition is missing at runtime.