Java force catch RuntimeException?
Is it possible to force java to make you catch RuntimeExceptions? Specifically I am working with the Spring framework and the whole Exception hierarchy is based upon RuntimeExceptions. A lot of the times I forget to try and catch the Exceptions. A specific example is when doing an LDAP query, or开发者_如何学编程 an SQL call.
Not with just Java.
But if you compile with the AspectJ compiler or modifies your classes with AspectJ load-time weaving, then it's possible.
A definition of an aspect from Wikipedia:
an aspect is a part of a program that cross-cuts its core concerns
Aspects is often used to add for example transaction and security logic.
To demonstrate how an aspect can solve your problem, I have created an example that catches all exceptions thrown back from call to the integration layer from inside a method in classes marked with the @Service annotation. In this case classes that contains .integration.
in the package name.
This is just an example. You can modify it to catch RuntimeExceptions other places. For example in all methods that's inside a class that has Facade in its name and calls other methods. See the picture below for ideas:
(source: espenberntsen.net)
The orange arrows are my AspectJ pointcut illustrated with the AJDT plugin in Eclipse. This is the places where you can catch and deal with the runtime exceptions in an AfterThrowing
advice.
Here is the advice:
@AfterThrowing(value="serviceMethodAfterExpcetionFromIntegrationLayerPointcut()",
throwing="e")
public void serviceMethodAfterExceptionFromIntegrationLayer(JoinPoint joinPoint,
RuntimeException e) {
StringBuilder arguments = generateArgumentsString(joinPoint.getArgs());
logger.error("Error in service " + joinPoint.getSignature()
+ " with the arguments: " + arguments, e);
}
My serviceMethodAfterExpcetionFromIntegrationLayerPointcut
actuall consist of two other poincuts:
@Pointcut("call(* *..integration.*.*(..))")
public void integrationLayerPointcut() {}
@Pointcut("within(@org.springframework.stereotype.Service *)")
public void serviceBean() {}
@Pointcut("serviceBean() && integrationLayerPointcut()")
public void serviceMethodAfterExpcetionFromIntegrationLayerPointcut() {}
Short summarized, the pointcut finds all places in classes marked with the @Service
annotation that call on a method in a class on the integration layer. (See orange arrows on the picture)
If you want to catch runtime exceptions in your test classes instead, you can change the pointcut to this:
@Pointcut("within(com.redpill.linpro.demo..*Test)")
public void inDemoProjectTestClass() {}
Then the advice above will catch all exceptions in the test classes that ends with Test in the ..demo package.
More information about @AspectJ style here.
AspectJ is well integrated with Spring. General information about AspectJ can be found here and Spring's AspectJ support here.
No: RuntimeException
and its subclasses are unchecked exceptions.
JLS 11.2.5 Why Runtime Exceptions are not Checked
The runtime exception classes (
RuntimeException
and its subclasses) are exempted from compile-time checking because, in the judgment of the designers of the Java programming language, having to declare such exceptions would not aid significantly in establishing the correctness of programs. Many of the operations and constructs of the Java programming language can result in runtime exceptions. The information available to a compiler, and the level of analysis the compiler performs, are usually not sufficient to establish that such run-time exceptions cannot occur, even though this may be obvious to the programmer. Requiring such exception classes to be declared would simply be an irritation to programmers.
JLS 11.5 The Exception Hierarchy
The class
Exception
is the superclass of all the exceptions that ordinary programs may wish to recover from. The classRuntimeException
is a subclass of classException
. The subclasses ofRuntimeException
are unchecked exception classes. The subclasses ofException
other thanRuntimeException
and its subclasses are all checked exception classes.
No. Subclasses of RuntimeException are never checked.
In fact, Spring exceptions are made runtime for a good reason. Spring converts checked exceptions to a runtime, because if, for example, SQLException is thrown because database is down you are unlikely to be able to recover or do something meaningful.
Moreover, with checked exceptions your code becomes more tangled and clumsy, especially if you have to have another try/catch block in catch block.
No, you cannot force the compiler to make you catch any RuntimeException
.
Basically because the method you are calling does not declare it throws a RuntimeException, there is no way for the compiler to be aware of any exceptions that could be thrown, or to force you to catch them.
No that is not possible.
What you could do, but is bad design and definetly not recommended, is that you make the method throw an Exception
public void doStuff() throws Exception {}
Thus enforcing any caller to catch Exception
. This includes RuntimeException
s, but it is bad design since the scope is very broad and does not specify what exception that is being thrown.
No. The only thing i can think of is to use a tool like FindBugs, PMD etc, to find these issues for you, although i don't believe either tool has a tool specific to that. You could write your own detector however. Of course this would only apply to explicit throwing of RuntimeExceptions, and not implicit ones, like NullPointerException.
Instead of forcing you to remember to catch all of the fun exceptions everywhere, I would encourage writing a wrapper for some of the spring calls.
So instead of being forced to remember
try {
SpringThing.doThatOneMethod();
catch (SpringConnectionException sce) { /*handle it*/ }
catch (SpringProxyException spe) { /*handle it*/ }
catch (SpringRuntimeException sre) { /*handle it*/ }
, you could just always invoke your own SpringExceptionsWrapper.doThatOneMethod()
.
If you really wanted to, you could have the method signatures for your wrapper functions list out some checked exceptions that you might wrap stuff in. I wouldn't encourage it since it forces you to correctly handle it everywhere.
RuntimeExceptions can be caught and handled like Checked Exceptions but they do not have to be handled. For example if you throw new NullPointerException() in a try block the compiler will not force you to put the throws keyword in your method declaration as when throwing a Checked Exception. Handling a RuntimeException or its subclass indicates bad programming style and should be avoided.
精彩评论