This is the second part of a series of posts looking at how features in Java 8 can help Scala developers stick to a functional style if they find themselves needing to develop Java code. The first part was about handling immutability.

Option/Optional

In Java it is common for methods which return a result which may not exist, to return null in the case where the result does not exist. Consider an example from java.util.Map in the standard library.

The get method:

Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.

This means that a developer using the the get method should, in order to have robust code, protect against the possibility of the value being null. This is fine if the developer reads the documentation to understand the implicit contract, and knows how to appropriately handle the null case, but it would be better if the signature of the get method enforced that the developer must handle the possibility of no result.

Scala developers will be familiar with the scala.collection.Map interface. A map of type T has a get method which returns Option[T]. The Option type is either an instance of Some[T] from which the value of type T can be extracted, or it is of type None. The developer using a Map has no choice but to handle the Option type, and most importantly the signature of the get method makes it unambiguously clear that this method may fail to return a value.

Java 8 introduces the Optional type, which serves a similar purpose to Option in Scala. The javadoc is here. It doesn’t have the subtypes of Some and None but since Java 8 doesn’t have pattern matching this is not too much of a loss. Optional has familiar functional operators such as flatMap, map, filter etc.

We can’t change the fact that some Java library classes use null to indicate the lack of a value to return, but we can choose to use it in Java code we write for ourselves.

Consider the following code:

class Person {

    private String firstName;
    private String middleName;
    private String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Person(String firstName, String middleName, String lastName) {
        this.firstName = firstName;
        this.middleName = middleName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getMiddleName() {
        return middleName;
    }

    public String getLastName() {
        return lastName;
    }
}

If the second constructor is used, the Person object will have a null value for middleName. Nothing about the getMiddleName method indicates this however. Consider the following code:

public static String renderPersonUpperCase(Person p) {
    return p.getFirstName().toUpperCase() +
            " " + p.getMiddleName().toUpperCase() +
            " " + p.getLastName().toUpperCase();
}

Person person1 = new Person("Billy", "Joe", "Armstrong");
Person person2 = new Person("Trent", "Reznor");
System.out.println(renderPersonUpperCase(person1));
System.out.println(renderPersonUpperCase(person2));

This causes the familiar and dreaded java.lang.NullPointerException. Of course we could code around this but we get no help from getMiddleName to know that it may return null.

With Optional we can rearrange our code as follows:

class Person {

    private String firstName;
    private Optional<String> middleName = Optional.empty();
    private String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Person(String firstName, String middleName, String lastName) {
        this.firstName = firstName;
        this.middleName = Optional.of(middleName);
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public Optional<String> getMiddleName() {
        return middleName;
    }

    public String getLastName() {
        return lastName;
    }
}

Then, we are forced to handle the fact that getMiddleName returns Optional<String>:

public static String renderPersonUpperCase(Person p) {
    return p.getMiddleName().<String>map((String m) ->
                    p.getFirstName().toUpperCase() +
                            " " + m.toUpperCase() +
                            " " + p.getLastName().toUpperCase()).
                    orElse(p.getFirstName().toUpperCase() +
                            " " + p.getLastName().toUpperCase());
}

If using map and orElse in Java seems a bit clunky, the same thing could be achieved in a more imperative style using and if statement with isPresent() but the important thing is that by using Optional in our method signature, a developer using that code is forced to handle the possibility of the value being empty, failure to do so can be caught at compile time (i.e. if we tried to use Optional<String> as a String) rather than receiving a NullPointerException at run-time.

Try

In Scala, all exceptions are unchecked, meaning that there is no need to use a throws block to to declare that a method may throw a checked exception. In fact where declaring a method throws an exception is required in order to provide compatibility with Java code it is necessary to use an annotation.

For similar reasons as those stated above for why it is beneficial to return an Option wrapping the return type rather than returning either the return type or null, in Scala we can use the Try class to make it explicit that a method may fail.

Consider the following example, where we use a Try to represent the fact that a divide operation may fail if we try to divide by zero. We can match on that result to handle it functionally.

import scala.util.{Failure, Success, Try}

object TryExample extends App {

  def divide(a: Int, b: Int): Try[Int] = Try(a/b)

  def divideAndPrint(a: Int, b: Int) = {
    divide(a, b) match {
      case Success(result) => println(s"$a divided by $b is $result")
      case Failure(ex: ArithmeticException) => println("Arithmetic Exception")
      case Failure(ex: Throwable) => println(s"unexpected Exception ${ex.getMessage}")
    }
  }

  divideAndPrint(4, 2)
  divideAndPrint(1, 0)
}

In Java, since ArithmeticException is unchecked we’re not obliged to use a throws declaration on a similar method, but without a Try class a similar method fails to communicate the possibility of an Exception:

public static Integer divide(Integer a, Integer b) {
    return a / b;
}

There is no built-in equivalent of scala.util.Try but if we want similar functional exception handling, one option is to use com.aol.cyclops.control.Try from the Cyclops React Library. We can wrap the unsafe divide method defined above:

public static Try<Integer, ArithmeticException> safeDivide(Integer a, Integer b) {
  return Try.catchExceptions(ArithmeticException.class).tryThis(
      new Try.CheckedSupplier<Integer, ArithmeticException>() {
          @Override
          public Integer get() throws ArithmeticException {
              return divide(a, b);
          }
      });
}

It’s much more verbose than the Scala equivalent, but Java usually is! Verbosity aside, this has allowed us to explicitly declare in the return type that the method may fail. The Cyclops React Try class contains functional operators for mapping and flatmapping over Try instances, but one simple way to handle instances is with a simple if-else block.

public static void printAndDivide(Integer a, Integer b) {
    Try<Integer, ArithmeticException> result = safeDivide(a, b);
    if(result.isSuccess()) {
        System.out.println(a + "divided by " + b + " equals " + result.get());
    } else {
        System.out.println("Arithmetic Exception thrown");
    }
}

Conclusion

In Scala, where a method may fail to return a result we use Option rather than returning null, and where a method may fail we use Try rather than allowing expections to occur unchecked. This is a good approach, especially when designing an API, since it means it is explicit to users of methods that they need handle the possibility of no result, or of an Exception.

In Java 8, we can use the built-in Optional type in place of Scala’s Option and we can use the third-party com.aol.cyclops.control.Try in place of scala.util.Try.