Interface Result<T>

Type Parameters:
T - value type
All Known Implementing Classes:
Failure, Success

public sealed interface Result<T> permits Success<T>, Failure<T>

A discriminated union that encapsulates either successful result with a value or failure with exception.

Creating Result

There are three methods to create result:

As Java does not have non-nullable types null can be supplied and received in all methods as a valid result value. If non-nullable type must be represented one can use Result<Optional<T>> although it is considered a bad practice to use Optional this way.

Direct instantiation of Success or Failure is also possible though not recommended.

Examples:


 Result<Integer> calculateSomething() {
     try {
         return Result.success(123);
     } catch (Exception ex) {
         return Result.failure(ex);
     }
 }

 Result<Void> doSomething() {
     try {
         return Result.empty();
     } catch (Exception ex) {
         return Result.failure(ex);
     }
 }

 Result<Optional<Integer>> doSomething() {
     try {
         return Result.success(Optional.empty());
     } catch (Exception ex) {
         return Result.failure(ex);
     }
 }
 

Handling Result

Chainable Methods

Examples:


 // Do some actions with either value or exception:
 //
 getResult().onSuccess(value -> {
     // process value
 }).onFailure(exception -> {
     // process exception
 });

 // Do some actions with either value or exception then get value or throw {@link RuntimeException}:
 //
 var value = getResult().onSuccess(value -> {
     // process value
 }).onFailure(exception -> {
     // process exception
 }).getOrThrow();
 

Pattern Matching

Result is represented by either Success or Failure instances which can be used in record pattern matching:

 
 public String buildString() {
      var result = doSomething();
      return switch (result) {
          case Success<String>(String value) -> value;
          case Failure<?>(Exception exception) -> "";
      }
 }
 
 

  • Method Summary

    Modifier and Type
    Method
    Description
    static <T> Result<T>
    Creates an empty successful result.
    static <T> Result<T>
    failure(Exception exception)
    Creates a failed result.
    default Optional<T>
    get()
    Returns optional value if success or empty optional if failure.
    default T
    Returns value if success or throws exception if failure.
    default boolean
    Returns if this result is a failure.
    default boolean
    Returns if this result is a success.
    default Result<T>
    Calls consumer with exception in case of failure.
    default Result<T>
    onSuccess(Consumer<T> consumer)
    Calls consumer with result value in case of success.
    static <T> Result<T>
    success(T value)
    Creates a successful result.
    default void
    Throws exception if failure.
  • Method Details

    • isSuccess

      default boolean isSuccess()
      Returns if this result is a success.
      Returns:
      success
    • isFailure

      default boolean isFailure()
      Returns if this result is a failure.
      Returns:
      failure
    • getOrThrow

      default T getOrThrow()
      Returns value if success or throws exception if failure. If exception is not RuntimeException then RuntimeException(exception) is thrown.
      Returns:
      value
    • get

      default Optional<T> get()

      Returns optional value if success or empty optional if failure.

      In case of null value there is no way to determine if this was success or failure. Use isSuccess() or isFailure() in this case.

      Returns:
      optional value or empty
    • throwIfFailure

      default void throwIfFailure()

      Throws exception if failure. If exception is not RuntimeException then RuntimeException(exception) is thrown.

      This method should be used instead of getOrThrow() if result value is Void or is not relevant. It can be also used as chained method for onSuccess(java.util.function.Consumer<T>)} or onFailure(java.util.function.Consumer<java.lang.Exception>).

      Examples:

      
       getResult()
            .onSuccess(value -> {
                // ...
             })
            .throwIfFailure();
      
       getResult()
            .onSuccess(value -> {
                // ...
            })
            .onFailure(exception -> {
                // log exception
                // can't throw arbitrary exception from lambda
            }
            .throwIfFailure();
       

    • onSuccess

      default Result<T> onSuccess(Consumer<T> consumer)

      Calls consumer with result value in case of success.

      If result was created by empty() then null value will be supplied to the consumer.

      Parameters:
      consumer - value consumer
      Returns:
      this instance
    • onFailure

      default Result<T> onFailure(Consumer<Exception> consumer)
      Calls consumer with exception in case of failure.
      Parameters:
      consumer - exception consumer
      Returns:
      this instance
    • success

      static <T> Result<T> success(T value)
      Creates a successful result.
      Type Parameters:
      T - value type
      Parameters:
      value - result value
      Returns:
      result
    • empty

      static <T> Result<T> empty()
      Creates an empty successful result. This is a convenience method for Result<Void>.
      Type Parameters:
      T - value type
      Returns:
      result
    • failure

      static <T> Result<T> failure(Exception exception)
      Creates a failed result.
      Parameters:
      exception - cause of failure
      Returns:
      result
      Throws:
      NullPointerException - if exception is null