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.

      NB we might consider a parameterized version of this to avoid creating closures - http://wiki.jvmlangsummit.com/images/7/7b/Goetz-jvmls-lambda.pdf

      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 <T> ResultOrProblems<T> catching(List<Problem> problems, 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.

      This method is useful for code that is attempting a more complex operation that could fail or encounter issues in many ways during computation, e.g. realizing an expression, building a project.

      This method can lead to a semi succesful result, so it's up to your code to check for hasErrors rather than isPresent() to make sure you don't use a failed object.

      Type Parameters:
      T - type the return type of the call
      Parameters:
      problems - a mutable list of problems to include with the result if a result is returned. This list can be used by the calling code to assemble problems as errors are encountered.
      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