Handling Exceptions in Java

Photo by Waldemar on Unsplash

Handling Exceptions in Java

I needed a cleaner way of handling exceptions in Java. After doing some research, I discovered several approaches to help make code cleaner and more concise. Here is what I found:

1. Optional and orElseThrow() (Java 8+):

Using Optional along with orElseThrow() can handle exceptions in a more concise manner.

Example:

Optional<String> optionalValue = Optional.ofNullable(getValue());
String result = optionalValue.orElseThrow(() -> new NotFoundException("Value not found"));

2. CompletableFuture (Java 8+):

CompletableFuture allows handling exceptions in asynchronous programming scenarios using methods like exceptionally().

Example:

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    // Some computation that might throw an exception
});

Integer result = future.exceptionally(ex -> handleException(ex)).join();

3. Exception Handling with Streams (Java 8+):

Streams allow handling exceptions within stream operations using map() and filter() along with Optional.

Example:

List<String> values = Arrays.asList("1", "two", "3", "four");

List<Integer> integers = values.stream()
    .map(s -> {
        try {
            return Integer.parseInt(s);
        } catch (NumberFormatException e) {
            return null; // Or handle the exception here
        }
    })
    .filter(Objects::nonNull)
    .collect(Collectors.toList());

4. Using try-with-resources (Java 7+):

For handling resources that need to be closed automatically, use try-with-resources to avoid explicit catch blocks.

Example:

try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
    // Use the reader
} catch (IOException e) {
    // Handle exception
}

5. Functional Error Handling (Java 8+):

Functional libraries like Vavr or functional interfaces (Function, Supplier, etc.) often offer utilities for handling exceptions in a more functional style.

Example using Vavr:

Try<Integer> result = Try.of(() -> Integer.parseInt("123"));

As a side note, you can define custom unchecked exceptions (extending RuntimeException) to avoid the need for explicit catch blocks for certain exceptions. Also, favor unchecked exceptions over checked exceptions when possible to reduce boilerplate code.

Conclusion

The choice of exception handling method depends on the specific context, readability, and maintainability. Using these modern techniques can lead to cleaner and more expressive code, but the choice should be made based on the specific needs of the application and codebase.