in Coding

Anti Pattern: Don’t use Optionals for data repositories

Java 8 Optionals

Java 8 introduced a new feature call Optionals. Optionals are an easy way to force the caller of a method to deal with a possible null return value:

If you use an Optional as the return type of your method, whoever calls the method will be reminded that it might return null. If you use Optionals, you don’t need to think about NotFoundExceptions, special return types or JavaDoc comments which state that the method might return null. An Optional says more than a thousand comments!

Optionals might just postpone the problem

But an Optional doesn’t do one thing: it doesn’t answer the question what to do if there is no method result. It just postpones the problem to the caller. This might be OK if null is a quite expected result of the method, but in most cases null means something went wrong. Don’t postpone this!

An example

Nearly every application stores data. Whenever data is stored, it will be loaded again which might go wrong as the data simply couldn’t be found. That sounds like a good use case for Optionals! Let’s see how it could look like:

Nice! If there is no Person with the given ID the repository will return an empty Optional and the caller has to deal with it. Technically, this is a nice and clean solution. But from the business perspective it isn’t. The real question is: Can it happen that we look for an ID which is not present? If yes, than an Optional is a good solution, but I would doubt that in many case.

Whenever you attempt to load data by its ID, it must be present! There are hardly any cases where you guess or search for an ID. Such IDs are like references or pointers in a programming language: they must point to something and returning an ID which points to nothing is a very bad idea. A typical situation where you load data by its ID goes like this: You provide a list of data (maybe a result of a search) and you provide a detail view on a single entry. So, you show the list in your UI and on a click on of the elements, the details of ID XYZ-123 are shown. This set of data must be there! Don’t use an optional here!

Never return null

Back in the days (which means before Java 8), there was a rule which said that you shall never return null. This rule was always a bit tricky to follow as it might lead to a lot of hidden traps. People started to return empty objects, special objects, return codes and other crazy stuff. If you did this in the past and you are using Optionals now, you definitely improved! But you should still ask you, why there might be no result and if it is OK to have no result. Not only from a technical perspective but also from the business perspective.

Optional is just a new name for null.

When to use Optionals

The actual use case for Optionals is functional programming in Java 8. If you use this, you will filter, map or reduce data and you will often come to the point where there might be the possibility that no data exists. It’s a good idea to use Optionals here, as you often write this code in a fluent style. A null pointer is really ugly to handle here. But the main difference is another: You do a search or filtering which perfectly could have no result. This is the main point for using an Optional. Don’t use an Optional, because you don’t want to deal with null (you need to do it anyway later!), use it because you have a really good reason to return null.

Best regards,

Write a Comment


  1. Returning an optional in a repository is actually more common that you might think. For example when doing cross-table lookup (foreign keys anyone?).

    As an example, consider a table for storing books and another for storing the current borrower of the book. If someone wanted to borrow the book, Optionals come in handy if we wanted to check if someone has already borrowed the book. The borrower may or may not be present.

    This is a common practice these days that two tables are connected via a common column, so it is actually more common to use optionals for finding things in repositories.

    • Also your captcha thing is broken. It only allows 5 characters. I’m only able to post because I was lucky enough to refresh to a 5 digit captcha

      • First: I hate my captcha plugin. Really. I will get a new one. I promise.

        Second: I really like your example and I totally share your opinion. A book can be borrowed or not – that’s optional. Using an optional to represent this scenario is perfect. However, my thought was this: Let’s say you want to find a particular book. You have two ways. On way is searching for the book which might return no result (or many, depends on the actual implementation). The other way is to load the book from the repository by it’s ID. Imagine a list of books where the users clicks on one of the books to see a detail view. In this case it’s an error if the book doesn’t exist.

          • Yes. My whole point is this: Is it a valid outcome that the object is not found (or is it an error)?

            This is an error, because nobody will just randomly guess IDs and try to load them.

            But this is a perfectly valid outcome, because a search might just find nothing.

        • Let’s assume, user opened a product list page, and click the product link. It goes to the product view page which gets the product by ID and shows the details in the front-end. However, while a user clicking the link, or he may wait sometime before clicking the link on products list page, the particular product might be deleted and when user clicks the product which was deleted, there will be some issues on the system. In order to avoid such issues, I usually use optional to catch the nullPointerExceptions.

  2. There is also the possibility that in between fetching the id and fetching the entity that id represents, the entity is deleted, so it is entirely possible that your byId method returns null.

    Whether you use an Optional or return null, you are passing off the responsibility of what to do to the caller, but with Optional, it’s extremely clear to the caller that this method may not return anything. You can also accomplish this with @Nullable, but it’s still not as verbose. Plus, if I realize my method may return nothing and so add @Nullable to it, I am not forced to change all the calls to this method, whereas if I change the return value to Optional, I have to go through and think about each call to this method and whether or not it’s going to be null, which is a good thing.

    The only valid argument I see against Optional is the extra memory usage, but you also get the nice functional methods that come along with Optional, so it’s a worthwhile tradeoff as far as I’m concerned.

  3. Looking for a borrower is business logic, in my opinion. Instead of working with Optionals I would rather write a contract method e.g. hasBorrower(id borrowerId) and use the repository method existsById(...) to check for that. This allows me to address the problem in my business service and not implicitly move the logic to the database.


  • find vs. get – Thomas Uhrig February 16, 2021

    Looking for a borrower is business logic, in my opinion. Instead of working with Optionals I would rather write a contract method e.g. hasBorrower(id borrowerId) and use the repository method existsById(...) to check for that. This allows me to address the problem in my business service and not implicitly move the logic to the database.