DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Java Thread Synchronization and Concurrency Part 1
  • Java EE 6 Pet Catalog with GlassFish and MySQL
  • Java Module Benefits With Example
  • Create a Multi-Tenancy Application in Nest.js, Part 4: Authentication and Authorization Setup

Trending

  • Exploring Intercooler.js: Simplify AJAX With HTML Attributes
  • Security by Design: Building Full-Stack Applications With DevSecOps
  • IoT and Cybersecurity: Addressing Data Privacy and Security Challenges
  • How GitHub Copilot Helps You Write More Secure Code
  1. DZone
  2. Data Engineering
  3. Data
  4. Ignoring Exceptions in Java

Ignoring Exceptions in Java

In this article, a developer walks us through how to go about ignoring checked exceptions in Java. Read on to learn more!

By 
Rainer Hahnekamp user avatar
Rainer Hahnekamp
·
May. 23, 18 · Tutorial
Likes (32)
Comment
Save
Tweet
Share
37.1K Views

Join the DZone community and get the full member experience.

Join For Free

In this article, I show how to ignore checked exceptions in Java. I will start by describing the rationale behind it and the common pattern to resolve this issue. Then I will present some libraries for that purpose.

Checked and Unchecked Exceptions

In Java, a method can force its caller to deal with the occurrence of potential exceptions. The caller can use the try/catch clause, where the try contains the actual code and catch contains the code to execute when the exception occurs.

Alternatively, the caller can pass on that burden to its "parent caller." This can go upwards until the main method is reached. If the main method also passes on the exception, the application will crash when an exception happens.

In the case of an exception, there are many scenarios where the application cannot continue to run and needs to stop. There are no alternative paths. Unfortunately, that means Java forces us to write code for a situation where the application shouldn't run anymore. Quite useless!

An option is to minimize that boilerplate code. We can wrap the exception into a RuntimeException, which is an unchecked exception. This has the effect that, even though the application still crashes, we don’t have to provide any handling code.

By no means do we log the exception and let the application continue like nothing has happened. It is possible, but similar to opening Pandora's Box.

When we call exceptions we have to write extra code for "checked exceptions," and the other ones of type RuntimeException "unchecked exceptions."

Checked and Unchecked Exceptions

Why Checked Exceptions at All?

We can find lots of checked exceptions in third-party libraries and even in the Java Class Library itself. The reason is quite obvious. A library vendor cannot predict in which context the developer will use their code.

Logically, they don’t know if our application has alternative paths. So they leave the decision to us. Their responsibility is to "label" methods that can potentially throw exceptions. Those labels give us the chance to implement counter-actions.

A good example is the connection to a database. The library vendor marks the connection retrieval method with an exception. If we use the database as a cache, we can send our queries directly to our primary database. This is the alternative path.

If our database is not the cache, there is no way the application can continue to run. And it’s OK if the application crashes:

Image title

A Lost Database Connection

Let’s put our theoretical example to real code:

public DbConnection getDbConnection(String username, String password) {
  try {
    return new DbProvider().getConnection(username, password);
  } catch (DbConnectionException dce) {
    throw new RuntimeException(dce);
  }
}

The database is not used as cache. In the event of a lost connection, we need to stop the application at once.

As described above, we wrap the DbConnectionException into a RuntimeException.

The required code is relatively verbose and always the same. This creates lots of duplication and decreases the readability.

The RuntimeException Wrapper

We can write a function to simplify this. It should wrap a RuntimeExceptionover some code and return the value. We cannot simply pass code in Java. The function must be part of a class or interface. Something like this:

public interface RuntimeExceptionWrappable<T> {
  T execute() throws Exception;
}

public class RuntimeExceptionWrapper {
  public static <T> T wrap(RuntimeExceptionWrappable<T> runtimeExceptionWrappable) {
    try {
      return runtimeExceptionWrappable.execute();
    } catch (Exception exception) {
      throw new RuntimeException(exception);
    }
  }
}

public class DbConnectionRetrieverJava7 {
  public DbConnection getDbConnection(final String username, final String password) {
    RuntimeExceptionWrappable<DbConnection> wrappable = new RuntimeExceptionWrappable<DbConnection>() {
      public DbConnection execute() throws Exception {
        return new DbProvider().getConnection(username, password);
      }
    };
    return RuntimeExceptionWrapper.wrap(wrappable);
  }
}

The RuntimeException wrapping has been extracted into its own class. In terms of software design, this might be the more elegant solution. Still, given the amount of code, we hardly can say the situation got better.

With Java 8 lambdas, things got easier. If we have an interface with one method only, then we just write the specific code of that method. The compiler does the rest for us. The unnecessary or "syntactic sugar code" to create a specific or anonymous class is not required anymore. That’s the basic use case for lambdas.

In Java 8, our example above looks like:

@FunctionalInterface
public interface RuntimeExceptionWrappable<T> {
  T execute() throws Exception;
}

public class DbConnectionRetrieverJava8 {
  public DbConnection getDbConnection(String username, String password) {
    return RuntimeExceptionWrapper.wrap(() ->
      new DbProvider().getConnection(username, password));
  }
}

The difference is quite obvious. The code is more concise.

Exceptions in Streams & Co.

RuntimeExceptionWrappable is a very generic interface. It is just a function that returns a value. Use cases for that function, or its variations, appear all over. For our convenience, Java‘s Class Library has a set of such common interfaces built-in. They are in the package java.util.function  and are better known as the "Functional Interfaces." Our RuntimeExceptionWrappable is similar to java.util.function.Supplier.

These interfaces form the prerequisite of the powerful Stream, Optional, and other features which are also part of Java 8. In particular, Stream comes with a lot of different methods for processing collections. Many of these methods have a “Functional Interface” as a parameter.

Let’s quickly switch the use case. We have a list of URL strings that we want to map into a list of objects of type java.net.URL.

The following code does not compile:

public List<URL> getURLs() {
  return Stream
    .of("https://www.hahnekamp.com", "https://www.austria.info")
    .map(this::createURL)
    .collect(Collectors.toList());
}

private URL createURL(String url) throws MalformedURLException {
  return new URL(url);
}

There is a big problem when it comes to exceptions. The interfaces defined in java.util.function don't throw exceptions. That's why our method createURL doesn’t have the same signature as java.util.funcion.Function, which is the parameter of the map method.

What we can do is to write the try/catch block inside the lambda:

public List<URL> getURLs() {
  return Stream
    .of("https://www.hahnekamp.com", "https://www.austria.info")
    .map(url -> {
      try {
        return this.createURL(url);
      } catch (MalformedURLException e) {
        throw new RuntimeException(e);
      }
    })
    .collect(Collectors.toList());
}

This compiles but doesn't look nice either. We can now take a step further and write a wrapper function along a new interface similar to RuntimeExceptionWrappable:

@FunctionalInterface
public interface RuntimeWrappableFunction<T, R> {
 R apply(T t) throws Exception;
}

public class RuntimeWrappableFunctionMapper {
 public static <T, R> Function<T, R> wrap(
   RuntimeWrappableFunction<T, R> wrappable) {
   return t -> {
     try {
       return wrappable.apply(t);
     } catch(Exception exception) {
       throw new RuntimeException(exception);
     }
   };
  }
}

And apply it to our Stream example:

public List<URL> getURLs() {
  return Stream
    .of("https://www.hahnekamp.com", "https://www.austria.info")
    .map(RuntimeWrappableFunctionMapper.wrap(this::createURL))
    .collect(Collectors.toList());
}

private URL createURL(String url) throws MalformedURLException {
  return new URL(url);

Great! Now we have a solution, where we can:

  • Run code without catching checked exceptions.

  • Use exception-throwing lambdas in Stream, Optional, etc.

SneakyThrow to Help

The SneakyThrow library lets you skip copying and pasting the code snippets from above. Full disclosure: I am the author.

SneakyThrow comes with two static methods. One runs code without catching checked exceptions. The other method wraps an exception-throwing lambda into one of the Functional Interfaces:

//SneakyThrow returning a result
public DbConnection getDbConnection(String username, String password) {
  return sneak(() -> new DbProvider().getConnection(username, password));
}

//SneakyThrow wrapping a function
public List<URL> getURLs() {
  return Stream
   .of("https://www.hahnekamp.com", "https://www.austria.info")
   .map(sneaked(this::createURL))
   .collect(Collectors.toList());
}

Alternative Libraries

ThrowingFunction

//ThrowingFunction returning a result
public DbConnection getDbConnection(String username, String password) {
  return unchecked(() -> 
       new DbProvider().getConnection(username, password))
    .get();
}

//ThrowingFunction returning a function
public List<URL> getURLs() {
  return Stream
    .of("https://www.hahnekamp.com", "https://www.austria.info")
    .map(unchecked(this::createURL))
    .collect(Collectors.toList());
}

In contrast to SneakyThrow, ThrowingFunction can't execute code directly. Instead, we have to wrap it into a Supplier and call the Supplier afterward. This approach can be more verbose than SneakyThrow.

If you have multiple unchecked  Functional Interfaces in one class, then you have to write the full class name with each static method. This is because unchecked does not work with method overloading.

On the other hand, ThrowingFunction provides you with more features than SneakyThrow. You can define a specific exception you want to wrap. It is also possible that your function returns an Optional, aka "lifting."

I designed SneakyThrow as an opinionated wrapper of ThrowingFunction.

Vavr

Vavr, aka JavaSlang, is another alternative. In contrast to SneakyThrow and ThrowingFunction, it provides a complete battery of useful features that enhance Java’s functionality.

For example, it comes with pattern matching, tuples, an own Stream and much more. If you haven't heard of it, it is definitely worth a look. Prepare to invest some time in order to understand its full potential.

//Vavr returning a result
public DbConnection getDbConnection(String username, String password) {
  return Try.of(() -> 
    new DbProvider().getConnection(username, password))
    .get();
}

//Vavr returning a function
public List<URL> getURLs() {
  return Stream
    .of("https://www.hahnekamp.com", "https://www.austria.info")
    .map(url -> Try.of(() -> this.createURL(url)).get())
    .collect(Collectors.toList());
}

Project Lombok

Such a list of libraries is not complete without mentioning Lombok. Like Vavr, it offers much more functionality than just wrapping checked exceptions. It is a code generator for boilerplate code and creates full Java Beans, Builder objects, logger instances, and much more.

Lombok achieves its goals by bytecode manipulation. Therefore, we require an additional plugin in our IDE.

@SneakyThrows is Lombok’s annotation for manipulating a function with a checked exception into one that doesn’t. This approach doesn’t depend on the usage of lambdas, so you can use it for all cases. It is the least verbose library.

Please keep in mind that Lombok manipulates the bytecode which can cause problems with other toolings you might use.

//Lombok returning a result
@SneakyThrows
public DbConnection getDbConnection(String username, String password) {
  return new DbProvider().getConnection(username, password);
}

//Lombok returning a function
public List<URL> getURLs() {
  return Stream
    .of("https://www.hahnekamp.com", "https://www.austria.info")
    .map(this::createURL)
    .collect(Collectors.toList());
}

@SneakyThrows
private URL createURL(String url) {
  return new URL(url);
}

Further Reading

The code is available on GitHub.

Java (programming language) Database connection application Library Interface (computing)

Published at DZone with permission of Rainer Hahnekamp. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Java Thread Synchronization and Concurrency Part 1
  • Java EE 6 Pet Catalog with GlassFish and MySQL
  • Java Module Benefits With Example
  • Create a Multi-Tenancy Application in Nest.js, Part 4: Authentication and Authorization Setup

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!