In Java, how do I set a return type if an exception occurs?
if the connection fails when I try to create it what should I return? eclipse is telling me I have to return a Connection object but if it fails I’m not sure what to do. thanks! UPDATED CODE TO LET EXCEPTION BUBBLE:
public class DbConn < public Connection getConn() throws SQLException < Connection conn; String hostname = "localhost"; String username = "root"; String password = "root"; Class.forName("com.mysql.jdbc.Driver").newInstance(); if(System.getenv("MY_ENVIRONMENT") != "development") < hostname = "localhost"; username = "produser"; password = "prodpass"; >conn = DriverManager.getConnection("jdbc:mysql:///mydb", username, password); return conn; > >
Frankly, I’m astonished. Eclipse is normally smart enough to understand that once you throw something, you don’t need to return anything. But to make it happy, put a «return null;» after the end of the catch block.
@Paul: actually Eclipse is only unhappy about «Unhandled exception type Exception» inside the catch (missing throws).
6 Answers 6
If an exception is thrown, there is no normal value returned from the method. Usually the compiler is able to detect this, so it does not even pester you with «return required» style warnings/errors. Sometimes, when it is not able to do so, you need to give an «alibi» return statement, which will in fact never get executed.
Redefining your method like this
public Connection getConn() < Connection conn = null; try < Class.forName("com.mysql.jdbc.Driver").newInstance(); if(System.getenv("MY_ENVIRONMENT") == "development") < String hostname = "localhost"; String username = "root"; String password = "root"; >conn = DriverManager.getConnection("jdbc:mysql:///mydb", username, password); > catch(Exception e) < // handle the exception in a meaningful way - do not just rethrow it! >return conn; >
Update: As others have pointed out, re-throwing an exception in a catch block the way you did is not a good idea. The only situation when it is a decent solution is if you need to convert between different exception types. E.g. a method called throws an exception type which you can not or do not want to propagate upwards (e.g. because it belongs to a proprietary library or framework and you want to isolate the rest of your code from it).
Even then, the proper way to rethrow an exception is to pass the original exception into the new one’s constructor (standard Java exceptions and most framework specific exceptions allow this). This way the stack trace and any other information within the original exception is retained. It is also a good idea to log the error before rethrowing. E.g.
public void doSomething() throws MyException < try < // code which may throw HibernateException >catch (HibernateException e) < logger.log("Caught HibernateException", e); throw new MyException("Caught HibernateException", e); >>
Is it good practice to convert RuntimeException to Checked?
In above catch block, my DAO method can throw DaoException or Any run time exception. But i have single catch block which will catch both and convert them to Checked exception and return. Is it good practice to convert or should i throw run time exceptions as is? Thanks!
4 Answers 4
In most cases RuntimeException being thrown by some library means that the condition occurred cannot be handled such as NullPointerException . So when you will wrap them into Checked exception the client will be forced to handle such exceptions for which there is no point in catching.
So I would say only wrap exceptions if there is some chance of being recovered from some bad situation.
A good use of Checked exceptions:
Many times some operations are timed operations, tryConnection(duration) , when the duration times out then a checked exception can be thrown TimedOutException , now the client can take a decision as to whether a retry is required or not. So this serves the purpose of checked exceptions.
Is it good practice to convert RuntimeException to Checked?
There at two kinds of Java programmers: those who think that checked exceptions are a good thing, and those who think they are a bad thing.
These two groups of programmers would give you opposite Answers to this Question.
My advice would be to weigh up the pros and cons for yourself, and make your own decision in the context of what the application design requires. Since it is impractical for us to review that design, nobody can tell you which path to take . even if there was an objectively correct path.
Having said that, your Question includes an example of a dangerous (IMO) programming practice.
When you catch Exception , you are catching all possible exceptions (apart from the Error exceptions that you should (almost) never catch anyway). What if the exception you caught was a (say) an NPE caused a bug in your code . and that you should have allowed to propagate (or logged)? What if it was a checked exception that you could and should have recovered from . or otherwise dealt with?
Catching Exception often leads to problems / bugs being swept under the carpet . only to emerge and cause problems down the track.
Convert JSR303 JavaBean Validation exceptions to custom exceptions
I have implemented the JSR303 JavaBean Validation in the Service layer of my web app (according to this article). Now I want to convert all validation exceptions (e.g. javax.validation.ConstraintViolationException) to my custom exception. I created an Aspect that is invoked whenever an exception is thrown in the Service layer:
@Aspect public class ExceptionConversionAspect < @AfterThrowing(pointcut="execution(* com.myexample.service.*.*(..))", throwing="e") public void convertServiceException(Exception e) < if (e instanceof ConstraintViolationException) < // this is my custom exception throw new InvalidServiceInputException("The service inputs failed validation", e); >> >
But my exception conversion aspect is not triggered when my service fails validation with ConstraintViolationException. I suspect this is because the validation exception is itself triggered by an Aspect:
@Aspect public class ValidateAspect < @Autowired private Validator validator; // Match any public methods in a class annotated with @AutoValidating @Around("execution(public * *(..)) && @within(com.myexample.validator.annotation.Validate)") public Object validateMethodInvocation(ProceedingJoinPoint pjp) throws Throwable < // some code here . >
How do I chain my aspects in the correct order? ValidateAspect first, followed by ExceptionConversionAspect?
Maybe it would help to create aspect for validateMethodInvocation method — it would be triggered by exception thrown by that method or override ValidateAspect so it is throwing proper exception?
2 Answers 2
Raul Bertone is almost right, but not quite. The logic must be reversed and the ExceptionConversionAspect must be the first in precedence.
Fully working sample for Java SE (I just emulate the Java EE exception):
Helper classes:
package javax.validation; public class ConstraintViolationException extends RuntimeException < private static final long serialVersionUID = -8041265519275356912L; public ConstraintViolationException(String arg0) < super(arg0); >>
package com.myexample.validator.annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface Validate <>
package com.myexample.service; public class InvalidServiceInputException extends RuntimeException < public InvalidServiceInputException(String arg0, Throwable arg1) < super(arg0, arg1); >>
Sample driver application:
The driver application is annotated by @Validate and emulates a service — see package name. It loops through 10 method calls, catching exceptions and printing them to standard output so as to show that they are indeed converted as desired.
package com.myexample.service; import com.myexample.validator.annotation.Validate; @Validate public class Application < public void doSomething(int i) < System.out.printf("Doing something #%d%n", i); >public static void main(String[] args) < Application application = new Application(); for (int i = 0; i < 10; i++) < try < application.doSomething(i + 1); >catch (Exception e) < System.out.println(e); System.out.println(" cause: " + e.getCause()); >> > >
The validation aspect randomly throws a ConstraintViolationException for demo purposes.
package com.myexample.aspect; import java.util.Random; import javax.validation.ConstraintViolationException; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @Aspect public class ValidateAspect < private static final Random RANDOM = new Random(); @Around("execution(public !static * *(..)) && @within(com.myexample.validator.annotation.Validate)") public Object validateMethodInvocation(ProceedingJoinPoint thisJoinPoint) throws Throwable < Object result = thisJoinPoint.proceed(); if (RANDOM.nextBoolean()) throw new ConstraintViolationException("uh-oh"); return result; >>
The exception conversion aspect has an additional @DeclarePrecedence annotation now.
package com.myexample.aspect; import javax.validation.ConstraintViolationException; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclarePrecedence; import com.myexample.service.InvalidServiceInputException; @Aspect @DeclarePrecedence("ExceptionConversionAspect, *") public class ExceptionConversionAspect < @AfterThrowing(pointcut = "execution(* com.myexample.service..*(..))", throwing = "e") public void convertServiceException(Exception e) < if (e instanceof ConstraintViolationException) < throw new InvalidServiceInputException("The service inputs failed validation", e); >> >
Console output:
Doing something #1 Doing something #2 com.myexample.service.InvalidServiceInputException: The service inputs failed validation cause: javax.validation.ConstraintViolationException: uh-oh Doing something #3 com.myexample.service.InvalidServiceInputException: The service inputs failed validation cause: javax.validation.ConstraintViolationException: uh-oh Doing something #4 Doing something #5 Doing something #6 com.myexample.service.InvalidServiceInputException: The service inputs failed validation cause: javax.validation.ConstraintViolationException: uh-oh Doing something #7 Doing something #8 Doing something #9 Doing something #10