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.