Either for error handling in java
My new workplace makes heavy use of functional java Either for error handling ( http://www.functionaljava.org/javadoc/4.5/functionaljava/fj/data/Either.html ).
exceptions are hardly used at all.
This is very annoying imo for many reasons. To name one: Every api call (that returns Either) within a method must first check if the returned Either is an error or not, before moving on to the next line. If it is an error, it is pushed back onto the method call stack in the form of an Aither. Each method on the stack also needs to check the reconfigured Either for the error, until finally we move on to the method that is responsible for handling the error. This results in very poorly structured Java code. I cannot write a normal java code stream as I have to "stop" at every api call (so streams are out of the question). eg
Either<Error, Value> myMethod(String someVar) {
Either<Error, Value> valEither someService.getSomething(someVar)
if (valEither.isRight()) {
Either<Error, Value> otherValue someService.getSomethingElse(valEither.right().value())
if (otherValue.isRight()) ..... //you get the idea
} else {
//maybe log
return valEither;
}
}
I can of course use Either monadic methods (which I do), but that doesn't solve the basic problems of having to "ask" the return type if it's an error or a value. There are many more reasons why I think using both an error handling framework is not a good idea (long accounts, long methods, nested generics, etc.).
To get around this, I thought I might have thrown a specific exception for every api call that returns an "error". Or, and catch the exception once, on the top-level method in which it is currently working.
Value val = myService.getSomething().rightOrThrow(new MyException("blaa"));
but this is not possible, as the only method for any type of projection that does something similar is throwing a java error that is not designed to catch (almost) any circumstance (I may accidentally catch stackoverflow or outofmemory errors).
myService.getSomething().right().valueE("some error msg");
Any suggestions or thoughts?
thank
source to share
Back when I programmed in FJ I also briefly asked this problem. I quickly realized that using it Either
in this way was not very useful, and that more native constructs such as Exceptions
were much easier syntactically and of course better suited to the language.
I used Either
when it makes sense to make additional functions using functional methods (for example, bimap
and map
et al), so something like:
return someService.getSomething(someVar)
.bimap((e)-> new Error("getSomething died for " + someVar, e),
(x)-> someService.getSomethingElse(x))
.right().map((x)-> someService.getSAnotherThing(x));
Perhaps this construct seems to make much more sense in languages ββthat support pattern matching.
Edit
As for how to throw the error, consider valueE , you can just write your own static version that throws whatever you like
source to share
The best solution I have found for throwing an exception in case the returned Either is an error:
either.right.on(err -> {throw new MyException(err);})
or use a helper method to make it more readable:
static <A> A willFailWith(String errorMsg) {
throw new MyException(errorMsg);
}
either.right.on(err -> willFailWith(err))
source to share