Suppose I have a class defining a big block of work to be done, that can produce several checked Exceptions.
class WorkerClass{
public Output work(Input input) throws InvalidInputException, MiscalculationException {
...
}
}
Now suppose I have a GUI of some sort that can call this class. I use a SwingWorker to delegate the task.
Final Input input = getInput();
SwingWorker<Output, Void> worker = new SwingWorker<Output, Void>() {
#Override
protected Output doInBackground() throws Exception {
return new WorkerClass().work(input);
}
};
How can I handle the possible exceptions thrown from the SwingWorker? I want to differentiate between the Exceptions of my worker class (InvalidInputException and MiscalculationException), but the ExecutionException wrapper complicates things. I only want to handle these Exceptions - an OutOfMemoryError should not be caught.
try{
worker.execute();
worker.get();
} catch(InterruptedException e){
//Not relevant
} catch(ExecutionException e){
try{
throw e.getCause(); //is a Throwable!
} catch(InvalidInputException e){
//error handling 1
} catch(MiscalculationException e){
//error handling 2
}
}
//Problem: Since a Throwable is thrown, the compiler demands a corresponding catch clause.
catch (ExecutionException e) {
Throwable ee = e.getCause ();
if (ee instanceof InvalidInputException)
{
//error handling 1
} else if (ee instanceof MiscalculationException e)
{
//error handling 2
}
else throw e; // Not ee here
}
You could use an ugly (smart?) hack to convert the throwable into an unchecked exception. The advantage is that the calling code will receive whatever exception was thrown by your worker thread, whether checked or unchecked, but you don't have to change the signature of your method.
try {
future.get();
} catch (InterruptedException ex) {
} catch (ExecutionException ex) {
if (ex.getCause() instanceof InvalidInputException) {
//do your stuff
} else {
UncheckedThrower.throwUnchecked(ex.getCause());
}
}
With UncheckedThrower defined as:
class UncheckedThrower {
public static <R> R throwUnchecked(Throwable t) {
return UncheckedThrower.<RuntimeException, R>trhow0(t);
}
#SuppressWarnings("unchecked")
private static <E extends Throwable, R> R trhow0(Throwable t) throws E {
throw (E) t;
}
}
Try/multi-catch:
try {
worker.execute();
worker.get();
} catch (InterruptedException e) {
//Not relevant
} catch (InvalidInputException e) {
//stuff
} catch (MiscalculationException e) {
//stuff
}
Or with the ExecutionException wrapper:
catch (ExecutionException e) {
e = e.getCause();
if (e.getClass() == InvalidInputException.class) {
//stuff
} else if (e.getClass() == MiscalculationException.class) {
//stuff
}
}
Or if you want exceptions' subclasses to be treated like their parents:
catch (ExecutionException e) {
e = e.getCause();
if (e instanceof InvalidInputException) {
//stuff
} else if (e instanceof MiscalculationException) {
//stuff
}
}
Related
How can I refactor below catch block I am using java11
Code
public String methodName(ClassRequest request, Destination ABC) {
try {
<Some Code Here>
} catch (Exception e) {
log.error("error", ABC, e);
if(e instanceof ABCRestException ||
(ABC == PREM && (e instanceof HttpServerErrorException || e instanceof HttpClientErrorException))) {
throw e;
} else if(e instanceof HttpServerErrorException) {
throw new ABCRestException(request.getAId(), "unexpected_error", "Some Message", e, INTERNAL_SERVER_ERROR);
} else if(e instanceof HttpClientErrorException) {
throw new ABCRestException(request.getAId(), "missing_field", "Some Message", e, BAD_REQUEST);
} else {
throw new ABCRestException(request.getAId(), "unexpected_error", "Some Massage", e, INTERNAL_SERVER_ERROR);
}
}
}
How I can refactor this code Means catch block
you just need two catch blocks like this
public String methodName(ClassRequest request, Destination ABC) {
try {
<Some Code Here>
} catch (HttpServerErrorException e) {
log.error("error", ABC, e);
if (ABC == PREM){
throw e;
}else{
throw new ABCRestException(request.getAId(), "unexpected_error", "Some Message", e, INTERNAL_SERVER_ERROR);
}
} catch (HttpClientErrorException e){
if (ABC == PREM){
throw e;
}else{
throw new ABCRestException(request.getAId(), "missing_field", "Some Message", e, BAD_REQUEST);
}
}
}
If you want to reuse some logic, you can write a private method and invoke it inside the catch block
If two or more exceptions share the same exact logic you can also use a multi-catch which will catch various exceptions in the same block
try{
codeGoesVroomVroomAndThrows()
}catch(ExceptionA | ExceptionB e){
//do something
}
In Java, if I declare and caught an exception, can I handle the exception in a caller anyway? Or it needs not to be caught to handle it by caller?
class A {
void first() throws Exception {
try {
throw new Exception("my exception")
} catch (Exception e) {
log.message("Error in first()", e.getCouse)
throw e
}
}
}
class B {
Result second(A a) {
try {
a.first()
} catch (Exception e) {
log.message("Caught in B class", e.message)
return new Result(result: null, error: e.message)
}
}
second(A a)
}
You can simply rethrow the exception you've caught (obviously the surrounding method has to permit this via its signature etc.). The exception will maintain the original stack trace.
catch (WhateverException e) {
throw e;
}
You can also wrap the exception in another one AND keep the original stack trace by passing in the Exception as a Throwable as the cause parameter:
try
{
...
}
catch (Exception e)
{
throw new YourOwnException(e);
}
I recently started using RxJava 2 and am wondering if its possible to catch more specific Exceptions when calling Completable.blockingAwait().
This is what I am doing:
try {
Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(#NonNull CompletableEmitter e) throws Exception {
e.onError(new IOException());
}
}).blockingAwait();
} catch (RuntimeException e) {
Throwable cause = e.getCause();
if(cause instanceof IOException) {
// Handle IOException
}
}
And this is what I would like to do:
try {
Completable.create(new CompletableOnSubscribe() {
#Override
public void subscribe(#NonNull CompletableEmitter e) throws Exception {
e.onError(new IOException());
}
}).blockingAwait();
} catch (IOException e) {
// Handle IOException
}
Is there any possibility to make this work?
A couple of lines down in the linked Javadoc there is the blockingGet operator that returns a Throwable which you can do instanceof checks with:
Throwable err = Completable.error(new IOException()).blockingGet();
if (err instanceof IOException) {
// ...
}
Please pay attention: caller throws parentexception only!!
Say that aexception, and bexception inherit from parentexception.
In method af, it throws aexception, bexception and parentexception.
void af() throws aexception, bexception, parentexception {}
The method caller calls af and throw parentexception only.
void caller() throws parentexception
Here we lost the information of subclasses of parentexception.
The method rootCaller calls the method caller and rootcaller can only catch parentexception thrown by caller and using the following exception process catch block:
void rootCaller() {
try {
caller();
} catch(parentexception e) {
if(e instanceof aexception) {
......
} else if(e instanceof bexception) {
......
} else if(e instanceof parentexception) {
......
} else {
......
}
}
This is so ugly and very easy to forget some subclass of parentexception if the subclasses are too many.
Is there anyway to improve such code?
Current answer can not give me any idea:
1, rootCaller cannnot use multi-catch to simplify the process cause caller only throw parentexception.
2, because caller only throw parentexception, there is not any other exception check if the af is changed latter to throws more than aexception and bexception, say cexception.
As others have suggested in the comments, you should be using multiple catch clauses.
void rootCaller() {
try {
caller();
} catch (AException e) {
// ...
} catch (ParentException e) {
// ...
} catch (BException e) {
// ...
} catch (AnotherException e) {
// ...
} catch (Exception e) {
// ...
}
}
The order of the catches matters too. The Exception will be tested against each case in turn and only trigger the first one that matches.
So for example with AException and BException extending ParentException in my above code the catch (BException e) block can never be reached as catch (ParentException e) is reached and executed first.
Is it possible to catch all exceptions of a method, except for a specific one, which should be thrown?
void myRoutine() throws SpecificException {
try {
methodThrowingDifferentExceptions();
} catch (SpecificException) {
//can I throw this to the next level without eating it up in the last catch block?
} catch (Exception e) {
//default routine for all other exceptions
}
}
/Sidenote: the marked "duplicate" has nothing to do with my question!
void myRoutine() throws SpecificException {
try {
methodThrowingDifferentExceptions();
} catch (SpecificException se) {
throw se;
} catch (Exception e) {
//default routine for all other exceptions
}
}
you can do like this
try {
methodThrowingDifferentExceptions();
} catch (Exception e) {
if(e instanceof SpecificException){
throw e;
}
}