I have recently started using RxJava2 in one of my projects and currently I am working on implementing error handling in it.
I have written a mock class below in which I was initially throwing the error after wrapping it in a custom exception. However some of the examples I came across on error handling on stackoverflow and other sites used Single.error instead.
I used both approaches and they resulted in my subscribers onError method being invoked with the / by zero exception. I didn't notice any difference between the two.
There is comprehensive documentation on Error Handling and Error Handling Operators along with a lot of other articles on how to handle the exception after it is thrown. But the information in the javadoc for Single.error and Observable.error is quite minimal.
Is there an advantage of using Single.error or Observable.error over just throwing the exception? When do we choose one approach over the other?
public class Test {
public static void main(String[] args){
Single.just(1)
.flatMap(x -> externalMethod(x))
.subscribe(
s -> System.out.println("Success : " + s),
e -> System.out.println("Error : "+e)
);
}
public static Single<Integer> externalMethod(int x){
int result = 0;
try{
/* Some database / time consuming logic */
result = x % 0;
}
catch (Exception e){
throw new CustomException(e.getMessage()); // --> APPROACH 1
OR
return Single.error(new CustomException(e.getMessage())); // --> APPROACH 2
}
return Single.just(result);
}
}
Actually it does not matter, becaues RxJava tries to catch and relay all Throwables
APPROACH 1 -- throw new CustomException();
(io.reactivex.internal.operators.single.SingleFlatMap)
#Override
public void onSuccess(T value) {
SingleSource<? extends R> o;
try {
o = ObjectHelper.requireNonNull(mapper.apply(value), "The single returned by the mapper is null");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
downstream.onError(e);
return;
}
if (!isDisposed()) {
o.subscribe(new FlatMapSingleObserver<R>(this, downstream));
}
}
You see here, that given mapper from flatMap is invoked with an try-catch. If the mapper throws a Throwable, the Throwable will be forwarded via onError to downstream subscriber.
APPROACH 2 -- return Single.error(...)
(io.reactivex.internal.operators.single.SingleError)
Single#error
#Override
protected void subscribeActual(SingleObserver<? super T> observer) {
Throwable error;
try {
error = ObjectHelper.requireNonNull(errorSupplier.call(), "Callable returned null throwable. Null values are generally not allowed in 2.x operators and sources.");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
error = e;
}
EmptyDisposable.error(error, observer);
}
public static void error(Throwable e, SingleObserver<?> observer) {
observer.onSubscribe(INSTANCE);
observer.onError(e);
}
Single#error emits given Throwable on subscription via #onError
When a value is emitted to Single#flatMap the mapper is applied and a subscription is opened returned value from the mapper.
(io.reactivex.internal.operators.single.SingleFlatMap.SingleFlatMapCallback.FlatMapSingleObserver)
#Override
public void onSubscribe(final Disposable d) {
DisposableHelper.replace(parent, d);
}
#Override
public void onError(final Throwable e) {
downstream.onError(e);
}
The returned Single returns a Single#error, which emits a Throwable via #onError. Given #onError will be delegated to the downstream subscriber via onError.
Performance wise one could be faster than the other, but this must be measured to have an exact image. Returning Single#error does more allocations and has more methods on the Stack (subscribeActual). On the other side, when throwing a Throwable it must be caught and handeled.
Therefore in my opinion it acutally does not matter, whether you use the one or the other.
Related
I want to throw Exceptions that are extended from Exception if Try.ofCallable() fails.
I have a callable of the type:
final Callable<MyResponse> decoratedCallable =
circuitBreakerService.getDecoratedMethod(
myArg1,
() -> myFunction(myArg1, myArg2, myArg3)
);
I am trying something like this:
Try.ofCallable(decoratedCallable).onFailure(throwable -> {
if (throwable instanceof CallNotPermittedException) {
throw new MyRuntimeExceptionA("msg1", throwable);
} else {
throw new MyRuntimeExceptionB("msg2", throwable);
}
});
This works (the function that wraps the above two statements throws the correct exception MyRuntimeExceptionA and MyRuntimeExceptionB) if both MyRuntimeExceptionA and MyRuntimeExceptionB extend RuntimeException, but not if they extend Exception.
If they extend Exception then I am not able to throw them from the main function.
The IDE asks to wrap them in try/catch - which I don't want.
You have two options. You can throw when you try to unwrap the Try by getting the value with the following code:
Try.ofCallable(decoratedCallable)
.getOrElseThrow(throwable -> {
if (throwable instanceof CallNotPermittedException) {
return new MyExceptionA("msg1", throwable);
} else {
return new MyExceptionB("msg2", throwable);
}
})
or move out the error mapping code to before unwrapping with a similar code:
Try.ofCallable(decoratedCallable)
.mapFailure(
Case(
$(instanceOf(CallNotPermittedException.class)),
throwable -> new MyExceptionA("msg1", throwable)
),
Case($(), throwable -> new MyExceptionB("msg2", throwable))
)
.get()
Both solutions will only throw when unrwapping, so if you want to throw early, you will have to unwrap early.
Otherwise, I would take the advice others posted in comments not to throw exceptions if you are using Try. The whole point in using Try is to work with total functions instead of partial functions that can throw exceptions.
I don't know much about vavr, but looking in the javadoc for the library, you can see the onFailure method takes a Consumer<? super Throwable> as a parameter. The problem is that consumers do not declare checked exceptions, so you will never be able throw checked exceptions from your lambda.
That being said, what I generally do in these cases is I create a "wrapping" class that will accept checked exceptions, all this wrapping class will do is catch any checked exceptions and wrap them in a runtime exception. For example:
public class ThrowingConsumerHelper {
public static <T> Consumer<T> throwingConsumer(
ThrowingConsumer<T> consumer) {
return object -> {
try {
consumer.accept(object);
} catch (Throwable t) {
throw new RuntimeException(t);
}
};
}
#FunctionalInterface
public interface ThrowingConsumer<T> {
void accept(T t) throws Exception;
}
}
And then use this like this:
import static ThrowingConsumerHelper.throwingConsumer;
public static void main(String[] args) {
onFailure(throwingConsumer(object -> { throw new Exception("Bug"); }));
}
public static void onFailure(Consumer<? super Throwable> consumer) {
// Do something
}
Given a function that might throw:
public static int f() throws Exception {
// do something
}
Is there any way this code:
public static int catchF() throws Exception {
try {
return f();
} catch (Exception ex) {
throw ex;
}
}
is any different to calling f directly? I.e. could the caller detect the difference by inspecting the exception? Is there any discernible overhead in using catchF instead of f?
If there is no difference, can compilers, or the JVM, optimise a call to catchF into a direct call to f?
While this might seem like a strange thing to do, the use case would be to re-introduce an exception at the type level after earlier hiding it:
class Test {
// Hide the exception.
public static <X extends Exception, T> T throwUnchecked(Exception ex) throws X {
throw (X) ex;
}
// Interface for functions which throw.
interface Throws<T, R, X extends Exception> {
R apply(T t) throws X;
}
// Convert a function which throws a visible exception into one that throws a hidden exception.
public static <T, R, X extends Exception> Function<T, R> wrap(Throws<T, R, X> thrower) {
return t -> {
try {
return thrower.apply(t);
} catch(Exception ex) {
return throwUnchecked(ex);
}
};
}
// Unhide an exception.
public static <R, X extends Exception> R unwrap(Supplier<R> supp) throws X {
try {
return supp.get();
} catch (Exception ex) {
throw (X)ex;
}
}
public static Stream<Integer> test(Stream<String> ss) throws NumberFormatException {
return Test.<Stream<Integer>, NumberFormatException>unwrap(
() -> ss.map(wrap(Integer::parseInt))
);
}
public static void main(String[] args) throws NumberFormatException {
final List<Integer> li = test(Arrays.stream(new String[]{"1", "2", "3"})).collect(toList());
System.out.println(li);
}
}
The intent is to wrap functions that throw exception into ones where the exception is hidden at the type level. This makes the exceptions usable for example with streams.
is any different to calling f directly?
No.
I.e. could the caller detect the difference by inspecting the exception?
No, because you're not constructing a new exception at this point. The stack trace was constructed at the point where the new WhateverException(...) was invoked (not where the throw was, although they are often in the same place).
Typically, you rethrow a caught exception if you need to do some cleanup as a result of the exception:
try {
// ...
} catch (SomeException e) {
// Clean up resources.
throw e;
}
The fact that something happened as the call stack was unwound is neither visible nor relevant to the caller.
A quick demo can show that the stack traces are identical whether the exception is caught and rethrown or simply allowed to propagate.
Is there any discernible overhead in using catchF instead of f?
The overhead of constructing the exception will far outweight any overhead of this redundant construct.
An exception handler that simply rethrows and does not affect the known types of the exceptions has absolutely no semantic effect.
In theory, then, compilers or the JVM could optimize the try-catch out. In practice, I doubt that they do, because such code should be rare and not on hot paths (exceptions should never be); it's probably not worth the effort to implement such an optimization.
Is there a way to have an Observable just throw an exception that occurs from within a function like flatMap()?
In Java, on a normal function, you can specify that it may throw an exception:
public void dangerousFunction() throws IOException {}
Within an Observable function like flatMap(), I can't seem to find a similar syntax. I can use a try/catch like this:
myObservable.flatMap(() -> {
try {
return dangerousFunction();
} catch (IOException e) {
return Observable.error(e);
}
});
Is there a cleaner method for writing that? If I have lots of maps and/or Observables, that winds up being a lot of try/catch blocks cluttering up my code.
The standard approach to dealing with exceptions in a RxJava map() method is propagate the exception by catch-and-throw. For example:
.map(b -> {
try {
...
} catch (IOException ex) {
// manual catch and throw
throw new RuntimeException(ex);
// or catch-and-throw using a built-in helper
throw Exceptions.propagate(e);
}
})
This can be get quite verbose when repeated across multiple map() calls so you could define a helper to wrap this behaviour e.g.
observable.map(RxMapWrapper.wrapAndThrow(new RxMapWrapper.Func1Wrapper<A, B>() {
#Override
public B call(A document) throws Exception {
// your map logic here ...
}
}))
public class RxMapWrapper {
public static <T, R> Func1<T, R> wrapAndThrow(Func1Wrapper<T, R> caughtFunction) {
return t -> {
try {
return caughtFunction.call(t);
} catch (Exception e) {
throw Exceptions.propagate(e);
}
};
}
public interface Func1Wrapper<T, R> extends Function {
R call(T t) throws Exception;
}
}
If you only want to return Observable.error(e) inside catch blocks, you don't need try/catch at all. Exception would go to downstream and .subscribe(,throwable) will catch it anyway.
If you want to return some other/default object when error occurred, try these operators: onErrorReturnItem, onErrorResumeNext, onErrorReturn. This would be cleaner.
Other option would be implementing this onErrorReturnItem mechanism into your methods itself instead of throwing Exception.
I have example code from a third party related to some API. It doesn't run because of an unhandled exception in a return statement.
The problem: The return type is an interface whose instances are always created with complicated factories (assume I do not have access to these). Thus even if I handle the exception in the stupid do-nothing way, I still can't return a valid dummy object.
public FunnyInterface calculateSomething()
{
return builder.someFunnyInterface(); // throws Exception
}
To get this code to run, is there anything I can do not involving:
modifying the code along the route where calculateSomething() is called,
finding a builder in the API that won't throw an Exception, or
manually writing a dummy class implementing the interface
?
Since you wrote that you can't call the builder, I guess that you are not interested in the value of type FunnyInterface, so just return null.
public FunnyInterface calculateSomething() {
try {
return builder.someFunnyInterface(); // throws Exception
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
Or just
public FunnyInterface calculateSomething() {
return null;
}
I'd recommend a simple rethrow with wrapped in a RuntimeException so you don't need to declare a checked exception:
// Dummy mockup interface + function
public static interface FunnyInterface {}
public static FunnyInterface builder_someFunnyInterface() throws Exception { return null; }
public FunnyInterface calculateSomething() {
try {
return builder_someFunnyInterface(); // throws Exception
} catch (Exception e) {
throw new RuntimeException(e);
}
}
I would not return null. If you don't have a meaningful way to handle the error, propagate it upwards to a level that does have a meaningful way to handle the error. If you really do want to return null/empty, then use Optional, otherwise throwing an unchecked RuntimeException is preferable.
What I want is a standard JDK class that look like this:
interface ExplodingRunnable {
void run() throws Exception;
}
Callable is no good, because its call() method is required to return a value, but I need a void.
Runnable is no good, because its run() method doesn't declare throws Exception.
I sort of need a combination of the two. Any ideas?
EDIT: I should have mentioned that I tried Callable<Void> but it requires you to define a method:
public Void call() {
// run your code;
return null; // ugly!
}
I'm looking for something a bit nicer.
Why do I want this?
I'm implementing a standard why of catching "will never happen" Exceptions (they will never happen, but various APIs define their methods throwing Exceptions) and throwing any Exceptions that might occur by wrapping them in an (unchecked) RuntimeException, so the caller can simply pass a "ExplodingRunnable" in and not have to code loads of perfunctory try/catch blocks that will never be exercised.
FINAL EDIT It looks like what I was looking for doesn't exist. The accepted answer is the closest to "correct", but it looks like there is no solution to answer the question as asked.
Could you just use Callable<Void>?
An interface with only one method, which returns void and throws Exception.
Among all java and javax classes, only one fits that description:
package java.lang;
public interface AutoCloseable
{
void close() throws Exception;
}
Well... the word "close" has many meanings...
You want to surround a bunch of statements with some extra handling, there is no sin to define your own interface here. You may find that your API requires users to learn 4 new phrases
Util.muckException( new ExplodingRunnable() { public void run() throws Exception
^1 ^2 ^3 ^4
You can actually cut down two, and user code would look like this
new MuckException(){ public void run() throws Exception
{
statement_1;
...
statement_n;
}};
public abstract class MuckException
{
public abstract run() throws Exception;
public MuckException()
{
try{ run(); }
catch(Exception e){ throw new Error(e); }
}
}
Just use Callable, ignore the return value and document things as ignoring the returned value and recommend returning null. Just because you can return something does not mean you have to.
I would just use Callable<Void> and learn to love it. ;)
You can have the checked exception not declared with the following.
Runnable runs = new Runnable() {
public void run() {
try {
// do something
} catch(Exception e) {
// rethrows anything without the compiler knowing.
// the method is deprecated but can be used on the current thread.
Thread.currentThread().stop(e);
}
}
});
Future future = executorService.submit(run);
try {
future.get();
} catch (ExecutionException ee) {
Throwable e = ee.getCause(); // can be the checked exception above.
}
and not have to code loads of perfunctory try/catch blocks that will never be exercised.
I had the same issue and fixed it a little differently
// Exceptions class
public RuntimeException wrap(Exception e) {
return e instanceof RuntimeException ? ((RuntimeException)e) : new RuntimeException(e);
}
// user code
try {
foo.bar();
} catch (Exception e) {
throw Exceptions.wrap(e);
}