Pinterest Stumbleupon Whatsapp
Advertisement

As a programming newbie How To Learn Programming Without All The Stress How To Learn Programming Without All The Stress Maybe you've decided to pursue programming, whether for a career or just as a hobby. Great! But maybe you're starting to feel overwhelmed. Not so great. Here's help to ease your journey. Read More , the concept of exception handling can be tough to wrap your head around. Not that the concept itself is difficult, but the terminology can make it seem more advanced than it is. And it’s such a powerful feature that it’s prone to misuse and abuse.

In this article, you’ll learn what exceptions are, why they’re important, how to use them, and common mistakes to avoid. Most modern languages 6 Easiest Programming Languages to Learn for Beginners 6 Easiest Programming Languages to Learn for Beginners Learning to program is about finding the right language just as much as it's about the edification process. Here are the top six easiest programming languages for beginners. Read More have some kind of exception handling, so if you ever move on from Java 7 Useful Tricks for Mastering a New Programming Language 7 Useful Tricks for Mastering a New Programming Language It's okay to be overwhelmed when you are learning to code. You'll probably forget things as quickly as you learn them. These tips can help you to better retain all that new information. Read More , you can take most of these tips with you.

Understanding Java Exceptions

In Java, an exception is an object that indicates something abnormal (or “exceptional”) occurred during your application’s run. Such exceptions are thrown, which basically means an exception object is created (similar to how errors are “raised”).

The beauty is that you can catch thrown exceptions, which lets you deal with the abnormal condition and allow your application to continue running as if nothing went wrong. For example, whereas a null pointer in C might crash your application, Java lets you throw and catch NullPointerExceptions before a null variable has a chance to cause a crash.

Remember, an exception is just an object, but with one important characteristic: it must be extended from the Exception class or any subclass of Exception. While Java has all kinds of built-in exceptions, you can also create your own if you wish. Some of the most common Java exceptions include:

  • NullPointerException
  • NumberFormatException
  • IllegalArgumentException
  • RuntimeException
  • IllegalStateException

So what happens when you throw an exception?

First, Java looks within the immediate method to see if there’s code that handles the kind of exception you threw. If a handler doesn’t exist, it looks at the method that called the current method to see if a handle exists there. If not, it looks at the method that called that method, and then the next method, etc. If the exception isn’t caught, the application prints a stack trace and then crashes. (Actually it’s more nuanced than simply crashing, but that’s an advanced topic beyond this article’s scope.)

A stack trace is a list of all the methods that Java traversed while looking for an exception handler. Here’s what a stack trace looks like:

Exception in thread "main" java.lang.NullPointerException
  at com.example.myproject.Book.getTitle(Book.java:16)
  at com.example.myproject.Author.getBookTitles(Author.java:25)
  at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

We can glean a lot from this. First, the thrown exception was a NullPointerException. It occurred in the getTitle() method on line 16 of Book.java. That method was called from getBookTitles() on line 25 of Author.java. That method was called from main() on line 14 of Bootstrap.java. As you can see, knowing all of this makes debugging easier.

But again, the true benefit of exceptions is that you can “handle” the abnormal condition by catching the exception, setting things right, and resuming the application without crashing.

Using Java Exceptions in Code

Let’s say you have someMethod() that takes an integer and executes some logic that could break if the integer is less than 0 or greater than 100. This could be a good place to throw an exception:

public void someMethod(int value) {
  if (value < 0 || value > 100) {
    throw new IllegalArgumentException();
  }
  // ...
}

In order to catch this exception, you need to go to where someMethod() is called and use the try-catch block:

public void callingMethod() {
  try {
    someMethod(200);
    someOtherMethod();
  } catch (IllegalArgumentException e) {
    // handle the exception in here
  }
  // ...
}

Everything within the try block will execute in order until an exception is thrown. As soon as an exception is thrown, all subsequent statements are skipped and the application logic immediately jumps to the catch block.

In our example, we enter the try block and immediately call someMethod(). Since 200 isn’t between 0 and 100, an IllegalArgumentException is thrown. This immediately ends execution of someMethod(), skips the rest of the logic in the try block (someOtherMethod() is never called), and resumes execution within the catch block.

What would happen if we called someMethod(50) instead? The IllegalArgumentException would never be thrown. someMethod() would execute as normal. The try block would execute as normal, calling someOtherMethod() when someMethod() completes. When someOtherMethod() ends, the catch block would be skipped and callingMethod() would continue.

Note that you can have multiple catch blocks per try block:

public void callingMethod() {
  try {
    someMethod(200);
    someOtherMethod();
  } catch (IllegalArgumentException e) {
    // handle the exception in here
  } catch (NullPointerException e) {
    // handle the exception in here
  }
  // ...
}

Also note that an optional finally block exists as well:

public void method() {
  try {
    // ...
  } catch (Exception e) {
    // ...
  } finally {
    // ...
  }
}

The code within a finally block is always executed no matter what. If you have a return statement in the try block, the finally block is executed before returning out of the method. If you throw another exception in the catch block, the finally block is executed before the exception is thrown.

You should use the finally block when you have objects that need to be cleaned up before the method ends. For example, if you opened a file in the try block and later threw an exception, the finally block lets you close the file before leaving the method.

Note that you can have a finally block without a catch block:

public void method() {
  try {
    // ...
  } finally {
    // ...
  }
}

This lets you do any necessary cleanup while allowing thrown exceptions to propagate up the method invocation stack (i.e. you don’t want to handle the exception here but you still need to clean up first).

Checked vs. Unchecked Exceptions in Java

Unlike most languages, Java distinguishes between checked exceptions and unchecked exceptions (e.g. C# only has unchecked exceptions). A checked exception must be caught in the method where the exception is thrown or else the code won’t compile.

To create a checked exception, extend from Exception. To create an unchecked exception, extend from RuntimeException.

Any method that throws a checked exception must denote this in the method signature using the throws keyword. Since Java’s built-in IOException is a checked exception, the following code won’t compile:

public void wontCompile() {
  // ...
  if (someCondition) {
    throw new IOException();
  }
  // ...
}

You must first declare that it throws a checked exception:

public void willCompile() throws IOException {
  // ...
  if (someCondition) {
    throw new IOException();
  }
  // ...
}

Note that a method can be declared as throwing an exception but never actually throw an exception. Even so, the exception will still need to be caught or else the code won’t compile.

When should you use checked or unchecked exceptions?

The official Java documentation has a page on this question. It sums up the difference with a succinct rule of thumb: “If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.”

But this guideline may be outdated. On the one hand, checked exceptions do result in more robust code 10 Tips for Writing Cleaner & Better Code 10 Tips for Writing Cleaner & Better Code Writing clean code looks easier than it actually is, but the benefits are worth it. Here's how you can start writing cleaner code today. Read More . On the other hand, no other language has checked exceptions in the same manner as Java, which shows two things: one, the feature isn’t useful enough for other languages to steal it, and two, you can absolutely live without them. Plus, checked exceptions don’t play nicely with lambda expressions introduced in Java 8.

Guidelines for Java Exceptions Usage

Exceptions are useful but easily misused and abused. Here are a few tips and best practices to help you avoid making a mess of them.

  • Prefer specific exceptions to general exceptions. Use NumberFormatException over IllegalArgumentException when possible, otherwise use IllegalArgumentException over RuntimeException when possible.
  • Never catch Throwable! The Exception class actually extends Throwable, and the catch block actually works with Throwable or any class that extends Throwable. However, the Error class also extends Throwable, and you never want to catch an Error because Errors indicate serious unrecoverable issues.
  • Never catch Exception! InterruptedException extends Exception, so any block that catches Exception will also catch InterruptedException, and that’s a very important exception that you don’t want to mess with (especially in multi-threaded applications) unless you know what you’re doing. If you don’t know which exception to catch instead, consider not catching anything.
  • Use descriptive messages to ease debugging. When you throw an exception, you can provide a String message as an argument. This message can be accessed in the catch block using the Exception.getMessage() method, but if the exception is never caught, the message will also appear as part of the stack trace.
  • Try not to catch and ignore exceptions. To get around the inconvenience of checked exceptions, a lot of newbie and lazy programmers will set up a catch block but leave it empty. Bad! Always handle it gracefully, but if you can’t, at the very least print out a stack trace so you know the exception was thrown. You can do this using the Exception.printStackTrace() method.
  • Beware of overusing exceptions. When you have a hammer, everything looks like a nail. When you first learn about exceptions, you may feel obliged to turn everything into an exception… to the point where most of your application’s control flow comes down to exception handling. Remember, exceptions are meant for “exceptional” occurrences!

Now you should be comfortable enough with exceptions to understand what they are, why they’re used, and how to incorporate them into your own code. If you don’t fully understand the concept, that’s okay! It took me a while for it to “click” in my head, so don’t feel like you need to rush it 6 Signs That You Are Not Meant To Be A Programmer 6 Signs That You Are Not Meant To Be A Programmer Not everyone is cut out to be a programmer. If you aren't completely sure that you're meant to be a programmer, here are some signs that may point you in the right direction. Read More . Take your time.

Got any questions? Know of any other exception-related tips that I missed? Share them in the comments below!

Leave a Reply

Your email address will not be published. Required fields are marked *