Skip to main content
Our Hunters, technology trend hunters, never stop exploring. In this new edition of Inspiring Technology, they ask us if we're mishandling Java exceptions. Read on!
27/12/2023
inspiring

In current developments, it's very common for an exception to be thrown in the event of an error. Examples of this could include an unmet business validation, records not found in the database when accessed by their ID, and even third-party libraries.

Now, these exceptions may or may not be handled in the same class where they are thrown, and most often they aren't. It's even possible that, in a three-tier architecture, an exception thrown in the data access layer ends up being handled by the presentation layer, which breaks the pattern and creates coupling.

It's clear that exception handling, when used in this way, becomes a sophisticated GOTO and violates the principle of least astonishment , which states that a program's behavior should be obvious, consistent, and predictable. Even if we could break the dependency between layers through the use of Exception Translators, the underlying problem would still exist: the use of exceptions for something that isn't exceptional.

According to the original Oracle documentation:
 

inspiring

Therefore, exceptions are used to handle exceptional events. When an exception is thrown, is it an exceptional or a relevant event? What's the difference? A user enters data into a form and submits it. The data is validated on the server and determined to be incorrect. In this case, it's not that uncommon for a user to enter incorrect data, so it can't be considered an exception. However, if it is relevant to the system, then the user's operation cannot be allowed to continue.

Aside from what has been explained, and because exceptions are working as GOTOs, there is a small additional performance issue.

So…How do we solve these problems?

Vavr to the rescue

Vavr is a library that embraces the functional paradigm, which has been gradually gaining ground in Java since version 1.8, and allows exception handling as normal data types. It uses the concept of monads, which were introduced in Java 8 for data types such as Optional, Streams, and so on.

Vavr proposes the use of five types of base data:

inspiring

1. Either: Syntactically, it is a tuple of two values, Left and Right. Right is the value obtained from an operation, and Left is the value in case the operation has failed:

inspiring

2. Option: Similar to Java's Optional. Its added value is the ability to transform into an Either. Additionally, if a map is performed on a null value in Java 8's Optional, nothing would happen, as it would never be executed. In vavr's Option , a NullPointerException would occur. The Vavr developers consider this a correct adherence to the requirement that a .map operation executed on a Monad must maintain the computational context.

3. Try: It is a monadic type that represents the execution of an operation that can end in success or failure.

The toEither() method returns an Either where T is the type of the data returned by the failPruneMehtod.

It also allows you to implement a working version of a try-catch block.

 

inspiring
inspiring
inspiring

4. Validation: is an Applicative Functor that will allow the accumulation of errors from different functions.

A Validation object can be easily converted to Either by invoking the .toEither() method;

Seq is a Java data type that expresses a collection of values. It can be easily converted to a list using .toJavaList();

inspiring

5. Lazy: This is a monodic value that represents a value calculated lazily and only once. That is, once calculated, it always returns the same value.

inspiring

How does this apply to my project?

It is assumed that the data arriving at the business from a REST service must always be correct, or else execution will be interrupted.

inspiring

The creation of the user would be as follows:

inspiring

Finally, the UserRepository would implement the save as follows: 
 

inspiring

Okay, but… what about transactional processing?

There is now an enhancement that will allow Spring to integrate Vavr monad-based rollback control into its transactional behavior.

However, you can always make an Aspect to run rollback programmatically as needed.

inspiring

Main advantages

By programming in this way , not a single exception has been thrown despite all the validations that have been done when creating the different objects (CreateUserCommand, User…).

Any exceptions that may occur during database access have been taken into account using Try . These exceptions are then translated into Business Error objects.

If it were decided to move the exceptions within an Error object, there would be no problem in losing the Stack Trace, since it is data that is within the exception itself.

Additionally , there is the advantage that if there are several errors in the user's entered data, all of them will be returned , not just the error related to the first validation that is executed.

Finally, a fully functional approach is adopted, allowing for increased development speed.

Disadvantages

Most Java developers come from an imperative background, so they often struggle with properly adopting Vavr as a functional library . As we've seen, it requires a different way of structuring programs . However, this library can be used imperatively.

Adopting Vavr, on the other hand, requires a coupling with the library itself , as there are no interfaces or anything that can be used to "wrap" this functionality. Therefore, if you're going to use it, you must do so with a clear understanding of what it entails because, as we've seen, it modifies the structure of programs, whether they follow an imperative or declarative functional approach.

Want to know more about Hunters?
Being a Hunter means accepting the challenge of testing new solutions that deliver differentiated results. Join the Hunters program and become part of a cross-functional group capable of generating and transferring knowledge.

Get ahead of the digital solutions that will drive our growth. Find more information about Hunters on the website.


Want to know more about Hunters?

Being a Hunter means accepting the challenge of testing new solutions that deliver differentiated results. Join the Hunters program and become part of a cross-functional group capable of generating and transferring knowledge.

Get ahead of the digital solutions that will drive our growth. Find more information about Hunters on the website.