Class Result<T>

  • Type Parameters:
    T - the type of the underlying result for a successful invocation
    All Implemented Interfaces:
    java.io.Serializable, Bean, ImmutableBean

    public final class Result<T>
    extends java.lang.Object
    implements ImmutableBean, java.io.Serializable
    The result of an operation, either success or failure.

    This provides a functional approach to error handling, that can be used instead of exceptions. A success result contains a non-null result value. A failure result contains details of the failure that occurred.

    Methods using this approach to error handling are expected to return Result<T> and not throw exceptions. The factory method of(Supplier) and related methods can be used to capture exceptions and convert them to failure results.

    Application code using a result should also operate in a functional style. Use map(Function) and flatMap(Function) in preference to isSuccess() and getValue().

      Result<Foo> intermediateResult = calculateIntermediateResult();
      return intermediateResult.flatMap(foo -> calculateFinalResult(foo, ...));
     

    Results can be generated using the factory methods on this class.

    See Also:
    Serialized Form
    • Nested Class Summary

      Nested Classes 
      Modifier and Type Class Description
      static class  Result.Meta<T>
      The meta-bean for Result.
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      static boolean allSuccessful​(Result<?>... results)
      Checks if all the results are successful.
      static boolean allSuccessful​(java.lang.Iterable<? extends Result<?>> results)
      Checks if all the results are successful.
      static boolean anyFailures​(Result<?>... results)
      Checks if any of the results are failures.
      static boolean anyFailures​(java.lang.Iterable<? extends Result<?>> results)
      Checks if any of the results are failures.
      static <T,​R>
      Result<R>
      combine​(java.lang.Iterable<? extends Result<T>> results, java.util.function.Function<java.util.stream.Stream<T>,​R> function)
      Takes a collection of results, checks if all of them are successes and then applies the supplied function to the successes wrapping the result in a success result.
      <U,​R>
      Result<R>
      combineWith​(Result<U> other, java.util.function.BiFunction<T,​U,​Result<R>> function)
      Combines this result with another result.
      static long countFailures​(Result<?>... results)
      Counts how many of the results are failures.
      static long countFailures​(java.lang.Iterable<? extends Result<?>> results)
      Counts how many of the results are failures.
      boolean equals​(java.lang.Object obj)  
      static <R> Result<R> failure​(Failure failure)
      Creates a failed result containing a failure.
      static <R> Result<R> failure​(FailureReason reason, java.lang.Exception exception)
      Creates a failed result caused by an exception with a specified reason.
      static <R> Result<R> failure​(FailureReason reason, java.lang.Exception exception, java.lang.String message, java.lang.Object... messageArgs)
      Creates a failed result caused by an exception with a specified reason and message.
      static <R> Result<R> failure​(FailureReason reason, java.lang.String message, java.lang.Object... messageArgs)
      Creates a failed result specifying the failure reason.
      static <R> Result<R> failure​(Result<?> failureResult)
      Returns a failed result from another failed result.
      static <R> Result<R> failure​(Result<?> result1, Result<?> result2, Result<?>... results)
      Creates a failed result combining multiple failed results.
      static <R> Result<R> failure​(java.lang.Exception exception)
      Creates a failed result caused by an exception.
      static <R> Result<R> failure​(java.lang.Exception exception, java.lang.String message, java.lang.Object... messageArgs)
      Creates a failed result caused by an exception.
      static <R> Result<R> failure​(java.lang.Iterable<? extends Result<?>> results)
      Creates a failed result combining multiple failed results.
      static <T,​R>
      Result<R>
      flatCombine​(java.lang.Iterable<? extends Result<T>> results, java.util.function.Function<java.util.stream.Stream<T>,​Result<R>> function)
      Takes a collection of results, checks if all of them are successes and then applies the supplied function to the successes.
      <R> Result<R> flatMap​(java.util.function.Function<? super T,​Result<R>> function)
      Processes a successful result by applying a function that returns another result.
      Failure getFailure()
      Returns the failure instance indicating the reason why the calculation failed.
      T getValue()
      Returns the actual result value if calculated successfully, throwing an exception if a failure occurred.
      T getValueOrElse​(T defaultValue)
      Returns the actual result value if calculated successfully, or the specified default value if a failure occurred.
      T getValueOrElseApply​(java.util.function.Function<Failure,​T> mapper)
      Returns the actual result value if calculated successfully, else the specified function is applied to the Failure that occurred.
      int hashCode()  
      boolean isFailure()
      Indicates if this result represents a failure.
      boolean isSuccess()
      Indicates if this result represents a successful call and has a result available.
      <R> Result<R> map​(java.util.function.Function<? super T,​? extends R> function)
      Processes a successful result by applying a function that alters the value.
      static Result.Meta meta()
      The meta-bean for Result.
      Result.Meta<T> metaBean()  
      static <R> Result.Meta<R> metaResult​(java.lang.Class<R> cls)
      The meta-bean for Result.
      static <T> Result<T> of​(java.util.function.Supplier<T> supplier)
      Creates a success Result wrapping the value produced by the supplier.
      static <R> Result<R> ofNullable​(R value)
      Returns a success result containing the value if it is non-null, else returns a failure result with a reason of FailureReason.MISSING_DATA and message to say an unexpected null was found.
      static <R> Result<R> ofNullable​(R value, FailureReason reason, java.lang.String message, java.lang.Object... messageArgs)
      Returns a success result containing the value if it is non-null, else returns a failure result with the specified reason and message.
      java.util.stream.Stream<T> stream()
      Converts this result to a stream.
      static <R> Result<R> success​(R value)
      Creates a successful result wrapping a value.
      java.lang.String toString()  
      static <T> Result<T> wrap​(java.util.function.Supplier<Result<T>> supplier)
      Creates a Result wrapping the result produced by the supplier.
      • Methods inherited from class java.lang.Object

        clone, finalize, getClass, notify, notifyAll, wait, wait, wait
    • Method Detail

      • success

        public static <R> Result<R> success​(R value)
        Creates a successful result wrapping a value.

        This returns a successful result object for the non-null value.

        Note that passing an instance of Failure to this method would be a programming error.

        Type Parameters:
        R - the type of the value
        Parameters:
        value - the result value
        Returns:
        a successful result wrapping the value
      • failure

        public static <R> Result<R> failure​(FailureReason reason,
                                            java.lang.String message,
                                            java.lang.Object... messageArgs)
        Creates a failed result specifying the failure reason.

        The message is produced using a template that contains zero to many "{}" placeholders. Each placeholder is replaced by the next available argument. If there are too few arguments, then the message will be left with placeholders. If there are too many arguments, then the excess arguments are appended to the end of the message. No attempt is made to format the arguments. See Messages.format(String, Object...) for more details.

        Type Parameters:
        R - the expected type of the result
        Parameters:
        reason - the result reason
        message - a message explaining the failure, uses "{}" for inserting messageArgs
        messageArgs - the arguments for the message
        Returns:
        a failure result
      • of

        public static <T> Result<T> of​(java.util.function.Supplier<T> supplier)
        Creates a success Result wrapping the value produced by the supplier.

        Note that if the supplier throws an exception, this will be caught and converted to a failure Result.

        Type Parameters:
        T - the type of the value
        Parameters:
        supplier - supplier of the result value
        Returns:
        a success Result wrapping the value produced by the supplier
      • wrap

        public static <T> Result<T> wrap​(java.util.function.Supplier<Result<T>> supplier)
        Creates a Result wrapping the result produced by the supplier.

        Note that if the supplier throws an exception, this will be caught and converted to a failure Result.

        Type Parameters:
        T - the type of the result value
        Parameters:
        supplier - supplier of the result
        Returns:
        a Result produced by the supplier
      • failure

        public static <R> Result<R> failure​(java.lang.Exception exception)
        Creates a failed result caused by an exception.

        The failure will have a reason of ERROR.

        Type Parameters:
        R - the expected type of the result
        Parameters:
        exception - the cause of the failure
        Returns:
        a failure result
      • failure

        public static <R> Result<R> failure​(java.lang.Exception exception,
                                            java.lang.String message,
                                            java.lang.Object... messageArgs)
        Creates a failed result caused by an exception.

        The failure will have a reason of ERROR.

        The message is produced using a template that contains zero to many "{}" placeholders. Each placeholder is replaced by the next available argument. If there are too few arguments, then the message will be left with placeholders. If there are too many arguments, then the excess arguments are appended to the end of the message. No attempt is made to format the arguments. See Messages.format(String, Object...) for more details.

        Type Parameters:
        R - the expected type of the result
        Parameters:
        exception - the cause of the failure
        message - a message explaining the failure, uses "{}" for inserting messageArgs
        messageArgs - the arguments for the message
        Returns:
        a failure result
      • failure

        public static <R> Result<R> failure​(FailureReason reason,
                                            java.lang.Exception exception)
        Creates a failed result caused by an exception with a specified reason.
        Type Parameters:
        R - the expected type of the result
        Parameters:
        reason - the result reason
        exception - the cause of the failure
        Returns:
        a failure result
      • failure

        public static <R> Result<R> failure​(FailureReason reason,
                                            java.lang.Exception exception,
                                            java.lang.String message,
                                            java.lang.Object... messageArgs)
        Creates a failed result caused by an exception with a specified reason and message.

        The message is produced using a template that contains zero to many "{}" placeholders. Each placeholder is replaced by the next available argument. If there are too few arguments, then the message will be left with placeholders. If there are too many arguments, then the excess arguments are appended to the end of the message. No attempt is made to format the arguments. See Messages.format(String, Object...) for more details.

        Type Parameters:
        R - the expected type of the result
        Parameters:
        reason - the result reason
        exception - the cause of the failure
        message - a message explaining the failure, uses "{}" for inserting messageArgs
        messageArgs - the arguments for the message
        Returns:
        a failure result
      • failure

        public static <R> Result<R> failure​(Result<?> failureResult)
        Returns a failed result from another failed result.

        This method ensures the result type matches the expected type. If the specified result is a successful result then an exception is thrown.

        Type Parameters:
        R - the expected result type
        Parameters:
        failureResult - a failure result
        Returns:
        a failure result of the expected type
        Throws:
        java.lang.IllegalArgumentException - if the result is a success
      • failure

        public static <R> Result<R> failure​(Result<?> result1,
                                            Result<?> result2,
                                            Result<?>... results)
        Creates a failed result combining multiple failed results.

        The input results can be successes or failures, only the failures will be included in the created result. Intended to be used with anyFailures(Result...).

           if (Result.anyFailures(result1, result2, result3) {
             return Result.failure(result1, result2, result3);
           }
         
        Type Parameters:
        R - the expected type of the result
        Parameters:
        result1 - the first result
        result2 - the second result
        results - the rest of the results
        Returns:
        a failed result wrapping multiple other failed results
        Throws:
        java.lang.IllegalArgumentException - if all of the results are successes
      • failure

        public static <R> Result<R> failure​(java.lang.Iterable<? extends Result<?>> results)
        Creates a failed result combining multiple failed results.

        The input results can be successes or failures, only the failures will be included in the created result. Intended to be used with anyFailures(Iterable).

           if (Result.anyFailures(results) {
             return Result.failure(results);
           }
         
        Type Parameters:
        R - the expected type of the result
        Parameters:
        results - multiple results, of which at least one must be a failure, not empty
        Returns:
        a failed result wrapping multiple other failed results
        Throws:
        java.lang.IllegalArgumentException - if results is empty or contains nothing but successes
      • failure

        public static <R> Result<R> failure​(Failure failure)
        Creates a failed result containing a failure.

        This is useful for converting an existing Failure instance to a result.

        Type Parameters:
        R - the expected type of the result
        Parameters:
        failure - details of the failure
        Returns:
        a failed result containing the specified failure
      • ofNullable

        public static <R> Result<R> ofNullable​(R value,
                                               FailureReason reason,
                                               java.lang.String message,
                                               java.lang.Object... messageArgs)
        Returns a success result containing the value if it is non-null, else returns a failure result with the specified reason and message.

        This is useful for interoperability with APIs that return null, for example Map.get(), where a missing value should be treated as a failure.

        The message is produced using a template that contains zero to many "{}" placeholders. Each placeholder is replaced by the next available argument. If there are too few arguments, then the message will be left with placeholders. If there are too many arguments, then the excess arguments are appended to the end of the message. No attempt is made to format the arguments. See Messages.format(String, Object...) for more details.

        Type Parameters:
        R - the expected type of the result
        Parameters:
        value - the potentially null value
        reason - the reason for the failure
        message - a message explaining the failure, uses "{}" for inserting messageArgs
        messageArgs - the arguments for the message
        Returns:
        a success result if the value is non-null, else a failure result
      • ofNullable

        public static <R> Result<R> ofNullable​(R value)
        Returns a success result containing the value if it is non-null, else returns a failure result with a reason of FailureReason.MISSING_DATA and message to say an unexpected null was found.

        This is useful for interoperability with APIs that can return null but where null is not expected.

        Type Parameters:
        R - the expected type of the result
        Parameters:
        value - the potentially null value
        Returns:
        a success result if the value is non-null, else a failure result
      • allSuccessful

        public static boolean allSuccessful​(Result<?>... results)
        Checks if all the results are successful.
        Parameters:
        results - the results to check
        Returns:
        true if all of the results are successes
      • allSuccessful

        public static boolean allSuccessful​(java.lang.Iterable<? extends Result<?>> results)
        Checks if all the results are successful.
        Parameters:
        results - the results to check
        Returns:
        true if all of the results are successes
      • anyFailures

        public static boolean anyFailures​(Result<?>... results)
        Checks if any of the results are failures.
        Parameters:
        results - the results to check
        Returns:
        true if any of the results are failures
      • anyFailures

        public static boolean anyFailures​(java.lang.Iterable<? extends Result<?>> results)
        Checks if any of the results are failures.
        Parameters:
        results - the results to check
        Returns:
        true if any of the results are failures
      • countFailures

        public static long countFailures​(Result<?>... results)
        Counts how many of the results are failures.
        Parameters:
        results - the results to check
        Returns:
        the number of results that are failures
      • countFailures

        public static long countFailures​(java.lang.Iterable<? extends Result<?>> results)
        Counts how many of the results are failures.
        Parameters:
        results - the results to check
        Returns:
        the number of results that are failures
      • combine

        public static <T,​R> Result<R> combine​(java.lang.Iterable<? extends Result<T>> results,
                                                    java.util.function.Function<java.util.stream.Stream<T>,​R> function)
        Takes a collection of results, checks if all of them are successes and then applies the supplied function to the successes wrapping the result in a success result. If any of the initial results was a failure, then a failure result reflecting the failures in the initial results is returned.

        If an exception is thrown when the function is applied, this will be caught and a failure Result returned.

        The following code shows where this method can be used. The code:

           Set<Result<MyData>> results = goAndGatherData();
           if (Result.anyFailures(results)) {
             return Result.failure(results);
           } else {
             Set<FooData> combined =
                 results.stream()
                     .map(Result::getValue)
                     .map(MyData::transformToFoo)
                     .collect(toSet());
             return Result.success(combined);
           }
         
        can be replaced with:
           Set<Result<MyData>> results = goAndGatherData();
           return Result.combine(results, myDataStream ->
               myDataStream
                   .map(MyData::transformToFoo)
                   .collect(toSet())
           );
         
        Type Parameters:
        T - the type of the values held in the input results
        R - the type of the values held in the transformed results
        Parameters:
        results - the results to be transformed if they are all successes
        function - the function to apply to the stream of results if they were all successes
        Returns:
        a success result holding the result of applying the function to the input results if they were all successes, a failure otherwise
      • flatCombine

        public static <T,​R> Result<R> flatCombine​(java.lang.Iterable<? extends Result<T>> results,
                                                        java.util.function.Function<java.util.stream.Stream<T>,​Result<R>> function)
        Takes a collection of results, checks if all of them are successes and then applies the supplied function to the successes. If any of the initial results was a failure, then a failure result reflecting the failures in the initial results is returned.

        If an exception is thrown when the function is applied, this will be caught and a failure Result returned.

        The following code shows where this method can be used. The code:

           Set<Result<MyData>> results = goAndGatherData();
           if (Result.anyFailures(results)) {
             return Result.failure(results);
           } else {
             Set<FooData> combined =
                 results.stream()
                     .map(Result::getValue)
                     .map(MyData::transformToFoo)
                     .collect(toSet());
             return doSomethingReturningResult(combined); // this could fail
           }
         
        can be replaced with:
           Set<Result<MyData>> results = goAndGatherData();
           return Result.flatCombine(results, myDataStream -> {
             Set<CombinedData> combined =
                 myDataStream
                     .map(MyData::transformToFoo)
                     .collect(toSet());
             return doSomethingReturningResult(combined); // this could fail
           });
         
        Type Parameters:
        T - the type of the values held in the input results
        R - the type of the values held in the transformed results
        Parameters:
        results - the results to be transformed if they are all successes
        function - the function to apply to the stream of results if they were all successes
        Returns:
        a result holding the result of applying the function to the input results if they were all successes, a failure otherwise
      • isSuccess

        public boolean isSuccess()
        Indicates if this result represents a successful call and has a result available.

        This is the opposite of isFailure().

        Returns:
        true if the result represents a success and a value is available
      • isFailure

        public boolean isFailure()
        Indicates if this result represents a failure.

        This is the opposite of isSuccess().

        Returns:
        true if the result represents a failure
      • getValue

        public T getValue()
        Returns the actual result value if calculated successfully, throwing an exception if a failure occurred.

        If this result is a failure then an IllegalStateException will be thrown. To avoid this, call isSuccess() or isFailure() first.

        Application code is recommended to use map(Function) and flatMap(Function) in preference to this method.

        Returns:
        the result value, only available if calculated successfully
        Throws:
        java.lang.IllegalStateException - if called on a failure result
      • getValueOrElse

        public T getValueOrElse​(T defaultValue)
        Returns the actual result value if calculated successfully, or the specified default value if a failure occurred.

        If this result is a success then the result value is returned. If this result is a failure then the default value is returned. The default value must not be null.

        Application code is recommended to use map(Function) and flatMap(Function) in preference to this method.

        Parameters:
        defaultValue - the default value to return if the result is a failure
        Returns:
        either the result value or the default value
      • getValueOrElseApply

        public T getValueOrElseApply​(java.util.function.Function<Failure,​T> mapper)
        Returns the actual result value if calculated successfully, else the specified function is applied to the Failure that occurred.

        If this result is a success then the result value is returned. If this result is a failure then the function is applied to the failure. The function must not be null.

        This method can be used in preference to getValueOrElse(Object) when the default value is expensive to create. In such cases, the default value will get created on each call, even though it will be immediately discarded if the result is a success.

        Parameters:
        mapper - function used to generate a default value. The function has no obligation to use the input Failure (in other words it can behave as a Supplier<T> if desired).
        Returns:
        either the result value or the result of the function
      • getFailure

        public Failure getFailure()
        Returns the failure instance indicating the reason why the calculation failed.

        If this result is a success then an an IllegalStateException will be thrown. To avoid this, call isSuccess() or isFailure() first.

        Returns:
        the details of the failure, only available if calculation failed
        Throws:
        java.lang.IllegalStateException - if called on a success result
      • map

        public <R> Result<R> map​(java.util.function.Function<? super T,​? extends R> function)
        Processes a successful result by applying a function that alters the value.

        This operation allows post-processing of a result value. The specified function represents a conversion to be performed on the value.

        If this result is a success, then the specified function is invoked. The return value of the specified function is returned to the caller wrapped in a success result. If an exception is thrown when the function is invoked, this will be caught and a failure Result returned.

        If this result is a failure, then this is returned. The specified function is not invoked.

        For example, it allows a double to be converted to a string:

           result = ...
           return result.map(value -> Double.toString(value));
         
        Type Parameters:
        R - the type of the value in the returned result
        Parameters:
        function - the function to transform the value with
        Returns:
        the new result
      • flatMap

        public <R> Result<R> flatMap​(java.util.function.Function<? super T,​Result<R>> function)
        Processes a successful result by applying a function that returns another result.

        This operation allows chaining of function calls that produce a result. The specified function will typically call another method that returns a result.

        If this result is a success, then the specified function is invoked. The return value of the specified function is returned to the caller and may be a success or failure. If an exception is thrown when the function is invoked, this will be caught and a failure Result returned.

        If this result is a failure, then an equivalent failure is returned. The specified function is not invoked.

        For example,

           result = ...
           return result.flatMap(value -> doSomething(value));
         
        Type Parameters:
        R - the type of the value in the returned result
        Parameters:
        function - the function to transform the value with
        Returns:
        the new result
      • combineWith

        public <U,​R> Result<R> combineWith​(Result<U> other,
                                                 java.util.function.BiFunction<T,​U,​Result<R>> function)
        Combines this result with another result.

        This operation allows two results to be combined handling succeess and failure.

        If both results are a success, then the specified function is invoked to combine them. The return value of the specified function is returned to the caller and may be a success or failure.

        If either result is a failure, then a combination failure is returned. The specified function is not invoked.

           result1 = ...
           result2 = ...
           return result1.combineWith(result2, (value1, value2) -> doSomething(value1, value2));
         
        Type Parameters:
        U - the type of the value in the other result
        R - the type of the value in the returned result
        Parameters:
        other - another result
        function - a function for combining values from two results
        Returns:
        a the result of combining the result values or a failure if either result is a failure
      • stream

        public java.util.stream.Stream<T> stream()
        Converts this result to a stream.

        If this result is a success then a single element stream containing the result value is returned. If this result is a failure then an empty stream is returned.

        Returns:
        a stream of size one or zero
      • meta

        public static Result.Meta meta()
        The meta-bean for Result.
        Returns:
        the meta-bean, not null
      • metaResult

        public static <R> Result.Meta<R> metaResult​(java.lang.Class<R> cls)
        The meta-bean for Result.
        Type Parameters:
        R - the bean's generic type
        Parameters:
        cls - the bean's generic type
        Returns:
        the meta-bean, not null
      • equals

        public boolean equals​(java.lang.Object obj)
        Overrides:
        equals in class java.lang.Object
      • hashCode

        public int hashCode()
        Overrides:
        hashCode in class java.lang.Object
      • toString

        public java.lang.String toString()
        Overrides:
        toString in class java.lang.Object