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

Managing a MongoDB deployment? Take a load off and live migrate to MongoDB Atlas, the official automated service, with little to no downtime.

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.

MongoDB Atlas is the easiest way to run the fastest-growing database for modern applications — no installation, setup, or configuration required. Easily live migrate an existing workload or start with 512MB of storage for free.

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

Published at DZone with permission of Matthew Casperson, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}