Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Making Code Readable With Optional

DZone's Guide to

Making Code Readable With Optional

See how you can take advantage of the Optional class to improve the readability of your code.

· Java Zone ·
Free Resource

Java-based (JDBC) data connectivity to SaaS, NoSQL, and Big Data. Download Now.

Working with the ZAP API recently I found myself writing code like this:

((ApiResponseSet)Iterables.getLast(((ApiResponseList)clientApi.ascan.scans()).getItems())).getAttribute("id");

The API was constructed around the idea of key/value pairs, and often returned objects that had to be cast to more specific types, which forces you to add a lot of boilerplate code for simple tasks like getting the ID of the last scan. Still, code like this was getting out of hand.

One of the problems with statements like this (beyond the obvious of trying to do too much with a single line of code) is that instead of reading the code left to right, you have to read it from the middle out. I have always found nested method calls to be far less readable than a fluent chaining of methods for this very reason.

So is there a better way? In this case, the Optional class comes to the rescue. That one single, ugly line of code can be broken down into a much more fluent sequence of calls like so:

Optional.of(clientApi.ascan.scans())
  .map(e -> (ApiResponseList)e)
  .map(ApiResponseList::getItems)
  .map(Iterables::getLast)
  .map(e -> (ApiResponseSet)e)
  .map(e -> e.getAttribute("id"));

The map method allows us to progressively transform the objects we are working with through a series of clear steps. The code is much more readable, and actually benefits from a degree of protection from Null Pointer Exceptions because the map method will not attempt to work with a null. But we can make it better.

Any of those casts could fail, throwing an exception, so let’s borrow a concept from C#’s as operator, which will cast an object or return null if the cast was invalid.

public class CastUtils {
  public static <T> T as(Class<T> t, Object o) {
     return t.isInstance(o) ? t.cast(o) : null;
  }
}

Now our code looks like this:

Optional.of(clientApi.ascan.scans())
  .map(e -> CastUtils::as(ApiResponseList.class, e))
  .map(ApiResponseList::getItems)
  .map(Iterables::getLast)
  .map(e -> CastUtils::as(ApiResponseSet.class, e))
  .map(e -> e.getAttribute("id"));

Now if any cast fails or any method returns null, the end result is an empty Optional rather than an exception. This is ideal because if I can’t get the last item’s ID, I don’t really care which point in the transformation failed, I just need to know that the information I want is not available.

Connect any Java based application to your SaaS data.  Over 100+ Java-based data source connectors.

Topics:
fluent ,null ,boilerplate ,exceptions ,api ,map ,java

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}