The Either Class in Vavr
In this article, take a look at the Either class in Vavr.
Join the DZone community and get the full member experience.Join For Free
Vavr library is an excellent tool to make your Java code really functional. One of the issues that was not solved by Java itself is an error handling – the language relies on exceptions, although it is not purely functional pattern. As a counterpart, Vavr brings such types as
Either, that implement functional concepts. In this post, I would like to share with you the
Either class, that offers a predictable return type for methods, that possibly can result into errors. This type makes your codebase more lightweight, that if you will invent your own return types. From the other side, it makes your code more unified and maintainable. Finally, the
Either class brings a number of useful methods.
An Idea Behind the Either Type
The traditional Java approach (and C++ too) for error handling is based on exceptions. However, if we will investigate how it is done in functional programming languages, we will find out, that exceptions are not a natural model for them. Moreover, an another Java problem is that it limits you with a single return type – and that issue forces us to “invent” return types like
OperationResut<T> (an example name), that can contain information about success scenario (returned object) and information about failure scenario (usually throwable). Once we obtain a value, we test it – likewise it is implemented by Vertx:
As you can note, that is a mixture of functional and imperative styles. Yes, this pattern avoids a try-catch error handling and allows us to supply a richer information about an error, but it is not yet 100% functional. And this can be solved using an either type.
From a technical point of view, either is a container, that can hold two values – one for successful result and one for failed result. Imagine, that you write a code, that deals with file reading – you use a file service abstraction, that your colleague wrote for you. You don’t need to know how it works, you just call a method, that returns a content of the file. Yet, you know, that it may throw an exception, if file does not exist. Take a look on the following code snippet:
Imagine, that in future, the technical design will require the
FileReadService to determine also other error cases. The number of
catch clauses with increase… With
Either type you can refactor this code as following:
This style helps you not only to eliminate try-catch blocks, but also to specify a single entry point for all errors to make them to recover from a cache. An another case of using the
Either type can be a validation. As it was mentioned, with the
Either you can provide a detailed feedback of validation errors:
Advantages of the
Either class before your own return types are straightforward:
- You don’t need to create different return types for each occasion, so you code will become more lightweight
- Either makes your codebase more unified and mantainable
- Either class includes a number of useful methods, which incorporate it into functional pipelines
Let now move to practice.
How to Map Results
We have already defined, that in a nutshell,
Either is a container. It has two fields – left value and right value, however the idea is that
Either holds only one value, and never both (that is why it called either). Conventionally, values are defined as:
- Left value = a failure case result
- Right value = a success case result
Either has numerous useful methods, that fit it into a functional pipeline; and mapping is one of them. You can map a right value and do something with it. It is done using the
map() method. Imagine, you work with on a function, that takes a list of students in a class (we don’t care how it is implemented, as we have an abstraction), and then you can build a pipeline, that filters only students with a good academic standing:
Either considers a right value as successful outcome, therefore, the
map() method accesses the right value. You can explicitly map the left value with a
mapLeft() method. We can chain several map methods, so in order to get an average GPA score in a class we:
- Map each student entity as his/her GPA score
- Use a built-in function
average()from a Vavr
Take a look on the code snippet below:
Please note, that here I sticked with
BigDecimal, as I don’t like doubles, and actually it is a good design practice to avoid them in precise computations. So, as the result of the
average() method is actually an
Option, we additionally convert it to a BigDecimal. I use
getOrElse() method, which allows to specify an alternative value, in case the list is empty.
Validate Results With Filter()
An another thing that makes this type special, is that you could not only to map a right result, but you can also do an assertion of it. There is a method
filter(), that takes a logical condition (predicate) to validate a right value.
In this code we did actually same thing, yet we have moved a list checking to
Either. The result of this operation return the
Option instance, so we need to call the
get() first, in order to access the either. Because we already did a result checking with the
filter() method, we don’t need to use
getOrElse() to provide an alternative result.
Other Notable Methods
Either ‘s functionality is not limited to what we have reviewed so far. There are other methods, that make our developer life easier. In this section we will briefly sum them up:
peek()= this method executes a
Consumerfunction on the right value, but does not modify it, like
map()(there is also
peekLeft()method for a left case)
sequence()= if you have a sequence of
Either, this method reduces them into a single
Eitherinstance. The result is
Eitherthat holds sequences for left and right values of all members
swap()= you can swap a left and a right value, so
You can find a source code for this post as a part of this GitHub repository.
In this post we reviewed the
Either class from the Vavr library. Basically, it is a container, that can hold a success or a failure result, but not both. This is a concept, originated from functional languages and solves an error handling without try-catch blocks (which is an imperative pattern). We observed how this type works and how to use it to filter or map results. Finally, we listed other useful methods, that are offered by this class.
Published at DZone with permission of Yuri Mednikov. See the original article here.
Opinions expressed by DZone contributors are their own.