Related
Consider the following code:
public Object getClone(Cloneable a) throws TotallyFooException {
if (a == null) {
throw new TotallyFooException();
}
else {
try {
return a.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
//cant be reached, in for syntax
return null;
}
The return null; is necessary since an exception may be caught, however in such a case since we already checked if it was null (and lets assume we know the class we are calling supports cloning) so we know the try statement will never fail.
Is it bad practice to put in the extra return statement at the end just to satisfy the syntax and avoid compile errors (with a comment explaining it will not be reached), or is there a better way to code something like this so that the extra return statement is unnecessary?
A clearer way without an extra return statement is as follows. I wouldn't catch CloneNotSupportedException either, but let it go to the caller.
if (a != null) {
try {
return a.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
throw new TotallyFooException();
It's almost always possible to fiddle with the order to end up with a more straight-forward syntax than what you initially have.
It definitely can be reached. Note that you're only printing the stacktrace in the catch clause.
In the scenario where a != null and there will be an exception, the return null will be reached. You can remove that statement and replace it with throw new TotallyFooException();.
In general*, if null is a valid result of a method (i.e. the user expects it and it means something) then returning it as a signal for "data not found" or exception happened is not a good idea. Otherwise, I don't see any problem why you shouldn't return null.
Take for example the Scanner#ioException method:
Returns the IOException last thrown by this Scanner's underlying Readable. This method returns null if no such exception exists.
In this case, the returned value null has a clear meaning, when I use the method I can be sure that I got null only because there was no such exception and not because the method tried to do something and it failed.
*Note that sometimes you do want to return null even when the meaning is ambiguous. For example the HashMap#get:
A return value of null does not necessarily indicate that the map contains no mapping for the key; it's also possible that the map explicitly maps the key to null. The containsKey operation may be used to distinguish these two cases.
In this case null can indicate that the value null was found and returned, or that the hashmap doesn't contain the requested key.
Is it bad practice to put in the extra return statement at the end just to satisfy the syntax and avoid compile errors (with a comment explaining it will not be reached)
I think return null is bad practice for the terminus of an unreachable branch. It is better to throw a RuntimeException (AssertionError would also be acceptable) as to get to that line something has gone very wrong and the application is in an unknown state.
Most like this is (like above) because the developer has missed something (Objects can be none-null and un-cloneable).
I'd likely not use InternalError unless I'm very very sure that the code is unreachable (for example after a System.exit()) as it is more likely that I make a mistake than the VM.
I'd only use a custom exception (such as TotallyFooException) if getting to that "unreachable line" means the same thing as anywhere else you throw that exception.
You caught the CloneNotSupportedException which means your code can handle it. But after you catch it, you have literally no idea what to do when you reach the end of the function, which implies that you couldn't handle it. So you're right that it is a code smell in this case, and in my view means you should not have caught CloneNotSupportedException.
I would prefer to use Objects.requireNonNull() to check if the Parameter a is not null. So it's clear when you read the code that the parameter should not be null.
And to avoid checked Exceptions I would re throw the CloneNotSupportedException as a RuntimeException.
For both you could add nice text with the intention why this shouldn't happen or be the case.
public Object getClone(Object a) {
Objects.requireNonNull(a);
try {
return a.clone();
} catch (CloneNotSupportedException e) {
throw new IllegalArgumentException(e);
}
}
The examples above are valid and very Java. However, here's how I would address the OP's question on how to handle that return:
public Object getClone(Cloneable a) throws CloneNotSupportedException {
return a.clone();
}
There's no benefit for checking a to see if it is null. It's going to NPE. Printing a stack trace is also not helpful. The stack trace is the same regardless of where it is handled.
There is no benefit to junking up the code with unhelpful null tests and unhelpful exception handling. By removing the junk, the return issue is moot.
(Note that the OP included a bug in the exception handling; this is why the return was needed. The OP would not have gotten wrong the method I propose.)
In this sort of situation I would write
public Object getClone(SomeInterface a) throws TotallyFooException {
// Precondition: "a" should be null or should have a someMethod method that
// does not throw a SomeException.
if (a == null) {
throw new TotallyFooException() ; }
else {
try {
return a.someMethod(); }
catch (SomeException e) {
throw new IllegalArgumentException(e) ; } }
}
Interestingly you say that the "try statement will never fail", but you still took the trouble to write a statement e.printStackTrace(); that you claim will never be executed. Why?
Perhaps your belief is not that firmly held. That is good (in my opinion), since your belief is not based on the code you wrote, but rather on the expectation that your client will not violate the precondition. Better to program public methods defensively.
By the way, your code won't compile for me. You can't call a.clone() even if the type of a is Cloneable. At least Eclipse's compiler says so. Expression a.clone() gives error
The method clone() is undefined for the type Cloneable
What I would do for your specific case is
public Object getClone(PubliclyCloneable a) throws TotallyFooException {
if (a == null) {
throw new TotallyFooException(); }
else {
return a.clone(); }
}
Where PubliclyCloneable is defined by
interface PubliclyCloneable {
public Object clone() ;
}
Or, if you absolutely need the parameter type to be Cloneable, the following at least compiles.
public static Object getClone(Cloneable a) throws TotallyFooException {
// Precondition: "a" should be null or point to an object that can be cloned without
// throwing any checked exception.
if (a == null) {
throw new TotallyFooException(); }
else {
try {
return a.getClass().getMethod("clone").invoke(a) ; }
catch( IllegalAccessException e ) {
throw new AssertionError(null, e) ; }
catch( InvocationTargetException e ) {
Throwable t = e.getTargetException() ;
if( t instanceof Error ) {
// Unchecked exceptions are bubbled
throw (Error) t ; }
else if( t instanceof RuntimeException ) {
// Unchecked exceptions are bubbled
throw (RuntimeException) t ; }
else {
// Checked exceptions indicate a precondition violation.
throw new IllegalArgumentException(t) ; } }
catch( NoSuchMethodException e ) {
throw new AssertionError(null, e) ; } }
}
Is having a return statement just to satisfy syntax bad practice?
As others have mentioned, in your case this does not actually apply.
To answer the question, though, Lint type programs sure haven't figured it out! I have seen two different ones fight it out over this in a switch statement.
switch (var)
{
case A:
break;
default:
return;
break; // Unreachable code. Coding standard violation?
}
One complained that not having the break was a coding standard violation. The other complained that having it was one because it was unreachable code.
I noticed this because two different programmers kept re-checking the code in with the break added then removed then added then removed, depending on which code analyzer they ran that day.
If you end up in this situation, pick one and comment the anomaly, which is the good form you showed yourself. That's the best and most important takeaway.
It isn't 'just to satisfy syntax'. It is a semantic requirement of the language that every code path leads to a return or a throw. This code doesn't comply. If the exception is caught a following return is required.
No 'bad practice' about it, or about satisfying the compiler in general.
In any case, whether syntax or semantic, you don't have any choice about it.
I would rewrite this to have the return at the end. Pseudocode:
if a == null throw ...
// else not needed, if this is reached, a is not null
Object b
try {
b = a.clone
}
catch ...
return b
No one mentioned this yet so here goes:
public static final Object ERROR_OBJECT = ...
//...
public Object getClone(Cloneable a) throws TotallyFooException {
Object ret;
if (a == null)
throw new TotallyFooException();
//no need for else here
try {
ret = a.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
//something went wrong! ERROR_OBJECT could also be null
ret = ERROR_OBJECT;
}
return ret;
}
I dislike return inside try blocks for that very reason.
The return null; is necessary since an exception may be caught,
however in such a case since we already checked if it was null (and
lets assume we know the class we are calling supports cloning) so we
know the try statement will never fail.
If you know details about the inputs involved in a way where you know the try statement can never fail, what is the point of having it? Avoid the try if you know for sure things are always going to succeed (though it is rare that you can be absolutely sure for the whole lifetime of your codebase).
In any case, the compiler unfortunately isn't a mind reader. It sees the function and its inputs, and given the information it has, it needs that return statement at the bottom as you have it.
Is it bad practice to put in the extra return statement at the end
just to satisfy the syntax and avoid compile errors (with a comment
explaining it will not be reached), or is there a better way to code
something like this so that the extra return statement is unnecessary?
Quite the opposite, I'd suggest it's good practice to avoid any compiler warnings, e.g., even if that costs another line of code. Don't worry too much about line count here. Establish the reliability of the function through testing and then move on. Just pretending you could omit the return statement, imagine coming back to that code a year later and then try to decide if that return statement at the bottom is going to cause more confusion than some comment detailing the minutia of why it was omitted because of assumptions you can make about the input parameters. Most likely the return statement is going to be easier to deal with.
That said, specifically about this part:
try {
return a.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
...
//cant be reached, in for syntax
return null;
I think there's something slightly odd with the exception-handling mindset here. You generally want to swallow exceptions at a site where you have something meaningful you can do in response.
You can think of try/catch as a transaction mechanism. try making these changes, if they fail and we branch into the catch block, do this (whatever is in the catch block) in response as part of the rollback and recovery process.
In this case, merely printing a stacktrace and then being forced to return null isn't exactly a transaction/recovery mindset. The code transfers the error-handling responsibility to all the code calling getClone to manually check for failures. You might prefer to catch the CloneNotSupportedException and translate it into another, more meaningful form of exception and throw that, but you don't want to simply swallow the exception and return a null in this case since this is not like a transaction-recovery site.
You'll end up leaking the responsibilities to the callers to manually check and deal with failure that way, when throwing an exception would avoid this.
It's like if you load a file, that's the high-level transaction. You might have a try/catch there. During the process of trying to load a file, you might clone objects. If there's a failure anywhere in this high-level operation (loading the file), you typically want to throw exceptions all the way back to this top-level transaction try/catch block so that you can gracefully recover from a failure in loading a file (whether it's due to an error in cloning or anything else). So we generally don't want to just swallow up an exception in some granular place like this and then return a null, e.g., since that would defeat a lot of the value and purpose of exceptions. Instead we want to propagate exceptions all the way back to a site where we can meaningfully deal with it.
Your example is not ideal to illustrate your question as stated in the last paragraph:
Is it bad practice to put in the extra return statement at the end
just to satisfy the syntax and avoid compile errors (with a comment
explaining it will not be reached), or is there a better way to code
something like this so that the extra return statement is unnecessary?
A better example would be the implementation of clone itself:
public class A implements Cloneable {
public Object clone() {
try {
return super.clone() ;
} catch (CloneNotSupportedException e) {
throw new InternalError(e) ; // vm bug.
}
}
}
Here the catch clause should never be entered. Still the syntax either requires to throw something or return a value. Since returning something does not make sense, an InternalError is used to indicate a severe VM condition.
public class OfficeTimeXception {
public int inTime;
public int outTime;
public void anyXception() throws CoreHourXception, NormalHourException {
int k = outTime - inTime;
if (inTime > 11) {
throw new CoreHourXception(inTime - 11);
}
if (k < 8) {
throw new NormalHourException(8 + (inTime - outTime));
} else if (outTime < 16) {
throw new CoreHourXception(16 - outTime);
}
}
if my try & catch statement is
{test.inTime = 12;
test.outTime = 19;
try {
test.anyXception();
}
catch (CoreHourXception e) {
System.out.println("core hour exception by" + e.getTime()
+ " hours");
e.printStackTrace();
} catch (NormalHourException e) {
System.out.println("normal hour exception by" + e.getTime()
+ " hours");
e.printStackTrace();
}}
I need to catch both exceptions when both conditions fail....but Iam able to get only coreHourException even when both the conditions failed.
You can only throw one Exception at a time, and code execution immediately stops when you do that (the later validations are not run at all).
If you want to check for multiple errors and return all the results at once, you have to collect the validation errors in a Collection and return that Collection (for example by attaching it to a wrapper Exception).
For example
List<Exception> errors = new List<>();
if (errorConditionOne) errors.add(new CoreHourXception());
if (errorConditionTwo) errors.add(new SomeOtherException(123, "abc"));
if (!errors.isEmpty) throw new ValidationException(errors);
These objects that you put in the errors Collection do not have to be Exception objects themselves, they can be anything that you find convenient to convey the information.
Merge CoreHourXception and NormalHourException into an HoreException which reports which conditions are violated:
public class HourException extends Exception {
private boolean normalViolated_;
private boolean coreViolated_;
public HourException(String message, boolean normalViolated, boolean coreViolated) {
super(message);
normalViolated_ = normalViolated;
coreViolated_ = coreViolated;
}
public boolean isCoreViolated() {
return coreViolated_;
}
public boolean isNormalViolated() {
return normalViolated_;
}
}
This is similar to Stephen C's solution. But instead of storing multiple message strings (which cannot be evaluated easily by any exception handler), you explicitly store the information about the violated constraints.
I need to catch both exceptions when both conditions fail....
That is impossible in Java ... and every other programming language I've ever come across.
Basically, only one exception can be thrown and can propagate at a time, and therefore only one exception can be caught.
If you want your code to report all of the failures, then you need to do something like this:
Create an empty list of messages.
Check each condition, one at a time. If the condition "fails", then add an error message to the list.
When you have checked all of the conditions, see if the list is non-empty. If it is, then EITHER convert the list of messages to a string and throw an exception with that string as the message OR throw an exception with a list field, passing the list to the exception via a constructor argument.
You can then catch the exception, and deal with the (possibly) multiple error conditions it is reporting.
Cumbersome? Yes!
I have the following code:
TestClass test=new TestClass();
test.setSomething1(0); //could, but probably won't throw Exception
test.setSomething2(0); //could, but probably won't throw Exception
I would like to execute: test.setSomething2(0); even if test.setSomething(0) (the line above it) throws an exception. Is there a way to do this OTHER than:
try{
test.setSomething1(0);
}catch(Exception e){
//ignore
}
try{
test.setSomething2(0);
}catch(Exception e){
//ignore
}
I have a lot of test.setSomething's in a row and all of them could throw Exceptions. If they do, I just want to skip that line and move to the next one.
For clarification, I don't care if it throws an Exception, and I can't edit the source code of the code which throws this exception.
THIS IS A CASE WHERE I DON'T CARE ABOUT THE EXCEPTIONS (please don't use universally quantified statements like "you should never ignore Exceptions"). I am setting the values of some Object. When I present the values to a user, I do null checks anyway, so it doesn't actually matter if any of the lines of code execute.
try {
// Your code...
} catch (Exception ignore) { }
Use the word ignore after the Exception keyword.
There is no way to fundamentally ignore a thrown exception. The best that you can do is minimize the boilerplate you need to wrap the exception-throwing code in.
If you are on Java 8, you can use this:
public static void ignoringExc(RunnableExc r) {
try { r.run(); } catch (Exception e) { }
}
#FunctionalInterface public interface RunnableExc { void run() throws Exception; }
Then, and implying static imports, your code becomes
ignoringExc(() -> test.setSomething1(0));
ignoringExc(() -> test.setSomething2(0));
IntelliJ Idea IDE suggests to rename a variable to ignored
when it isn't used.
This is my sample code.
try {
messageText = rs.getString("msg");
errorCode = rs.getInt("error_code");
} catch (SQLException ignored) { }
Unfortunately no, there isn't, and this is by intention. When used correctly, exceptions should not be ignored as they indicate that something didn't work and that you probably shouldn't continue down your normal execution path. Completely ignoring exceptions is an example of the 'Sweep it under the rug' anti-pattern, which is why the language doesn't support doing so easily.
Perhaps you should look at why TestClass.setSomething is throwing exceptions. Is whatever you're trying to 'test' really going to be valid if a bunch of setter methods didn't work correctly?
You can't ignore exception in Java. If a method declares being able to throw something this is because something important can't be done, and the error can't be corrected by the method designer. So if you really wan't to simplify your life encapsulate the method call in some other method like this :
class MyExceptionFreeClass {
public static void setSomething1(TestClass t,int v) {
try {
t.setSomething1(v);
} catch (Exception e) {}
public static void setSomething2(TestClass t,int v) {
try {
t.setSomething2(v);
} catch (Exception e) {}
}
and call it when you need it:
TestClass test=new TestClass();
MyExceptionFreeClass.setSomething1(test,0);
MyExceptionFreeClass.setSomething2(test,0);
You should not ignore Exceptions. You should handle them. If you want to make your test code simple, then add the try-catch block into your functions. The greatest way to ignore exceptions is to prevent them by proper coding.
I know this is old, but I do think there are occasions when you want to ignore an exception. Consider you have a string that contains a delimited set of parts to be parsed. But, this string can sometimes contain say, 6 or 7 or 8 parts. I don't feel that checking the len each time in order to establish an element exists in the array is as straight forward as simply catching the exception and going on. For example, I have a string delimited by '/' character that I want to break apart:
public String processLine(String inLine) {
partsArray = inLine.split("/");
//For brevity, imagine lines here that initialize
//String elems[0-7] = "";
//Now, parts array may contains 6, 7, or 8 elements
//But if less than 8, will throw the exception
try {
elem0 = partsArray[0];
elem1 = partsArray[1];
elem2 = partsArray[2];
elem3 = partsArray[3];
elem4 = partsArray[4];
elem5 = partsArray[5];
elem6 = partsArray[6];
elem7 = partsArray[7];
catch (ArrayIndexOutOfBoundsException ignored) { }
//Just to complete the example, we'll append all the values
//and any values that didn't have parts will still be
//the value we initialized it to, in this case a space.
sb.append(elem0).append(elem1).append(elem2)...append(elem7);
//and return our string of 6, 7, or 8 parts
//And YES, obviously, this is returning pretty much
//the same string, minus the delimiter.
//You would likely do things to those elem values
//and then return the string in a more formatted way.
//But was just to put out an example where
//you really might want to ignore the exception
return sb.toString();
}
Those who write empty catch blocks shall burn in the Hell for the eternity.
Or worse, they will be forced to debug the damn rubbish they wrote forever and ever.
That said, one thing you might want to do is writing exception handling in a less verbose way. The NoException library is very good at that.
So basically I have a GridWorld Project that I'm doing right now in my AP Comp Sci class. I'm doing Pacman. Here is my code for the act method (for those unfamiliar with GridWorld, the act method is called every time an actor is expected to make a new move) :
public void act()
{
Location loc = getLocation();
if(direction==null) {
}
else if(direction.equals("NORTH")) {
Location next = loc.getAdjacentLocation(loc.NORTH);
if(getGrid().isValid(next) && (getGrid().get(next)==null || getGrid().get(next) instanceof Food)) {
if(getGrid().get(next) instanceof Food)
addFood();
moveTo(next);
direction = "NORTH";
}
}
else if(direction.equals("SOUTH")) {
Location next = loc.getAdjacentLocation(loc.SOUTH);
if(getGrid().isValid(next) && (getGrid().get(next)==null || getGrid().get(next) instanceof Food)) {
if(getGrid().get(next) instanceof Food)
addFood();
moveTo(getLocation().getAdjacentLocation(getLocation().SOUTH));
direction = "SOUTH";
}
}
else if(direction.equals("EAST")) {
Location next = loc.getAdjacentLocation(loc.EAST);
if(getGrid().isValid(next) && (getGrid().get(next)==null || getGrid().get(next) instanceof Food)) {
if(getGrid().get(next) instanceof Food)
addFood();
moveTo(getLocation().getAdjacentLocation(getLocation().EAST));
direction = "EAST";
}
else if(getLocation().getCol()==20 && getLocation().getRow()==9) {
moveTo(new Location(9,0));
direction = "EAST";
}
}
else if(direction.equals("WEST")) {
Location next = loc.getAdjacentLocation(loc.WEST);
if(getGrid().isValid(next) && (getGrid().get(next)==null || getGrid().get(next) instanceof Food)) {
moveTo(getLocation().getAdjacentLocation(getLocation().WEST));
direction = "WEST";
}
else if(getLocation().getCol()==0 && getLocation().getRow()==9) {
moveTo(new Location(9,20));
direction = "WEST";
}
}
}
The reason for the weird wording in the last two if statements is bc I want the Pacman to be able to teleport in the real game. Now when I run the game, about 90% of the time it works but in the other 10% I get an IllegalArgumentException bc it says I am trying to move to a place that is not on the board (eg. (9,-1) and (9,21)). I want to know how I can catch or throw or whatever I need to do to stop this from happening. I have never used catch or throw so also please try to explain your reasoning thanks!
To throw an exception, you use keyword throw. To catch, you use the try / catch construct. See this for more details:
http://docs.oracle.com/javase/tutorial/essential/exceptions/try.html
For your case, you'd do something like this - this is a test case:
try {
throw new IllegalArgumentException("Threw an IllegalArgumentException");
} catch(IllegalArgumentException e) {
System.out.println("Caught an IllegalArgumentException..." + e.getMessage());
}
You should, however, look into your code to see why IllegalArgumentException is being thrown anyway and fix that part. Using exceptions and try / catch is for unexpected events, not events that you expect to happen and that you can handle in a better way.
For example, FileNotFoundException gets thrown when a file could not be found. You generally try / catch that, so that you do something if the file was not found. However, if it's expected in a reasonable number of cases that the file might not be there, it would be better to first check if the file exists and then if it does actually do something with it.
You can catch IllegalArgumentException in the same way you catch a normal exception. Typically an IAE comes from a state that invalidates your program, so if you receive a negative index you will need to convert that to its equivalent valid value. In terms of how your program is intended to function, typically a negative index reference is not a good thing.
It seems you want to be able to catch your exceptions to keep your game running, and you are contented with parameters being wrong. So effectively you are using exceptions into the logic of the program, defeating their purpose.
An IllegalArgumentException is a runtime exception, you should not catch them and the program should just fail in some way. Simply make sure that the parameters passed are correct.
You can learn to catch and throw exceptions easily with one of the many tutorials found on Google.
However, and IllegalArgumentException means that some parameter you're sending to a third-party API is wrong. You should debug your application and see what code is causing the trouble, check the API documentation to see the requirements/constraints of the parameters you are breaking and fix it.
Of course, you can only add a catch (IllegalArgunentException e) and do nothing about it. Your program may run, but maybe it can crash later.
I want to catch an exception, that is nested into another exception.
I'm doing it currently this way:
} catch (RemoteAccessException e) {
if (e != null && e.getCause() != null && e.getCause().getCause() != null) {
MyException etrp = (MyException) e.getCause().getCause();
...
} else {
throw new IllegalStateException("Error at calling service 'service'");
}
}
Is there a way to do this more efficient and elegant?
The ExceptionUtils#getRootCause() method can come in very handy in such situations.
There is no more elegant way of selectively "catching" nested exceptions. I suppose if you did this kind of nested exception catching a lot, you could possibly refactor the code into a common utility method. But it still won't be either elegant or efficient.
The elegant solution is to do away with the exception nesting. Either don't chain the exceptions in the first place, or (selectively) unwrap and rethrow the nested exceptions further up the stack.
Exceptions tend to be nested for 3 reasons:
You have decided that the details of the original exception are unlikely to be useful for the application's error recovery ... but you want to preserve them for diagnostic purposes.
You are implementing API methods that don't allow a specific checked exception but your code unavoidably throws that exception. A common workaround is to "smuggle" the checked exception inside an unchecked exception.
You are being lazy and turning a diverse set of unrelated exceptions into a single exception to avoid having lots of checked exceptions in your method signature1.
In the first case, if you now need to discriminate on the wrapped exceptions, then your initial assumptions were incorrect. The best solution is change method signatures so that you can get rid of the nesting.
In the second case, you probably should unwrap the exceptions as soon as control has passed the problematic API method.
In the third case, you should rethink your exception handling strategy; i.e. do it properly2.
1 - Indeed, one of the semi-legitimate reasons for doing this has gone away due to the introduction of the multi-exception catch syntax in Java 7.
2 - Don't change your API methods to throws Exception. That only makes things worse. You now have to either "handle" or propagate Exception each time you call the methods. It is a cancer ...
You should add some checks to see if e.getCause().getCause() is really a MyException. Otherwise this code will throw a ClassCastException. I would probably write this like:
} catch(RemoteAccessException e) {
if(e.getCause() != null && e.getCause().getCause() instanceof MyException) {
MyException ex = (MyException)e.getCause().getCause();
// Do further useful stuff
} else {
throw new IllegalStateException("...");
}
}
I just solved a problem like this by writing a simple utility method, which will check the entire caused-by chain.
/**
* Recursive method to determine whether an Exception passed is, or has a cause, that is a
* subclass or implementation of the Throwable provided.
*
* #param caught The Throwable to check
* #param isOfOrCausedBy The Throwable Class to look for
* #return true if 'caught' is of type 'isOfOrCausedBy' or has a cause that this applies to.
*/
private boolean isCausedBy(Throwable caught, Class<? extends Throwable> isOfOrCausedBy) {
if (caught == null) return false;
else if (isOfOrCausedBy.isAssignableFrom(caught.getClass())) return true;
else return isCausedBy(caught.getCause(), isOfOrCausedBy);
}
When you use it, you would just create a list of if's from most specific Exception to least specific, with a fallback else-clause:
try {
// Code to be executed
} catch (Exception e) {
if (isCausedBy(e, MyException.class)) {
// Handle MyException.class
} else if (isCausedBy(e, AnotherException.class)) {
// Handle AnotherException.class
} else {
throw new IllegalStateException("Error at calling service 'service'");
}
}
Alternative/Addition per requests in comments
If you want to use a similar method to get the Exception object of the class you're looking for, you can use something like this:
private Throwable getCausedByOfType(Throwable caught, Class<? extends Throwable> isOfOrCausedBy) {
if (caught == null) return null;
else if (isOfOrCausedBy.isAssignableFrom(caught.getClass())) return caught;
else return getCausedByOfType(caught.getCause(), isOfOrCausedBy);
}
This could be used in addition to isCausedBy() this way:
if (isCausedBy(e, MyException.class)) {
Throwable causedBy = getCausedByOfType(e, MyException.class);
System.err.println(causedBy.getMessage());
}
It can also used directly instead of isCausedBy(), although it's probably a matter of opinion whether this is more readable.
Throwable causedBy;
if ((causedBy = getCausedByOfType(e, IllegalAccessException.class)) != null) {
System.err.println(causedBy.getMessage());
}
I see no reason why you want exception handling to be efficient and elegant, I settle for effective. They're called Exceptions for a reason.
This code will be a maintenance nightmare. Can't you redesign the call stack to throw the Exception you are interested in? If it is important the method signatures should show it and not hide it wrapped in 2 other exceptions.
The first (e != null) is unnecessary.
And you can change the 3rd better to e.getCause().getCause() instanceof MyException)
You can do as below:
catch (RemoteAccessException e) {
int index = ExceptionUtils.indexOfThrowable(e, MyExcetption.class)
if (index != -1) {
//handleMyException
} else {
}
}
I doubt, but you can check with instanceof if the exception is of the correct type.
Edit: There should be a reason that the nested exception is wrapped, so you have to ask yourself what is the purpose of catching the nested one.
I suppose you could also use ExceptionUtils.throwableOfThrowable() as in here
If you are investigating that whether an exception is caused by a custom exception (e.g. MyException) you can iterate with a while-loop until you find an instance of MyException.
boolean isCausedByMyException(Throwable exception) {
do {
if (exception instanceof MyException) {
return true;
}
exception = exception.getCause();
} while (exception != null);
return false;
}