Skip to main content

Maybe - A Better Optional

Why Maybe#

Maybe is an alternative to Java's Optional. Java has Optional then why do we need Maybe?

  • First of all, Java's Optional is not Serializable. When it was added to Java 8, the designers of the language didn't want us to use it as a type for the object member variables.
  • Java's Optional has the get() method which means it may throw an exception if Optional.isPresent() is false.

Create#

Maybe.maybe()#

To construct Maybe, use Maybe.maybe. If the given argument is null, it creates Nothing, otherwise it's Just with the given value.

import j8plus.types.Maybe;
Maybe.maybe(123);// Maybe<Integer> = Just(123)
Maybe.maybe(null);// Maybe = Nothing

Maybe.nothing()#

import j8plus.types.Maybe;
Maybe.nothing();// Maybe = Nothing

Maybe from Optional#

import j8plus.types.Maybe;
final Optional<String> optionalName = Optional.ofNullable("Kevin");// Optional[Kevin]
// ...final Maybe<String> maybeName = Maybe.fromOptional(optionalName);// Maybe<String> = Just(Kevin)

Maybe to Optional#

If you need to convert Maybe into Optional, you can do it with Maybe.toOptional().

import j8plus.types.Maybe;
Maybe.maybe(1).toOptional(); // Optional[1]Maybe.nothing().toOptional(); // Optional.empty

Transform#

Maybe.map()#

import j8plus.types.Maybe;
Maybe.maybe(1).map(n -> n * 2); // Maybe<Integer> = Just(2)

Maybe.flatMap()#

import j8plus.types.Maybe;
public Maybe<User> findUser(final Long id) 
// ...
final Maybe<User> maybeUser = findUser(1L);// Maybe<User> = Just(User(1L, Kevin, Maybe<String> = Just(kevin@blah.blah)))maybeUser.flatMap(user -> user.getEmail()); // Maybe<String> = Just(kevin@blah.blah)
final Maybe<User> maybeUser2 = findUser(2L);// Maybe<User> = Just(User(2L, John, Maybe = Nothing))maybeUser2.flatMap(user -> user.getEmail()); // Maybe = Nothing

Maybe.filter()#

Maybe.filter() can check if the value in Maybe.Just matches the given Predicate and if so, it keeps Maybe.Just as is. If not, it turns it into Maybe.Nothing. If the Maybe is already Maybe.Nothing, nothing happens, and it is still Maybe.Nothing.

import j8plus.types.Maybe;
Maybe.maybe(10).filter(n -> n > 9);// Maybe<Integer> = Just(10)
Maybe.maybe(8).filter(n -> n > 9);// Maybe = Nothing

Get the Value#

Maybe.fold()#

So if Optional.get() is dangerous because it throws NoSuchElementException when Optional has a null value (i.e. Optional.empty()), what should I use?

A better way is using fold which is also called as 'Catemorphism' in functional programming.

Maybe.fold() takes two parameters. The first one is a Supplier to get the alternative value when Maybe is Nothing. The other one is a Function to handle the value when it is Maybe.Just.

e.g.)

import j8plus.types.Maybe;
Maybe.maybe(10)  .fold(    // Nothing case: When it's Nothing, returns 0.    () -> 0,    // Just case: When it's Just, return the value after applying this function.    n -> n * 5  ); // 50
import j8plus.types.Maybe;
Maybe.maybe(1).fold(() -> 0, n -> n * 2); // 2Maybe.nothing().fold(() -> 0, n -> n * 2); // 0
Maybe.maybe("Kevin").fold(() -> "", name -> "Hello " + name);// "Hello Kevin"
Maybe.nothing().fold(() -> "", name -> "Hello " + name);// ""

When it is Maybe.Just, if you don't want to change the value but just want to get it, you can use Function.identity() for the Just case function.

import java.util.function.Function;import j8plus.types.Maybe;
Maybe.maybe(123).fold(() -> 0, Function.identity()); // 123Maybe.nothing().fold(() -> 0, Function.identity()); // 0

Maybe.fold() is the same as Maybe.map().getOrElse().

import j8plus.types.Maybe;
Maybe.maybe(1).fold(() -> 0, n -> n * 2); // 2Maybe.maybe(1).map(n -> n * 2).getOrElse(() -> 0); // 2
Maybe.nothing().fold(() -> 0, n -> n * 2); // 0Maybe.nothing().map(n -> n * 2).getOrElse(() -> 0); // 0

Maybe.getOrElse()#

If you don't need to change the value in the Maybe and just want to get it, you can use Maybe.getOrElse().

import j8plus.types.Maybe;
Maybe.maybe(1).getOrElse(() -> 0); // 1Maybe.nothing().getOrElse(() -> 0); // 0

Check Maybe Type#

Maybe.isJust()#

To check if a Maybe instance is Maybe.Just, use Maybe.isJust(). If true, it is Maybe.Just. If false, it is Maybe.Nothing.

import j8plus.types.Maybe;
Maybe.maybe(1).isJust(); // trueMaybe.nothing().isJust(); // false

Maybe.isNothing()#

To check if a Maybe instance is Maybe.Nothing, use Maybe.isNothing(). If true, it is Maybe.Nothing. If false, it is Maybe.Just.

import j8plus.types.Maybe;
Maybe.nothing().isNothing(); // trueMaybe.maybe(1).isNothing(); // false