...
Wiki Markup |
---|
A common argument favoring undeclared checked exceptions (even unchecked exceptions) is that the caller does not have to define innumerable {{catch}} blocks for each specific checked exception that the callee can throw. Likewise, handling each exception within the callee is believed to clutter-up the code. One way to deal with this issue is to wrap the specific exceptions into a new exception, appropriate for the abstraction level. For example, a method may throw an {{IOException}} instead of specific exceptions such as {{FileNotFoundException}}. While exception handling should be as specific as possible, a compromise can be struck to increase the code readability in complex systems \[[Venners 03|AA. Java References#Venners 03]\]. However., wrapping checked exceptions into a broader exception class may not provide enough context for a recovery at the top level. Unchecked exceptions and undeclared checked exceptions, on the other hand, help reduce clutter in code but are unsuitable when a client is expected to recover from an exceptional condition. |
...
Any checked exception thrown by the default constructor of Class.NewInstancenewInstance()
is propagated even if it is not declared explicitly. On the contrary, the java.lang.reflect.Constructor.NewInstancenewInstance()
method wraps any exceptions thrown from within the constructor into a checked exception called InvocationTargetException
.
Code Block | ||
---|---|---|
| ||
public class BadNewInstance { private static Throwable throwable; private BadNewInstance() throws Throwable { throw throwable; } public static synchronized void undeclaredThrow(Throwable throwable) { // theseThese two should not be passed if (throwable instanceof IllegalAccessException || throwable instanceof InstantiationException) { throw new IllegalArgumentException(); // uncheckedUnchecked, no declaration required } BadNewInstance.throwable = throwable; try { BadNewInstance.class.newInstance(); } catch (InstantiationException e) { /* dead code */ } catch (IllegalAccessException e) { /* dead code */ } finally { BadNewInstance.throwable = null; } // avoidAvoid memory leak } } public class UndeclaredException { public static void main(String[] args) { // noNo declared checked exceptions BadNewInstance.undeclaredThrow(new Exception("Any checked exception")); } } |
Even if the programmer wishes to catch and handle the possible checked exceptions, the compiler refuses to believe that any can be thrown in the particular context. One way to deal with this difficulty is to catch Exception
and check whether the possible checked exception is an instance of it else re-throw the exception. This is shown below. The most obvious pitfall is that this technique is easy to bypass whenever an unanticipated checked exception is thrown.
Code Block |
---|
public static void main(String[] args) { try { BadNewInstance.undeclaredThrow(new IOException("Any checked exception")); } }catch(Exception e) { if (e instanceof IOException) { System.out.println("IOException occurred"); } else if (e instanceof RuntimeException) { throw (RuntimeException) e; } else { //some other unknown checked exception } } } |
Compliant Solution
Wiki Markup |
---|
Prefer the method {{Constructor.newInstance()}} over {{Class.newInstance()}}. An alternative is to use the builder interface recommended by Bloch \[[Bloch 08|AA. Java References#Bloch 08]\]. |
...
Code Block | ||
---|---|---|
| ||
interface Thr<EXC extends Exception> { void fn() throws EXC; } public class UndeclaredGen { static void undeclaredThrow() throws RuntimeException { @SuppressWarnings("unchecked") // suppressesSuppresses warnings Thr<RuntimeException> thr = (Thr<RuntimeException>)(Thr) new Thr<IOException>() { public void fn() throws IOException { throw new IOException(); } }; thr.fn(); } public static void main(String[] args) { undeclaredThrow(); } } |
...
Wiki Markup |
---|
According to the Java API \[[API 06|AA. Java References#API 06]\], class {{Thread}} documentation, |
Wiki Markup \[{{Thread.stop()}}\] may be used to generate exceptions that its target thread is unprepared to handle (including checked exceptions that the thread could not possibly throw, were it not for this method). For example, the following method is behaviorally identical to Java's throw operation, but circumvents the compiler's attempts to guarantee that the calling method has declared all of the checked exceptions that it may throw.
...
Refrain from employing code (legitimate or hostile) that is capable of throwing undeclared checked exceptions (legitimate or hostile). If the source code can throw them, explicitly document the behavior. Finally, do not use deprecated methods such as Thread.stop()
.
...
Failure to document undeclared checked exceptions can result in checked exceptions that the caller is unprepared to handle. This violates the safety property.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
EXC06- J | low | unlikely | high | P1 | L3 |
...