Contents

Exception Handling in Java with Code Examples

Written by: David Vlijmincx

Introduction

Using try-catch blocks and exceptions, you can handle failures that occur during runtime. While some methods require explicit exception handling, others can be handled differently.

Creating Methods that Throw Exceptions

Methods that can throw checked exceptions must declare this using the throws keyword. The following example shows two methods one that doesn't declare and exception but can still throw a runtime exception. The other method declares a checked exception. The user of that method needs to handle it.

1
2
3
4
5
6
7
public void update(String name, String userId) {
    // This method doesn't declare any exceptions
}

public void update(String name, String userId) throws Exception {
    // This method declares it can throw a SQLException
}

When calling a method that throws a checked exception, you'll get a compilation error if you don't handle it:

1
2
3
4
5
6
7
8
9
// This won't compile without exception handling
update("John Doe", "USER123");

// This will compile and work
try {
    update("John Doe", "USER123");
} catch (Exception e) {
    // Handle the exception
}

Throwing Exceptions inside Constructors

Constructors can throw exceptions, which is useful for validating object during creation. Here's an example that validates a username during object instantiation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class User { 
    String name;
    
    public User(String name) {

    if (name == null || name.isEmpty()) {
        throw new IllegalArgumentException("Name cannot be null or empty");
    }

    this.name = name;

    }
}

Basic Exception Handling with Try-Catch

The standard way to handle exceptions in Java is using try-catch blocks. The following example shows you how to use the try statement.

1
2
3
4
5
try{
    new User("name");
} catch (Exception e) {
    System.out.println("e.getMessage() = " + e.getMessage());
}

Handling Specific Exception Types

You can catch different types of exceptions separately. This approach is useful when a method might throw multiple exception types. Here's an implementation where the User constructor could throw both IllegalArgumentException and ValidationException exceptions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static class ValidationException extends RuntimeException {}

class User {
    String name;

    public User(String name) {

        if (name == null || name.isEmpty()) {
            throw new IllegalArgumentException("Name cannot be null or empty");
        }

        if (name.length() > 20) {
            throw new ValidationException();
        }

        this.name = name;

    }
}

public void main(String[] args) {

    try{
        new User("name");
    } catch (IllegalArgumentException e) {
        System.out.println("e.getMessage() = " + e.getMessage());
    } catch (ValidationException e) {
        System.out.println("e.getMessage() = other message" + e.getMessage());
    }

}

Combining catch statements

If the exception handling is the same for two or more exceptions you can use a pipe to combine these catch statements. The following example shows you how to improve the previous error handling.

1
2
3
4
5
try{
        new User("name");
    } catch (IllegalArgumentException | ValidationException e) {
        System.out.println("e.getMessage() = " + e.getMessage());
    }

Using Optional to Avoid using Exceptions

In some cases you can prevent having to use exceptions. For example when looking for a user you could use Optional to know if a user was found or not.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {
    
    UserService userService = new UserService();
    userService.findUserSafely("USER123")
            .ifPresent(user -> System.out.println("name"));
    
}

public class UserService {
    public Optional<User> findUserSafely(String userId) {
        try {
            User user = findUser(userId);
            return Optional.of(user);
        } catch (IllegalStateException e) {
            return Optional.empty();
        }
    }
}

Using RuntimeExceptions for Unchecked Exceptions

When you want to throw exceptions without forcing the caller to handle them, use RuntimeException. You also don't have to declare them in the signature of the method. So other developers won't immediately know that the method throws an exception. This is how you throw a runtime exception:

1
2
3
4
5
6
7
public User getUser(String userId) {
    if (userId == null) {
        throw new RuntimeException("UserId cannot be null");
    }
     
    // ... your code
}