Nullability and Optionality

Java has the Optional<T>1 utility class which represents a container object that may contain some value or null. In Java, null is often used to represent a value that is missing, absent or logically uninitialized. Here's an example of how we can use the Optional class:

Optional<String> some = Optional.ofNullable("John");
Optional<String> none = Optional.ofNullable(null);

System.out.println(some.isPresent()); // true
System.out.println(some.get()); // prints John
System.out.println(none.isEmpty()); // true

Rust has no null. Optional or missing values are represented by the Option<T> type. The equivalent of the Java code above in Rust would be:

let some: Option<&str> = Some("John");
let none: Option<&str> = None;

assert_eq!(some.is_some(), true); // ok
println!("{}", some.unwrap());  // prints John
assert_eq!(none.is_none(), true); // ok

Control flow with optionality

In Java, you may have used if/else statements to control the flow when using nullable values. For example:

String name = some Name object that may be null...

if (name != null) {
    // do something with the name variable e.g. print it
    System.out.println(name);
} else {
    // deal with the null case or print a default name
    System.out.println("John");
}

We can rewrite the code above to use the Optional class as follows:

String name = some Name object that may be null...

Optional<String> optionalName = Optional.ofNullable(name);

if (optionalName.isPresent()) {
    // do something with the name
    System.out.println(optionalName.get());
} else {
    // deal with the empty Optional or print a default name
    System.out.println("John");
}

In Rust, we can use pattern matching to achieve the same behavior:

let name: Option<&str> = Some("Arya");

match name {
    Some(name) => println!("{}", name),
    None => println!("John")  // if None, print default name instead
}

We can also make the Java code even more succinct:

String name = some Name object that may be null...

String nameToPrint = Optional.ofNullable(name).orElse("John");

System.out.println(nameToPrint);

And the Rust code can be rewritten as below:

let name: Option<&str> = Some("Arya");

let name_to_print = name.unwrap_or("John"); // if name is None, use default value

println!("{}", name_to_print);

Note: If the default value is expensive to compute, you can use unwrap_or_else instead. It takes a closure as an argument, which allows you to lazily initialize the default value.

If we only care about the presence of a value (rather than its absence), then we can write code like this in Java:

Optional<String> optionalName = Optional.of("Arya");

optionalName.ifPresent(name -> System.out.println("The name is " + name)); // prints: The name is Arya

The equivalent in Rust can be achieved using if let:

let name = Some("Arya");

if let Some(name) = name {
    println!("The name is {}", name); // prints: The name is Arya
}

1

The Optional class was introduced in Java 8.