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.
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
}
I would like to two have two different methods running in catch and final blocks. I have found AutoCloseable interface, but I need something to fire in case of exception only.
Like:
SomeService service = CreateService().andOpenTransaction()
try {
service.doSomeMessyThingsInsideDB();
} catch (Exception e) {
service.rollbackTransaction();
throw e;
} finally {
service.closeConnection();
}
Is there any way to make it simpler? As I said I am familiar with AutoCloseable, but it helps me only with finally block. I still cannot use it inside the catch.
Well you could define your own interface, and then some static runner method:
public interface ErrorHandlingCloseable extends AutoCloseable {
void run() throws Exception;
void onError(Exception e);
static void execute(ErrorHandlingClosable ehc) throws Exception {
try(ErrorHandlingClosable temp = ehc) {
ehc.run();
} catch(Exception e) {
ehc.onError(e);
throw e;
}
}
}
Which you then could then call like this:
SomeService service = CreateService().andOpenTransaction();
ErrorHandlingCloseable.execute(new ErrorHandlingCloseable() {
public void run() throws Exception { service.doSomeMessyThingsInsideDB(); }
public void onError(Exception e) { service.rollbackTransaction(); }
public void close() throws Exception { service.closeConnection(); }
});
But you see, it's still messy.
You could even implement this interface in your SomeService but then you're restricted that the run() method will always call doSomeMessyThingsInsideDB().
Another way but still similar would be to use Java8 and create a helper functional interface:
public interface ThrowingRunnable {
void run() throws Exception;
}
And then a static method somewhere:
public static void execute(ThrowingRunnable action,
ThrowingRunnable onCatch,
ThrowingRunnable onFinally) throws Exception {
try(AutoCloseable ao = onFinally) {
action.run();
} catch(Exception e) {
onCatch.run();
throw e;
}
}
The interesting part is probably this: try(AutoCloseable ao = onFinally), which "registers" your onFinally method to be called when finally is reached.
This could then be called like this:
execute(
service::doSomeMessyThingsInsideDB,
service::rollbackTransaction,
service::closeConnection
);
You said you are familiar with AutoCloseable, but you don't use it.
Have you considered using try-with-resources statement?
Your code can be simplified to:
try (SomeService service = CreateService().andOpenTransaction()) {
service.doSomeMessyThingsInsideDB();
} catch(exception e){
service.rollbackTransaction();
throw e;
}
Oracle has great doc for that, including examples.
Note: A try-with-resources statement can have catch and finally blocks just like an ordinary try statement. In a try-with-resources statement, any catch or finally block is run after the resources declared have been closed.
Answering your question, this is as simple as it can get.
If your class doesn't implement Closeable then you can either implement it or use finally.
First step: Handling the exception
You evidently want the exception handled before some close. Then you need inside a try-with-resources to handle the exception.
/** throws RuntimeException */
void process(Callable<Void> work, Consumer<Exception> onFail) {
try {
work.call();
} catch (Exception e) {
onFail(e);
}
}
try (SomeService service = CreateService().andOpenTransaction()) {
process(() -> service.doSomeMessyThingsInsideDB(),
e -> {
service.rollbackTransaction();
throw new IllegalStateException(e);
});
}
This is not very satisfactory, but again also integrating the AutoCloseable, might give too few use-cases.
Second step: with AutoCloseable
<SV extends AutoCloseable> void processAutoClosing(Supplier<SV> serviceFactory,
Callable<Void> work, Consumer<Exception> onFail) {
try (SV service = serviceFactory.get()) {
process(work, onFail);
}
}
processAutoClosing(...);
So I have 20 setters in a row all of which could potentially fail. Rather than skip them all if one fails or surround them each with a try catch is there a way to do this with some of Java 8s features?
For example, I was thinking something like this:
public void mapElement(Function function) {
try the function
catch if something goes wrong
}
Then I could use this like so:
mapElement(myObject.putA(a));
mapElement(myObject.putB(b));
mapElement(myObject.putC(c));
....
How about something like this:
public void tryTo(Runnable action) {
try {
action.run();
} catch (Exception e) {
// do something?
}
}
tryTo(() -> myObject.putA(a));
tryTo(() -> myObject.putB(b));
tryTo(() -> myObject.putC(c));
Note that myObject, a, b and c all need to be effectively final for this to work.
A spin on the above is to have a single method that takes an array of Runnables and executes them in a loop:
public void tryAll(Runnable... actions) {
for (Runnable action : actions) {
try {
action.run();
} catch (Exception e) {
// do something?
}
}
}
tryAll(() -> myObject.putA(a),
() -> myObject.putB(b),
() -> myObject.putC(c));
You could use the Runnable functional interface.
Its function descriptor is () -> void.
It suits perfectly for your need as the mapping operation returns no result and you don't need to specify any parameter as input of the function either.
Indeed here : myObject.putA(a), you don't want to pass the a parameter to the function.
You want rather pass the whole expression myObject.putA(a) as a lambda body :
() -> myObject.putA(a);
You could so write this mapElement() method :
public static void mapElement(Runnable mapProcessor) {
// Retry logic
try {
mapProcessor.run();
} catch (Exception e) {
// exception handling
}
}
Note that to catch any Java exception (both checked and runtime), you have to catch RuntimeException rather than Exception.
And you can use mapElement() in this way :
MyObject myObject = new MyObject();
...
mapElement(() -> myObject.putA(a));
mapElement(() -> myObject.putB(b));
mapElement(() -> myObject.putC(c));
Runnable may not convey the expected meaning as it was primarily
designed for thread execution.
If it makes sense you also may introduce your own functional interface.
With this way, you may also declare any specific checked exception in the function if it appears relevant.
Which is not possible with Runnable.
For example :
#FunctionalInterface
public interface MapProcessor{
void map() throws MappingException;
}
You could so use it in this way :
public static void mapElement(MapProcessor mapProcessor) {
// Retry logic
try {
mapProcessor.map();
}
catch (MappingException e) {
// Mapping exception handling
}
catch (Exception e) { // or RuntimeException if more relevant
// other exception handling
}
}
I have observed that Hystrix treats all exceptions coming out of commands as failures for circuit breaking purposes. It includes exceptions which are thrown from command run () method and created by Hystrix itself, e.g. HystrixTimeoutException.
But I have business exceptions to be thrown from run() method that signify that service responded with valid error which has to be processed further.
One example of such exception is WebServiceFaultException while using WebServiceTemplate from SpringWS.
So I do not need those specific exceptions to trip the circuit.
How this behavior can be achieved?
There is an obvious way of wrapping business exceptions into a holder object, returning it from run() method, then unwrapping it back to the Exception and rethrow. But it was wondering if there is a cleaner way.
There are following solutions available.
Return exception instead of throwing
Most straightforward and dirty approach. This looks a little funky, because you have to erase the command to Object and there is a lot of type casting.
Observable<BusinessResponse> observable = new HystrixCommand<Object>() {
#Override
protected Object run() throws Exception {
try {
return doStuff(...);
} catch (BusinessException e) {
return e; // so Hystrix won't treat it as a failure
}
}
})
.observe()
.flatMap(new Func1<Object, Observable<BusinessResponse>>() {
#Override
public Observable<BusinessResponse> call(Object o) {
if (o instanceof BusinessException) {
return Observable.error((BusinessException)o);
} else {
return Observable.just((BusinessResponse)o);
}
}
});
Use holder object to hold both result and exception
This apporach requires introduction of additional holder class (which can also be used on it's own for other purposes).
class ResultHolder<T, E extends Exception> {
private T result;
private E exception;
public ResultHolder(T result) {
this.result = result;
}
public ResultHolder(E exception) {
if (exception == null) {
throw new IllegalArgumentException("exception can not be null");
}
this.exception = exception;
}
public T get() throws E {
if (exception != null) {
throw exception;
} else {
return result;
}
}
public Observable<T> observe() {
if (exception != null) {
return Observable.error(exception);
} else {
return Observable.just(result);
}
}
#SuppressWarnings("unchecked")
public static <T, E extends Exception> ResultHolder<T, E> wrap(BusinessMethod<T, E> method) {
try {
return new ResultHolder<>(method.call());
} catch (Exception e) {
return new ResultHolder<>((E)e);
}
}
public static <T, E extends Exception> Observable<T> unwrap(ResultHolder<T, E> holder) {
return holder.observe();
}
interface BusinessMethod<T, E extends Exception> {
T call() throws E;
}
}
Now code that uses it looks much cleaner, the only downside might be a fair amount of generics. Also this approach is at it's best in Java 8 where lambdas and method references are available, otherwise it will look clunky.
new HystrixCommand<ResultHolder<BusinessResponse, BusinessException>>() {
#Override
protected ResultHolder<BusinessResponse, BusinessException> run() throws Exception {
return ResultHolder.wrap(() -> doStuff(...));
}
}
.observe()
.flatMap(ResultHolder::unwrap);
Use HystrixBadRequestException
HystrixBadRequestException is a special kind of exception which will not count as a failure in terms of circuit breaker and metrics. As seen in documentation:
Unlike all other exceptions thrown by a HystrixCommand this will not
trigger fallback, not count against failure metrics and thus not
trigger the circuit breaker.
Instances of HystrixBadRequestException are not created by Hystrix itself, so it is safe to use it as a wrapper for business exceptions. However, original business exception still requires to be unwrapped.
new HystrixCommand<BusinessResponse>() {
#Override
protected BusinessResponse run() throws Exception {
try {
return doStuff(...);
} catch (BusinessException e) {
throw new HystrixBadRequestException("Business exception occurred", e);
}
}
}
.observe()
.onErrorResumeNext(e -> {
if (e instanceof HystrixBadRequestException) {
e = e.getCause(); // Unwrap original BusinessException
}
return Observable.error(e);
})
I have a method that deletes some files:
void deepDelete(Path root) {
Files.walk(root)
.filter(p -> !Files.isDirectory(p))
.forEach(p -> { try { Files.delete(p); }
catch (IOException e) { /* LOG */ }
});
}
The try/catch block reduces the readability of the operation, especially vs. using a method reference:
void deepDelete(Path root) throws IOException {
Files.walk(root)
.filter(p -> !Files.isDirectory(p))
.forEach(Files::delete); //does not compile
}
Unfortunately that code does not compile.
Is there a way to apply an action that throws checked exceptions in a terminal operation and simply "rethrow" any exceptions?
I understand that I could write a wrapper that transforms the checked exception into an unchecked exception but I would rather stick to methods in the JDK if possible.
As far as I can tell: no. I use this techempower article as my java8 guide, and it's pretty explicit (see the section headed "Exception transparency").
If you declare this method:
#SuppressWarnings("unchecked")
static <T extends Throwable> RuntimeException sneakyThrow(Throwable t) throws T {
throw (T)t;
}
Then you can do:
try {
Files.delete(p);
} catch (IOException e) {
throw sneakyThrow(e);
}
This bypasses the checked exception rules and throws the raw IOException without wrapping, although you still have to catch it & rethrow. I'm not saying this is a good idea, but it's an idea.