Have you recently faced a NullPointerExceptionin your code? If not, then you must be a careful writer. One of the most common exception types in Java applications are NullPointerExceptions. As long as the language allows us to assign null values to any object, it will always be easy to write a small piece of code, which, at some point, will cause a NullPointerExceptionand crash the entire system. The java.util.Optional<T>class was introduced in Java 8 to alleviate this problem. Indeed, the Optional's API turns out to be quite powerful. There are plenty of cases where Optionals fit well. However, they are not designed to completely solve the problem with NullPointerExceptions. Additionally, Optionals themselves are very easy to be misused. A good indicator for that is the number of articles that are often being published on how Optionals should or should not be used.In contrast to Java, the type systems of other languages, like Kotlin, Swift, Groovy and more, are able to distinguish between variables that are allowed to point to null values and those that are not. In other words, they do not allow a null value to be assigned to a variable unless it is explicitly declared as nullable. In this article, we will give an overview of some features of different programming languages that reduce or avoid the necessity of working with null values.

Java Optionals

With java.util.Optional<T>introduced in Java 1.8, the need for null references is significantly reduced. Nevertheless, some care is needed when creating an instance of an Optional or when using it. For instance, the Optional.getmethod will throw a NoSuchElementExceptionif the value is not present, or the Optional.ofmethod will throw a NullPointerExceptionif the provided value is null. Therefore, both of these methods are as risky as directly de-referencing potential null values. One benefit we get from an Optional is that it provides a set of higher order functions, which can be chained without worrying whether the value is present or not.

Null Checks

Let’s consider a simple example with two classes' user and address where the required field in user is only usernameand the required fields in address are streetand number. The task is to find the ZIP code of the user with the given id. If any of the non-required values are missing, then an empty string should be returned. Assume that a UserRepositoryis also provided. One way to implement this task is the following:

Provided that the userRepositoryis not null, this code will not throw a NullPointerException. However, three if-statements are sitting in the code only for doing null-checks. The amount of the boilerplate code is comparable to the amount of code written to accomplish the task.

Optional Chaining

If Optionals were used as return types on the methods that do not guarantee to return a non-null value, the above implementation could also be written as:

If not worse, the second implementation is not any better than the first one. The null-checks are simply replaced with Optional.isPresent, which, indeed, should be used before invoking Optional.get. By the way, the Optional.getis a good candidate to get deprecated. Java 10 introduced a better alternative — Optional.orElseThrow — whose behavior is the same, but the method name is screaming that an exception will be thrown if the value is not present.The code above is only intending to show an ugly usage of Optionals. A more elegant approach would be to make a chain of higher-order functions provided by the Optional API:

If the Optional returned by the user repository is empty, the flatMapwill simply return an empty Optional. Otherwise, it will return an optional wrapping the user’s address. In this way, there is no need for any null-checking. The same holds for the second flatMapinvocation. Thus, the optional is cascaded until the value we were looking for is reached.

Enhancements in Java 9

The Optional API is further enriched in Java 9 with three other methods: or, stream and ifPresentOrElse: Optional.or provides another possibility to chain Optionals. For instance, if we already have a collection of users in memory and we want to search through this collection before going into the repository, we could do the following:

Optional.ifPresentOrElseis similar to Optional.ifPresentfrom Java 1.8, but it performs a second action if the value is not present. For example, if the task was to print the ZIP code and it is provided or print a message otherwise, we could do the following:

After all, one of the biggest pitfalls in Java is that it allows every non-primitive type to be assigned to null— ven the Optional type itself. Nothing can stop us from assigning nullinstead of an empty Optional to an Optional type. If it happens that the findByIdmethod simply returns null, then everything we described above becomes pointless.

Kotlin's Null Safety

Unlike Java, the Kotlin’s type system supports nullable types, which means types that except for the usual values of their data type may also represent the special value null. By default, all variables are non-nullable. To declare a nullable variable, the type on the declaration should be followed by a question mark. Furthermore, dereferencing nullable variables is allowed either through the null-safe call ?., the non-null assertion !!,or the Elvis operator ?:. The following examples show how to declare, assign, and reference nullable variables:

Notice the difference between the null-safe call ?.and the non-null assertion operator !!. Just like the name suggests, if the de-referenced variable is null, the former will immediately return null, whereas the latter will throw a NullPointerExceptioninstead. You don’t want to use !!unless you are a lover of the NullPointerExceptions. The Elvis operator is similar to the Optional.orElse. It returns the value of the expression on the left-hand side of ?:if it is not null. Otherwise, it evaluates the right-hand side expression and returns the result.

Nullable Chaining

Similar to Optionals in Java, nullable values in Kotlin can also be chained by using, for example, the null-safe call operator. An implementation of the findZipCodemethod in Kotlin would be done in a single statement:

Instead of Optional.flatMap, we can use the null-safe call ?. and, instead of Optional.orElse, we can use the Elvis operator ?:. Additionally, we don’t have to be concerned whether the userRepositoryis nullor not, because if it was, the compiler wouldn’t allow us to write userRepository.findById(userId), but we would rather be forced to use any of the operators mentioned above.

Swift

Swift behaves very similar to Kotlin. A type has to be marked explicitly to be able to store nil values. This can be done by adding the ?postfix operator to the type of a field or variable declaration. This is, however, just a short form of the type Optional<Wrapped>, which is defined in the Swift standard library. Swift Optionals, unlike normal types, don’t have to be initialized directly or by a constructor. They are nilby default. A Swift Optional is actually an enumeration, which has two states: noneand some, where nonerepresents niland some represents an existing wrapped object.

Implicitly Unwrapped Optionals

Optionals can also be declared as implicitly unwrapped Optional by using the !postfix operator on the type of the variable declaration. The main difference is that these can be accessed directly without the ?or !operators. The usage of implicitly unwrapped Optionals is highly discouraged, except in very specific situations, where they are necessary and where you can be certain, that a value exists. There are very few cases in which this mechanism is really needed, one of which is the Interface Builder Outlets for iOS or macOS.

Here is an example of how it should NOT be done:

// zipCode will be nil by default and is implicitly unwrapped
var zipCode : String!
/*
* if zipCode has a value, it will work fine but in this case
* it hasn’t and will therefore throw an error
*/
zipCode.append("0")

The proper way of achieving the same result:

var zipCode : String?
zipCode?.append("0") // this line will return nil but no error is thrown

Optional Chaining

Optional chaining can be used to safely access fields and methods of the object contained in an Optional using the ?postfix operator. Many calls to Optionals can be chained together, hence the name Optional chaining. Such an expression always returns an Optional, which will contain either the resulting object or none if any Optional in the chain contains none. Therefore, the result of the Optional chain has to be checked for nilagain. This can be avoided by using either Optional binding, a nil-coalescing operator, or a guard-statement.

Optional Binding

The if letstatement provides a safe way to unwrap Optionals. If the given Optional contains none, the if block will be skipped. Otherwise, a local constant, which is only valid within the if block, will be declared. This constant can have the same name as the Optional, which causes the actual Optional to be invisible within the block. In addition to multiple unwrapping statements, a boolean expression can also be added to the if letstatement. These statements are separated by a comma ( ,), which behaves like the &&operator.

Guard

The guard statement, as the name suggests, guards code after it. In methods, it’s usually at the very beginning for checking the validity of the method parameters. But, it’s also able to unwrap Optionals (similar to Optional binding) and “guard” the code after it, if the Optional contains none. A guard statement only consists of a condition and/or an unwrapping statement and a compulsory elseblock. The compiler makes sure that this else block exits its enclosing scope by using control transfer statements ( return, throw, break, continue) or call methods whose return type is Never. The unwrapped value of the Optional is visible in the enclosing scope of the guard statement, where it can be used like an ordinary constant. The guard statement makes the code more readable and prevents a lot of nested if statements.

Conclusion

Java Optionals are recommended to be used as return types of the API whenever the requested value is not guaranteed. In this way, the client of the API will be encouraged to check for the presence of the returned value and also write cleaner code by utilizing the Optional’s API. However, one of the biggest pitfalls is that Java is incapable of enforcing programmers to not assign null values. Other modern languages, like Kotlin and Swift, are designed to be able to distinguish between types that are allowed to represent a nullvalue, and types that are not. Furthermore, they provide a rich set of features to cope with nullable variables and, thus, minimizing the risk of the null reference exceptions.