Class ProblemException

java.lang.Object
java.lang.Throwable
java.lang.Exception
nz.org.riskscape.problem.ProblemException
All Implemented Interfaces:
Serializable

public class ProblemException extends Exception

Thrown from ResultOrProblems.getOrThrow() as an alternative to using functional style flow control in your code with ResultOrProblems. ProblemException is a checked exception and is explicitly meant to be - it is ised for exceptional flow control: calling code must decide how to deal with the exception; declaring code should be careful that they should be using this instead of returning a ResultOrProblems. Use with catching(Call) to 'clean' up exceptional flow control within a method body.

This is in contrast to a ResultComputationException which is a programming error caused by not checking for a result before calling get(). ResultComputationException is an unchecked exception and is not meant to be caught (apart from error reporting code).

Example use: ``` public ResultOrProblems doThing() { return ProblemException.wrap(() -> { Struct structType = givenType.find(Struct.class).orElseThrow(new ProblemException(unexpectedTypeProblem())); RSList listType = otherType.find(RSList.class).orElseThrow(new ProblemException(unexpectedTypeProblem())); RealizedExpression expr = realizer.realize(structType, someExpr).orElseThrow();

 return new Foo(listType, expr);
 

}); } `` A small number of micro benchmarks were done to compare the relative costs of throwing/catching a ProblemException, vs returning a ResultOrProblems, including the cost of using thewrap` method to clean up code. Findings were:

  • throwing exceptions is slower than returning a failed ResultOrProblems, if suppressing stack traces then it becomes almost neglible (say, 20% slower)
  • throwing exceptions is faster when code mostly succeeds - avoids the overhead of constructing a wrapper object for each method call
  • using the catching(Call) method adds overhead, say, a 10x overhead to succeeding code and a 2x overhead to failing code. But this was 10ms vs 100ms for 100k iterations around a trivial method.

Ultimately this shows that for code that's not in a tight loop or being called a lot, worry about write nice looking code, don't worry about performance.

See Also:
  • Constructor Details

  • Method Details

    • throwUnlessEmpty

      public static void throwUnlessEmpty(List<Problem> problems) throws ProblemException
      Throws:
      ProblemException
    • catching

      public static final <T> ResultOrProblems<T> catching(ProblemException.Call<T> call)

      Wrap some code in a try-catch so that the result of T is wrapped in a ResultOrProblems of type T. If the code throws a ProblemException, a failed result is returned.

      Type Parameters:
      T - type the return type of the call
      Parameters:
      call - the code to call
      Returns:
      Either a successful result of type T or a failed result.
    • catching

      public static final <T> ResultOrProblems<T> catching(ProblemException.ProblemsCall<T> call)

      Wrap some code in a try-catch so that the result of T is wrapped in a ResultOrProblems of type T. If the code throws a ProblemException, a failed result is returned. Any problems added in to the list will also be returned. If the problems list has errors, then a failed result will be returned (ignoring any result that might have been returned).

      Type Parameters:
      T - type the return type of the call
      Parameters:
      call - the code to call
      Returns:
      Either a successful result of type T or a failed result.
    • toResult

      public <T> ResultOrProblems<T> toResult()
      Returns:
      a failed ResultOrProblems that includes the problems attached to this exception
    • fillInStackTrace

      public Throwable fillInStackTrace()
      Overrides:
      fillInStackTrace in class Throwable
    • getProblems

      public List<Problem> getProblems()
    • getMessage

      public String getMessage()
      Overrides:
      getMessage in class Throwable