Class Result<T>

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

    public final class Result<T>
    extends Object
    implements org.joda.beans.ImmutableBean, 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
    • 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,
                                            String message,
                                            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​(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. This recognizes and handles FailureException and FailureItemProvider exceptions.

        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​(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. This recognizes and handles FailureException and FailureItemProvider exceptions.

        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​(Throwable cause)
        Creates a failed result caused by a throwable.

        This recognizes and handles FailureException and FailureItemProvider exceptions. If the exception type is not recognized, the failure will have a reason of ERROR.

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

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

        This recognizes and handles FailureException and FailureItemProvider exceptions. If the exception type is not recognized, the failure will have a reason of ERROR.

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

        public static <R> Result<R> failure​(Throwable cause,
                                            String message,
                                            Object... messageArgs)
        Creates a failed result caused by a throwable.

        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:
        cause - 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​(Exception cause,
                                            String message,
                                            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:
        cause - 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,
                                            Throwable cause)
        Creates a failed result caused by a throwable with a specified reason.
        Type Parameters:
        R - the expected type of the result
        Parameters:
        reason - the result reason
        cause - the cause of the failure
        Returns:
        a failure result
      • failure

        public static <R> Result<R> failure​(FailureReason reason,
                                            Exception cause)
        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
        cause - the cause of the failure
        Returns:
        a failure result
      • failure

        public static <R> Result<R> failure​(FailureReason reason,
                                            Throwable cause,
                                            String message,
                                            Object... messageArgs)
        Creates a failed result caused by a throwable 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
        cause - 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,
                                            Exception cause,
                                            String message,
                                            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
        cause - 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:
        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:
        IllegalArgumentException - if all of the results are successes
      • failure

        public static <R> Result<R> failure​(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:
        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
      • failure

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

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

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

        public static <R> Result<R> ofNullable​(R value,
                                               FailureReason reason,
                                               String message,
                                               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​(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​(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​(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​(Iterable<? extends Result<T>> results,
                                                    Function<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​(Iterable<? extends Result<T>> results,
                                                        Function<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
      • ifSuccess

        public void ifSuccess​(Consumer<? super T> consumer)
        Executes the given consumer if the result represents a successful call and has a result available.
        Parameters:
        consumer - the consumer to be decorated
      • 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
      • ifFailure

        public void ifFailure​(Consumer<Failure> consumer)
        Executes the given consumer if the result represents a failure.
        Parameters:
        consumer - the consumer to be decorated
      • get

        public Optional<T> get()
        Returns the result value if calculated successfully, empty if a failure occurred.
        Returns:
        the result value if success, empty if 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:
        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 may 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​(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 IllegalStateException will be thrown. To avoid this, call isSuccess() or isFailure() first.

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

        public <R> Result<R> map​(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
      • mapFailure

        public Result<T> mapFailure​(Function<Failure,​Failure> function)
        Processes a failed result by applying a function that alters the failure.

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

        If this result is a failure, then the specified function is invoked. The return value of the specified function is returned to the caller wrapped in a failure 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 success, then this is returned. The specified function is not invoked.

        Parameters:
        function - the function to transform the failure with
        Returns:
        the new result
      • mapFailureItems

        public Result<T> mapFailureItems​(Function<FailureItem,​FailureItem> function)
        Processes a failed result by applying a function that alters the failure items.

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

        If this result is a failure, then the specified function is invoked. The return values of the specified function is returned to the caller wrapped in a failure 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 success, then this is returned. The specified function is not invoked.

        Parameters:
        function - the function to transform the failure with
        Returns:
        the new result
      • flatMap

        public <R> Result<R> flatMap​(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,
                                                 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 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​(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
      • metaBean

        public Result.Meta<T> metaBean()
        Specified by:
        metaBean in interface org.joda.beans.Bean
      • hashCode

        public int hashCode()
        Overrides:
        hashCode in class Object