I would like to catch an exception I expect but allow the others through.
The solution I have come to at the moment is:
protected void perfromCall(Class expectedException) throws Exception {
try {
response = call.call(request);
} catch (Exception e) {
if (!expectedException.isInstance(e)) {
throw new Exception(e);
}
}
}
While this will silently eat the expected exception as I would like and throw the others, what I don't like about it is that it wraps the unexpected exceptions and now I have to catch unexpected in the caller whereas previously (before trying to silently catch expected exceptions) I could let them bubble up to the test framework to fail the test.
Is there a cleaner way to say "I expected exceptions of class A, but for any other exception, let it be thrown up the chain until it's handled by the test framework above"?
Edit: I wanted to provide some justification as to why I want to do this as there were some answers (now deleted) that questioned silently eating an exception. This is for a test framework that calls a service. Some of the tests pass bad arguments to the service, so they expect an exception thrown by the service due to catching the invalid request. I therefore want to silently eat the expected exception, but still let unexpected exceptions to bubble up and fail the test.
protected void perfromCall(Class<?> expectedException) throws Exception {
try {
response = call.call(request);
} catch (Exception e) {
if (!expectedException.isInstance(e)) {
throw e;
}
}
}
Related
Let's suppose I have this class:
public class Obj1{
...
public void do_Something(int someParameter) throws SomeException {
if(...) throw new SomeException();
...
}
...
}
then, somewhere
public class Obj2{
...
public void do_SomeOtherThing(Obj1 obj1){
obj1.do_Something();
//apparently the only solution is try-catching it directly, even if I'm not in the main...
...
}
I've learned that exceptions should only be thrown by METHOD, and catched by MAIN, so, my question is: is try-catch the unique way to handle sub-method exceptions, or the most external method (do_SomeOtherThing) will throw it, so that I can try-catch it directly in main, deleting the try-catch in Object2 class?
Basically, can I do as follows?
public static void main(String[] args){
Object1 obj1 = new Object1();
Object2 obj2 = new Object2();
try{
obj2.do_SomeOtherThing(obj1);
}
catch(SomeException e){
...
}
}
or not?
A checked exception is part of the contract that a method has with its caller, and a thrown exception will always need to be handled one way or another.
The correct answer depends on the exact situation:
The caller can handle the exception:
String getStringFromRemoteServer() throws IOException { ... }
String getConfigString() {
try {
return getStringFromRemoteServer();
} catch (IOException e) {
LOG.warn("Failed to contact server, using local version.", e);
return getLocalString();
}
}
In this case we have an alternative source of the data we need, so if the preferred method fails we catch the exception, log it (so that we know a problem exists with our network) and call the alternative.
The exception is fatal, and we don't want any function higher in the call tree to try to handle it.
Configuration parseConfiguration(String configString) throws ParseException { ... }
void loadConfiguration() {
try {
this.globalConfig = parseConfiguration(getConfigString());
} catch (ParseException e) {
throw new RuntimeException("Corrupted config", e);
}
}
In this case an exception means that the configuration of our application is fatally broken. There is no point in trying to handle this error, and no point in any of our callers trying to handle it, so declaring throws on loadConfiguration() would just be confusing clutter. We wrap the exception in a RuntimeException and rethrow it. Note that we don't log it -- there will be some top level reporting of uncaught exceptions, so logging it here would be repetition.
It is still valuable to have parseConfiguration() throw a checked exception, because when we are calling it from the interactive configuration editor we catch the exception and display an error message to the user.
Maybe our caller can handle the exception.
int stringToInteger(String s) throws BadNumberException { ... }
String decimalStringToHexString(String s) throws BadNumberException {
return intToHex(stringToInteger(s));
}
In this case we are not changing the meaning of the exception -- decimalStringToHexString is converting a number from a string, and one possible outcome is that the string is illegal. Our caller needs to be aware of that as a possible outcome, just as callers of stringToInteger() are, so we simply declare the exception and let our caller handle it. Our caller knows the context they are using the number in, so they can decide how to handle the exception.
A couple of rules:
Never completely ignore an exception (OK, maybe InterruptedException). If you write try { ... } catch (Exception e) {} the empty catch clause will make it hard to spot why your code doesn't work.
When you wrap an exception, always include the original exception as the cause.
I'm working with spring boot and I'm dealing with a good way to handle exceptions:
I have this case where interact with a repository to get a product. But what about if there is a connection issue with the DB, I'm not going to catch that exception
Product product = productRepository.findById(productId)
.orElseThrow(() -> new NotFoundException("Could not find a product"));
try {
// Product logic
} catch(Exception e) {
throw new ProductException(String.format("Error getting product productId=%s. Exception message: %s",
productId, e.getMessage()), e);
}
I have a controller advice to catch the exception and return a nice response:
#ControllerAdvice
public class ExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler({NotFoundException.class})
public ResponseEntity<Error> handleNotFoundException(HttpServletRequest request, Exception exception) {
.....
}
I think I could do something like this:
try {
Product product = productRepository.findById(productId)
.orElseThrow(() -> new NotFoundException("Could not find a product"));
} catch(NotFoundException e) {
throw new NotFoundException(e.getMessage())
} catch(Exception e) {
throw new ProductException(String.format("Error getting product productId=%s. Exception message: %s",
productId, e.getMessage()), e);
That worked but it looks weird since I'm throwing NotFoundException twice. Any idea?
Generally speaking, there is nothing weird catching an Exception just to throw it again right after. You may for example catch it to log it somewhere and then throw it to the next handler for real handling (like in your case).
You can simply write:
catch (NotFoundException e) {
// Log if needed
throw e; // <-- no need to build a new one
}
However, for the part which comes after, catching generic Exception is usually a bad practice. There are too many sources this exception may come from, and you can't just assume that it is because of the DB not responding.
So the best would be that your function catches what it knows how to handle, and throws what it doesn't know how to handle. For example:
public void yourFunction() throws NotFoundException, ProductException {
//you don't know how to handle NotFoundException and ProductException here, hence you throw them up
try {
// your logic
} catch (SpecificExceptionYouWantToCatch e) {
//handle specific exception you know how to handle
} catch (AnotherSpecificException e) {
//handle other specific exception you know how to handle
}
//Let all the other Runtime exceptions flow up to the caller.
}
If there is an exception, something went wrong. You can't just wrap it and pretend it was a ProductException, so:
If you recognize the Exception and know how to handle it, then do it (as you're doing for NotFoundException)
However, if you didn't expect that Exception, then better let it flow. At some point it will be caught and handled, maybe, or maybe will just crash the program. But you will want to know it, while if you just wrap it into a ProductException you will probably hide to the system a bigger issue.
You can still catch it in ControllerAdvice, even you don't throw it so there is no need to try caatch that exception instead add:
#ExceptionHandler({PSQLException.class})
This is for Postgres you will have different exception for other typoes of databases then you can handle the message as well and see what is the cause of it in ControllerAdvice
Sonar complains when catching the generic type Exception, but sometimes we need to do some general exception handling for ALL (even not yet recognized) exception types. What is the solution to pass this sonar check?
Unless you are invoking a method which throws Exception, there is no need to catch Exception: catch the exceptions you know about, and the compiler will tell you when you have to start handling another one.
The problem with catching "not yet recognized" Exceptions is that you lose the signal that you have to handle a new exception in a special way.
For example:
void someMethod() {
// Do stuff.
}
void callIt() {
try {
someMethod();
} catch (Exception e) {
// ...
}
}
If someMethod is now changed so that it throws, say, an InterruptedException:
void someMethod() throws InterruptedException {
Thread.sleep(1000);
// Do stuff.
}
you aren't told by the compiler that you need to add handling for the InterruptedException in callIt(), so you will silently swallow interruptions, which may be a source of problems.
If, instead, you had caught RuntimeException, or RuntimeException | IOException | OtherExceptionYouAlreadyKnowAbout, the compiler would flag that you had to change your code to handle that InterruptedException as well; or, that you can't change the signature of someMethod(), and the checked exception has to be handled there.
I'm studying for a CS exam this Friday and have hit a bump in the road here. The question asks me to handle the exception and then propagate the exception using two different methods, but I was under the impression they were the same thing. Can anyone help? The practice question is listed below.
You are given the following class:
public class ReadData {
public void getInput() {
getString();
getInt();
}
public void getString() throws StringInputException {
throw new StringInputException();
}
public void getInt() throws IntInputException {
throw new IntInputException();
}
}
class StringInputException extends Exception {}
class IntInputException extends Exception {}
The code above will result in compilation errors in getInput() method.
Rewrite getInput() method using two different techniques:
Method 1 - Handle the exception
Method 2 - Propagate the exception
so that the code compiles.
They are not the same thing. Propagation basically means re-throwing the exception, that is, allowing somewhere further up in the code to handle it; generally this is done if nothing can be done about the exception at the current level. Handling the exception means catching it and actually doing something about it - informing the user, retrying, logging - but not allowing the exception to go any further.
class Example {
// a method that throws an exception
private void doSomething() throws Exception {
throw new Exception();
}
public void testHandling() {
try {
doSomething();
} catch (Exception e) {
// you caught the exception and you're handling it:
System.out.println("A problem occurred."); // <- handling
// if you wouldn't want to handle it, you would throw it again
}
}
public void testPropagation1() throws Exception /* <- propagation */ {
doSomething();
// you're not catching the exception, you're ignoring it and giving it
// further down the chain to someone else who can handle it
}
public void testPropagation2() throws Exception /* <- propagation */ {
try {
doSomething();
} catch (Exception e) {
throw e; // <- propagation
// you are catching the exception, but you're not handling it,
// you're giving it further down the chain to someone else who can
// handle it
}
}
}
"Handle the exception" means to catch it and do whatever is necessary to continue normally.
"Propagate the exception" means to not catch it and let your caller deal with it.
dictionary.com is your friend in this one.
Sometimes we have to deal with that pesky english language.
Handle means do something with the exception,
abort program ,
print error,
mess around with data ...
propagate it means forward it onto someplace else i.e. re throw it.
In trying to refactor some I code I attempted to throw the exception in the catch clause like so -
try {
....
}
catch(Exception exception){
.....
throw exception
}
However when I attempted to throw the exception on line "throw exception" the compiler complained with a message that I needed to surround my throw clause in a new try/catch like so -
try
{
....
}
catch (Exception exception)
{
.....
try
{
throw exception
}
catch (Exception e2)
{
...
}
}
Why does the compiler require this and what use does it provide ?
Thanks
The exception java.lang.Exception is a checked exception. This means that it must either be declared in the throws clause of the enclosing method or caught and handled withing the method body.
However, what you are doing in your "fixed" version is to catch the exception, rethrow it and then immediately catch it again. That doesn't make much sense.
Without seeing the real code, it is not clear what the real solution should be, but I expect that the problem is in the original try { ... } catch handler:
If possible, you should catch a more specific exception at that point, so that when you rethrow it, it is covered by the method's existing throws list.
Alternatively, you could wrap the exception in an unchecked exception and throw that instead.
As a last resort, you could change the signature of the method to include Exception in the throws list. But that's a really bad idea, because it just pushes the problem off to the caller ... and leaves the developer / reader in the position of not knowing what exceptions to expect.
In Java, there is a distinction between checked and unchecked exceptions. An unchecked exception can essentially be thrown at any place in code and, if it's not caught somewhere, it will propagate up to the entry point of your application and then stop the process (usually with an error message and stack trace). A checked exception is different: The compiler won't let you just let it propagate, you need to either surround any code which might throw a checked exception with try-catch blocks (and "throw exception" is the simplest case if exception is an instance of a checked exception class) or you must mark the method which contains the call to code that might throw a checked exception with a "throws" declaration. If the desired behaviour is to throw an unchecked exception, then you'll need to wrap the exception in a RuntimeException. If the desired behaviour is to keep the exception checked, then you'll need to add a throws declaration to your current method.
In your original code, nothing catches the thrown exception. I would imagine you either have to specify that your function throws an exception or have another try/catch block as the compiler suggests to catch it.
Instead of
public void yourFunction(){
try {
....
}
catch(Exception exception){
.....
throw exception
}
}
try
public void yourFunction() throws Exception{
try {
....
}
catch(Exception exception){
.....
throw exception
}
}
My guess is that your trying to throw an exception sub class that isn't declared by the method as an exception type it can throw.
The following example works
package test.example;
public class ExceptionTest {
public static void main(String[] args) throws Exception{
try {
int value = 1/0;
} catch (Exception e) {
System.out.println("woops the world is going to end");
throw e;
}
}
}
However this example will give an error.
package test.example;
public class ExceptionTest {
public static void main(String[] args) throws RuntimeException{
try {
int value = 1/0;
} catch (Exception e) {
System.out.println("woops the world is going to end");
throw e;
}
}
}
Note in the second example I'm simply catching Exception not RuntimeException, it won't compile as I throw Exception which is an undeclared throws, even though I do declare RuntimeException.
Yes the exception is a RuntimeException but the compiler doesn't know that.
Just thought of a third working example to show you. This one also works because your throwing the same type as you declare. (note the only change is the catch block)
package test.example;
public class ExceptionTest {
public static void main(String[] args) throws RuntimeException{
try {
int value = 1/0;
} catch (RuntimeException e) {
System.out.println("woops the world is going to end");
throw e;
}
}
}
You need to understand the differences between all three of these answers