How to find potential unchecked exceptions in Java? - java

In accordance with the Java specification, The Java compiler verifies automatically that all checked exceptions are caught, based on "throw" statements and method signatures, and ignores unchecked exceptions.
However, sometimes it would be useful for the developer to find out what unchecked exceptions can be thrown, for instance some 3rd party code might throw unchecked exceptions in situations where the developer would tend to expect a checked exception (like Long.parseLong). Or a developer might throw an unchecked exception as a placeholder for a future checked exception and forget to replace it.
In these examples, it is theoretically possible to find these uncaught unchecked exception. In the first case, the signature of Long.parseLong indicates that it throws NumberFormatException, and in the second case, the source code is available, so the compiler knows what unchecked exceptions are thrown.
My question is: is there a tool that can report these cases? Or maybe a way to let the Java compiler treat temporarily unchecked exceptions are checked exceptions? That would be very useful to verify manually and fix potential bugs that would otherwise cause a crash of the whole thread or application at runtime.
EDIT: after some answers, I have to underline that my goal is not to find the exhaustive list of unchecked exceptions possible in the system, but potential bugs due to unchecked exceptions. I think it boils down to the two cases:
a method's signature indicates that it throws an unchecked exception, and the caller doesn't catch it
a method's body throws explicitly unchecked exceptions, and the caller doesn't catch them

Yes you can write a static analysis to do this. I've done something similar myself and wrote mine in a program analysis tool called Atlas. Here: https://github.com/EnSoftCorp/java-toolbox-commons/.../ThrowableAnalysis.java is some code that might be helpful for what you need, it statically computes matches for throw sites and potential catch sites in a piece of software (conservatively in that it does not consider path feasibility). For your case you are interested in throw sites that do not have a corresponding catch block.
Here are the important bits of the analysis.
All exceptions checked or unchecked must extend Throwable. It sounds like you are only interested in "unchecked" throwables so you should consider classes that directly extend or are children of a class that extends Error or RuntimeException.
In the Atlas Shell you could write the following queries to find all the unchecked throwables.
var supertypeEdges = Common.universe().edgesTaggedWithAny(XCSG.Supertype)
var errors = supertypeEdges.reverse(Common.typeSelect("java.lang", "Error"))
var uncheckedExceptions = supertypeEdges.reverse(Common.typeSelect("java.lang", "RuntimeException"))
show(errors.union(uncheckedExceptions))
Any exception that can be caught at runtime (checked or unchecked) must have a corresponding "throw" site. While a thrown checked exception must be declared in a method signature, it is not required to be declared for a thrown unchecked exception. However this isn't really that important since we can detect all thrown unchecked exceptions simply by looking at the type hierarchy as we discussed in step 1.
To match the throw site with the corresponding catch block we must remember that a thrown exception propogates back up the call stack until it is caught (or crashes the program when it is not caught by the main method or thread entry point). To do this analysis you need a call graph (the more precise the call graph is the more accurate your analysis will be here). For each throw of an unchecked exception type step backwards along the call graph to the callsite of the method that could throw the unchecked exception. Check if the callsite is contained within a try block (or has a trap region if you are analyzing bytecode). If it is you must check the compatibility of the catch blocks/trap regions and determine if the exception will be caught. If the exception is not caught repeat the process stepping backwards along the call graph to each callsite until the exception is caught or there is no possible catch block.
Using the ThrowableAnalysis code I shared earlier you could bring it all together to find each uncaught thrown unchecked throwable types.
public class Analysis {
// execute show(Analysis.run()) on the Atlas shell
public static Q run(){
Q supertypeEdges = Common.universe().edgesTaggedWithAny(XCSG.Supertype);
Q errors = supertypeEdges.reverse(Common.typeSelect("java.lang", "Error"));
Q uncheckedExceptions = supertypeEdges.reverse(Common.typeSelect("java.lang", "RuntimeException"));
Q typeOfEdges = Common.universe().edgesTaggedWithAny(XCSG.TypeOf);
Q thrownUncheckedThrowables = typeOfEdges.predecessors(errors.union(uncheckedExceptions)).nodesTaggedWithAny(XCSG.ThrownValue);
AtlasSet<Node> uncaughtThrownUncheckedThrowables = new AtlasHashSet<Node>();
for(Node thrownUncheckedThrowable : thrownUncheckedThrowables.eval().nodes()){
if(ThrowableAnalysis.findCatchForThrows(Common.toQ(thrownUncheckedThrowable)).eval().nodes().isEmpty()){
uncaughtThrownUncheckedThrowables.add(thrownUncheckedThrowable);
}
}
Q uncaughtThrownUncheckedThrowableMethods = Common.toQ(uncaughtThrownUncheckedThrowables).containers().nodesTaggedWithAny(XCSG.Method);
Q callEdges = Common.universe().edgesTaggedWithAny(XCSG.Call);
Q rootMethods = callEdges.reverse(uncaughtThrownUncheckedThrowableMethods).roots();
Q callChainToUncaughtThrowables = callEdges.between(rootMethods, uncaughtThrownUncheckedThrowableMethods);
return callChainToUncaughtThrowables.union(Common.toQ(uncaughtThrownUncheckedThrowables));
}
}
Here's a screenshot of the result of running this code on the following test case.
public class Test {
public static void main(String[] args) {
foo();
}
private static void foo(){
throw new Pig("Pigs can fly!");
}
public static class Pig extends RuntimeException {
public Pig(String message){
super(message);
}
}
}
Important Caveats: You must consider whether or not to do whole program analysis here. If you only analyze your code and not the full JDK (several million lines of code) then you will only detect uncaught runtime exceptions which originate inside your application. For example you would not catch "test".substring(0,10) which throws an out of bounds exception inside the substring method declared in the String class in the JDK. While Atlas supports partial or whole program analysis using Java source or bytecode and can scale up to the full JDK, you would need to allocate about an hour of pre-processing time and 20 gigabytes more memory if you plan to include the full JDK.

There is an Intellij plugin that can help you discover unchecked exceptions.
You can customize the search process to include/exclude libraries when searching for them.
https://plugins.jetbrains.com/plugin/8157?pr=

My question is: is there a tool that can report these cases?
AFAIK, no.
Or maybe a way to let the Java compiler treat temporarily unchecked exceptions are checked exceptions?
AFAIK, no.
While tools like this are theoretically possible (with some caveats1), they would be close to useless in practice. If you rely solely on local analysis of methods, most ordinary Java would be flagged as potentially throwing a wide range of unchecked exceptions. Some of these could be excluded with some simple non-local analysis, but that would be nowhere like enough to avoid excessive "false positives".
IMO, there is no practical way to eliminate all runtime exceptions.
What you should be doing is to combining the following practice in order to reduce the number of bugs (including unexpected runtime exceptions) that make it into production code
Thorough and methodical testing; e.g. by developing automated unit and system test-suites, and using coverage tools to help you identify codepaths that have not been tested.
Use of static analysis tools like PMD and FindBugs that can detect certain classes of problem. You can help these and similar tools by using annotations like #NotNull.
Code reviews.
Following good coding practice, especially when developing multi-threaded code.
But note that these practices are expensive, and they don't eliminate all bugs.
Some of the other answers seem to be suggestion that you should catch all exceptions (e.g. Exception, RuntimeException or even Throwable) as a way of avoiding crashes.
This is misguided. Yes, you can "catch them all" (this is called Pokemon exception handling!) but you can't safely recover from an arbitrary unexpected exception. In general, the only entirely safe thing to do when you get an unexpected exception is to bail out.
1 - These caveats are: 1) the analyser needs to be aware of the Java language constructs that can throw unchecked exceptions implicitly; e.g. instance method call can throw a NPE, a new can throw an OOOME, etc. 2) you need to analyse all library methods used by your code, including 3rd-party libraries, 3) Java exceptions could be thrown from native code, and 4) things involving static and "bytecode engineering" need to be considered.

There is no way to get a list of possible unchecked exceptions. Since they are not declared anywhere (they are created on the fly) it's just not possible without a pretty specific code analyzer tool--and even then it might not catch some from compiled library classes.
For examples of tricky things to predict consider anything that allocates memory can throw an out of memory exception and you could even instantiate an exception reflectively which would be pretty much impossible to find with ANY static analysis tools.
If you are really really paranoid you could catch RuntimeException, that should get all unchecked exceptions that you would want to deal with--it's not a recommended tactic but can prevent your program from failing from some unknown/unseen future bug.

It's not possible to find unchecked exceptions in many cases, or you might as well end up with a very long list of possible exceptions that could occur.
When is it not possible to find unchecked exceptions? Assume you want to call a method of an interface. One implementation might throw certain unchecked exceptions, others won't. The compiler can't know because it's only known at runtime.
Why could you end up with a very long list of possible exceptions? Well, pretty much every method might throw NullPointerException, in case you provide null parameters which are not explicitly checked. If they are checked, there's probably an IllegalArgumentException instead. Furthermore, every single method which this method calls might also throw different unchecked exceptions, which would have to be added to the list. You could run into a ClassNotFoundError or OutOfMemoryError anytime, which would also have to be added to that list...

Image a simple method like
public Foo bar(String input) {
return new Foo(input.charAt(0));
}
Alone that method could throw at least a NullPointerException or some OutOfBounds thing.
And the catch is: in order to see "all" potential exceptions, your tool would have to check each and any line of code (compiled or source) that goes into your applications.
I don't see how this could in any way be "manageable".
And it gets worse, what if
public Foo(char whatever) {
String klazz = ... god knows
throw (RuntimeException) Class.forName(klazz).newInstance();
Of course, that would need some try/catch for the checked exceptions that the reflection code has; but the point is: understand the whole universe of potential exceptions might end up in some "pretty huge map" drawn for you. With so many paths/branches in it that you never find the 0.001% of interesting paths in there.

Related

Why my Ide is not warning me about handle this exception [duplicate]

I've studied that: With an unchecked exception, however, the compiler doesn't force client programmers either to catch the exception or declare it in a throws clause. In fact, client programmers may not even know that the exception could be thrown. eg, StringIndexOutOfBoundsException thrown by String's charAt() method.
what its mean?
according to that code there is no need to put try catch block in code,
but i've seen compiler forces to put the code in try catch block.
I'm very confused what they are exactly?
Unchecked exceptions are those that extend RuntimeException class. Compiler will never force you to catch such exception or force you to declare it in the method using throws keyword. All other exception types (that do not extend RuntimeException) are checked and therefore must be declared to be thrown and/or catched.
Checked exceptions are used when you want the caller of your method (i.e the user of your API) to explicitly handle the exceptional case in your API. Checked exceptions are declared when you believe the call will be able to do something meaningful with that exceptional case, like retrying the call, rolling changes back or converting it into some user-readable error message.
If you believe that there is nothing useful the call can do about the exception (especially when it represents a bug, or a wrong usage of your API), then the exception should be unchecked. Also, an API with too many checked exceptions can be annoying to program with (e.g. try using java reflection API=)
Checked Exceptions are useful for handling events that occur in the normal operation of a program. An example would be an IOException that is thrown when a file cannot be opened. These exceptions occur even if there is nothing wrong with the program. It is necessary, therefore, to tell the program how to handle the exception.
Unchecked exceptions are useful for identifying defects in the code. For instance, a NullPointerException is thrown when a value is read on a null object. Thus an Unchecked Exception represents a problem that requires a manual fix by the programmer. It is reasonable for the program to crash in order to avoid erroneous behavior, so a try-catch block is not required (but might be desirable in order to provide mitigation, such as displaying an error to the user).
What is your question exactly?
Compilers shouldn't (and won't) enforce you to try/catch unchecked exceptions, that would go against exactly what they are.
The general idea is that checked exceptions are something you may be able to foresee but may be based on input that is out of your control and that you have to deal with.
Unchecked exceptions will usually represent bugs in your program.
There's a number of people that think checked exceptions are a mistake in the Java platform and they only use them very sparingly or not at all. You can read more about this debate by searching google.
It is because,
Unchecked Exceptions are not a result of programmer's fault. Instead they are the serious consequences where we(programmer) aren't expected to do much with it.
In case of Checked Exception, it is an exception generated because of the programmer's fault & often can be resolved by programmer itself.
Check the following links :
Why RunTime Exceptions are unchecked ?
Checked vs Unchecked Exception ?
All Exceptions are part of run time and not compile time. There are two kinds of exceptions checked exceptions and unchecked exceptions. Examples of checked exceptions are IO Exceptions, ClassNotFound Exception and examples of unchecked exceptions are runtime exceptions. In the case of checked exceptions, error or warning message comes at compile time so that the user will take care of it at runtime by using throws keyword, which is used to throw exceptions to the default catch mechanism system. But in case of unchecked exceptions warning is not there at compile time.
**Checked Exceptions
Exceptions which are to be checked or handled or should be taken care during the time of writing the code are called as checked exceptions.
For eg:
1. we have FileNotFoundException -->which will be occured when we are writing some code related to file classes. There will e defenetly posibility of non existence of file. In such case in order to handle them , we are forced to handle those exception for sure.
2. one more example is ParseException ,which will be occured when we are dealing with date functions.
UnChecked Exceptions
These are the exceptions that are optional to be handled during the time of coding. Its up to us whether we handle them or not. In case if we fail to handle them, There is a chance of getting runtime errors during the exceution.
For eg:
We have something called NullPointerException,ArithemeticException,NosSuchElementFoundException and so on. These are like optional things we dont even have to handle them. More over even jvm or compiler will not recommend us to handle them.**
in simple words,
checked exceptions are those which can be and should be handled by your code(therefore compiler forces you to handle them)
unchecked exceptions are those which lie beyond programmer's control(therefore compiler doesn't forces you to handle them)
use the same rule even while creating your custom exceptions.

How can I see the runtime exceptions thrown within a given method?

I have a method which calls several other methods. However these methods and other operations (like navigating array or working with null pointers) can throw runtime exceptions which are not explicit.
One could make use of a try{...}catch(Exception e){...} block to make sure that no wild exception crosses the barrier and my method does not throw any exception which isn't explicit declared in its signature.
However this solution is ugly and prone to bugs since I may not want to catch everything or I may want to provide some specific behavior given a specific error situation.
So, is there a way for Eclipse to show me something like "careful, your method says that it throws IllegalArgumentException and JSONException, but you are missing some runtime exceptions that you can catch internally or declare that you throw them as well"? So far Eclipse only shows me which Exceptions I really must declare in the method's signature, but I also wanna be forced to declare the (Unchecked) runtime exceptions.
Ps.: This is not a duplicate of How can I know what exceptions can be thrown from a method? since the best solution there is to use a catch-all block.
Short answer is: you can't.
That is the nature of RuntimeException; they are not "checked" exceptions; therefore you are not enforced to add them to your throws clause.
The important thing is that on some level your code understands that RuntimeExceptions might occur; and deals with them in the correct way.
Example: assume you are working on "providers" that should process requests that are coming from a restful API.
There are now two types of problems:
A) those that you "expect" and where you give fine granular feedback on. For example your API spec might list many 400.xxx, 409.xxx, ... answers for various problems. It makes sense to use "checked" exceptions for these things (the code throwing an "ApiException" already knows that this error should show up as 409.xxx to the user of the restful API).
B) Then there are those that you "do not expect"; basically those are reflecting "bugs" in your code; like "he, this argument should not be null"; "he, this 'key' is unknown". For those ... just throw RuntimeExceptions. But make sure that your top layer catches them; and for example turns them into a 500.xxx answer to the user ("some internal error happened, here is the stacktrace; send us a bug report)
Your request has an interesting twist. You want to catch all exceptions that the invoked methods may throw, but you don’t want to use catch(Exception ex){ … } because that would imply that … you are catching all exceptions.
Let’s ask the other way round: which exception do you want to exclude from the catch clause? If you want to catch all checked exceptions as well as all runtime exceptions, you exclude Errors and those runtime exception which may not occur. Well, that’s what catch(Exception ex){ … }already does. It doesn’t catch Errors and you don’t need to bother about exceptions that are impossible to occur.
That said, there is a reason why you shouldn’t catch RuntimeExceptions. They are there to signal conditions that normally shouldn’t occur even if their impossibility can’t be proven at compile time.
If you want your IDE to collect all runtime exceptions that are in principle possible, consider
Every access to an object or array may cause a NullPointerException
Every array access may cause an ArrayIndexOutOfBoundsException or NegativeArraySizeException
Every array write access may cause an ArrayStoreException
Every integer division may cause an ArithmeticException
Every runtime type cast, including those hidden by Generics may produce a ClassCastException
etc. And these are only the exceptions associated with language constructs, not containing those possibly produced by library methods.
The set of possible exceptions will soon explode if you really ask a tool to collect them all for a particular piece of code and all invoked methods.
You would need an insanely large list of exception types in your catch clause and that only to hide the fact that you are actually attempting to catch all exceptions (as catch(Exception ex) would immediately make apparent)…

Adding Unused Exceptions to 'throws'

Why does the Java compiler allow exceptions to be added via throws even when they're not possibly able to be thrown?
example:
private static void foo() throws java.io.FileNotFoundException {
System.out.println("no possible FileNotFoundException here");
}
The above code compiles just fine, but it's not possible for a FileNotFoundException to be thrown.
I would suggest maintenance: because you might want to change that method later to add an operation that could throw a FileNotFoundException, and you want to force all callers of this method to know what to do if that method should be changed to throw FileNotFoundException in the future.
Another manifestation of the issue is that a subclass may override this method and throw the exception, and this cannot be determined by compiling the superclass alone.
Because the compiler isn't smart enough to find out every exception?
It sounds quite logical that Java can't know the possible outcomes for all algorithms. Just like a programming language can never prove a mathematical exception, it can only execute mathematics.
This means that an obvious mathematical "infinite loop", isn't always obvious to the programming language. I think that for such reasoning, the compiler doesn't bother looking at what will be executed.
If the compiler would have to pre-check for all exceptions the coder writes, it might spend "days" checking the code. All in all it just seems better to have the programmer responsible for the exceptions. Either way, it doesn't hurt.
Checked exceptions are validated by the compiler only in the try { } block, method bodies are not validated. There are multiple reasons, the complexity of such check being one, the fact that a child class can override the method and decide to throw the exception is a second.
In Netbeans 7.3.1, this would show up as an "unreported exception" and it will warn you that it must be caught or declared. So it would be an error. It depends on your tool.

Checked vs Unchecked exception

I've studied that: With an unchecked exception, however, the compiler doesn't force client programmers either to catch the exception or declare it in a throws clause. In fact, client programmers may not even know that the exception could be thrown. eg, StringIndexOutOfBoundsException thrown by String's charAt() method.
what its mean?
according to that code there is no need to put try catch block in code,
but i've seen compiler forces to put the code in try catch block.
I'm very confused what they are exactly?
Unchecked exceptions are those that extend RuntimeException class. Compiler will never force you to catch such exception or force you to declare it in the method using throws keyword. All other exception types (that do not extend RuntimeException) are checked and therefore must be declared to be thrown and/or catched.
Checked exceptions are used when you want the caller of your method (i.e the user of your API) to explicitly handle the exceptional case in your API. Checked exceptions are declared when you believe the call will be able to do something meaningful with that exceptional case, like retrying the call, rolling changes back or converting it into some user-readable error message.
If you believe that there is nothing useful the call can do about the exception (especially when it represents a bug, or a wrong usage of your API), then the exception should be unchecked. Also, an API with too many checked exceptions can be annoying to program with (e.g. try using java reflection API=)
Checked Exceptions are useful for handling events that occur in the normal operation of a program. An example would be an IOException that is thrown when a file cannot be opened. These exceptions occur even if there is nothing wrong with the program. It is necessary, therefore, to tell the program how to handle the exception.
Unchecked exceptions are useful for identifying defects in the code. For instance, a NullPointerException is thrown when a value is read on a null object. Thus an Unchecked Exception represents a problem that requires a manual fix by the programmer. It is reasonable for the program to crash in order to avoid erroneous behavior, so a try-catch block is not required (but might be desirable in order to provide mitigation, such as displaying an error to the user).
What is your question exactly?
Compilers shouldn't (and won't) enforce you to try/catch unchecked exceptions, that would go against exactly what they are.
The general idea is that checked exceptions are something you may be able to foresee but may be based on input that is out of your control and that you have to deal with.
Unchecked exceptions will usually represent bugs in your program.
There's a number of people that think checked exceptions are a mistake in the Java platform and they only use them very sparingly or not at all. You can read more about this debate by searching google.
It is because,
Unchecked Exceptions are not a result of programmer's fault. Instead they are the serious consequences where we(programmer) aren't expected to do much with it.
In case of Checked Exception, it is an exception generated because of the programmer's fault & often can be resolved by programmer itself.
Check the following links :
Why RunTime Exceptions are unchecked ?
Checked vs Unchecked Exception ?
All Exceptions are part of run time and not compile time. There are two kinds of exceptions checked exceptions and unchecked exceptions. Examples of checked exceptions are IO Exceptions, ClassNotFound Exception and examples of unchecked exceptions are runtime exceptions. In the case of checked exceptions, error or warning message comes at compile time so that the user will take care of it at runtime by using throws keyword, which is used to throw exceptions to the default catch mechanism system. But in case of unchecked exceptions warning is not there at compile time.
**Checked Exceptions
Exceptions which are to be checked or handled or should be taken care during the time of writing the code are called as checked exceptions.
For eg:
1. we have FileNotFoundException -->which will be occured when we are writing some code related to file classes. There will e defenetly posibility of non existence of file. In such case in order to handle them , we are forced to handle those exception for sure.
2. one more example is ParseException ,which will be occured when we are dealing with date functions.
UnChecked Exceptions
These are the exceptions that are optional to be handled during the time of coding. Its up to us whether we handle them or not. In case if we fail to handle them, There is a chance of getting runtime errors during the exceution.
For eg:
We have something called NullPointerException,ArithemeticException,NosSuchElementFoundException and so on. These are like optional things we dont even have to handle them. More over even jvm or compiler will not recommend us to handle them.**
in simple words,
checked exceptions are those which can be and should be handled by your code(therefore compiler forces you to handle them)
unchecked exceptions are those which lie beyond programmer's control(therefore compiler doesn't forces you to handle them)
use the same rule even while creating your custom exceptions.

In Java, when should I create a checked exception, and when should it be a runtime exception? [duplicate]

This question already has answers here:
Closed 10 years ago.
The community reviewed whether to reopen this question last year and left it closed:
Original close reason(s) were not resolved
Possible Duplicate:
When to choose checked and unchecked exceptions
When should I create a checked exception, and when should I make a runtime exception?
For example, suppose I created the following class:
public class Account {
private float balance;
/* ... constructor, getter, and other fields and methods */
public void transferTo(Account other, float amount) {
if (amount > balance)
throw new NotEnoughBalanceException();
/* ... */
}
}
How should I create my NotEnoughBalanceException? Should it extend Exception or RuntimeException? Or should I just use IllegalArgumentException instead?
There's a LOT of disagreement on this topic. At my last job, we ran into some real issues with Runtime exceptions being forgotten until they showed up in production (on agedwards.com), so we resolved to use checked exceptions exclusively.
At my current job, I find that there are many who are for Runtime exceptions in many or all cases.
Here's what I think: Using CheckedExceptions, I am forced at compile time to at least acknowledge the exception in the caller. With Runtime exceptions, I am not forced to by the compiler, but can write a unit test that makes me deal with it. Since I still believe that the earlier a bug is caught the cheaper it is to fix it, I prefer CheckedExceptions for this reason.
From a philosophical point of view, a method call is a contract to some degree between the caller and the called. Since the compiler enforces the types of parameters that are passed in, it seems symmetrical to let it enforce the types on the way out. That is, return values or exceptions.
My experience tells me that I get higher quality, that is, code that JUST WORKS, when I'm using checked exceptions. Checked exceptions may clutter code, but there are techniques to deal with this. I like to translate exceptions when passing a layer boundary. For example, if I'm passing up from my persistence layer, I would like to convert an SQL exception to a persistence exception, since the next layer up shouldn't care that I'm persisting to a SQL database, but will want to know if something could not be persisted. Another technique I use is to create a simple hierarchy of exceptions. This lets me write cleaner code one layer up, since I can catch the superclass, and only deal with the individual subclasses when it really matters.
In general, I think the advice by Joshua Bloch in Effective Java best summarises the answer to your question: Use checked expections for recoverable conditions and runtime exceptions for programming errors (Item 58 in 2nd edition).
So in this case, if you really want to use exceptions, it should be a checked one. (Unless the documentation of transferTo() made it very clear that the method must not be called without checking for sufficient balance first by using some other Account method - but this would seem a bit awkward.)
But also note Items 59: Avoid unnecessary use of checked exceptions and 57: Use exceptions only for exceptional conditions. As others have pointed out, this case may not warrant an exception at all. Consider returning false (or perhaps a status object with details about what happened) if there is not enough credit.
When to use checked exceptions? Honestly? In my humble opinion... never. I think it's been about 6 years since I last created a checked exception.
You can't force someone to deal with an error. Arguably it makes code worse not better. I can't tell you the number of times I've come across code like this:
try {
...
} catch (IOException e) {
// do nothing
}
Whereas I have countless times written code like this:
try {
...
} catch (IOException e) {
throw new RuntimeExceptione(e);
}
Why? Because a condition (not necessarily IOException; that's just an example) wasn't recoverable but was forced down my throat anyway and I am often forced to make the choice between doing the above and polluting my API just to propagate a checked exception all the way to the top where it's (rightlfully) fatal and will be logged.
There's a reason Spring's DAO helper classes translate the checked SQLException into the unchecked DataAccessException.
If you have things like lack of write permissions to a disk, lack of disk space or other fatal conditions you want to be making as much noise as possible and the way to do this is with... unchecked exceptions (or even Errors).
Additionally, checked exceptions break encapsulation.
This idea that checked exceptions should be used for "recoverable" errors is really pie-in-the-sky wishful thinking.
Checked exceptions in Java were an experiment... a failed experiment. We should just cut our losses, admit we made a mistake and move on. IMHO .Net got it right by only having unchecked exceptions. Then again it had the second-adopter advantage of learning from Java's mistakes.
IMHO, it shouldn't be an exception at all. An exception, in my mind, should be used when exceptional things happen, and not as flow controls.
In your case, it isn't at all an exceptional status that someone tries to transfer more money than the balance allows. I figure these things happen very often in the real world. So you should program against these situations. An exception might be that your if-statement evaluates the balance good, but when the money is actually being subtracted from the account, the balance isn't good anymore, for some strange reason.
An exception might be that, just before calling transferTo(), you checked that the line was open to the bank. But inside the transferTo(), the code notices that the line isn't open any more, although, by all logic, it should be. THAT is an exception. If the line can't be opened, that's not an exception, that's a plausible situation.
IMHO recap: Exceptions == weird black magic.
being-constructive-edit:
So, not to be all too contradictive, the method itself might very well throw an exception. But the use of the method should be controlled: You first check the balance (outside of the transferTo() method), and if the balance is good, only then call transferTo(). If transferTo() notices that the balance, for some odd reason, isn't good anymore, you throw the exception, which you diligently catch.
In that case, you have all your ducks in a row, and know that there's nothing more you can do (because what was true became false, as if by itself), other than log the exception, send a notification to someone, and tell the customer politely that someone didn't sacrifice their virgins properly during the last full moon, and the problem will be fixed at the first possible moment.
less-enterprisey-suggestion-edit:
If you are doing this for your own pleasure (and the case seems to be this, see comments), I'd suggest returning a boolean instead. The usage would be something like this:
// ...
boolean success = transferTo(otherAccount, ONE_MILLION_DOLLARS_EXCLAMATION);
if (!success) {
UI.showMessage("Aww shucks. You're not that rich");
return; // or something...
} else {
profit();
}
// ...
My rule is
if statements for business logic errors (like your code)
cheched exceptions for environment errors where the application can recover
uncheched exception for environment errors where there is no recovery
Example for checked exception: Network is down for an application that can work offline
Example for uncheched exception: Database is down on a CRUD web application.
There is much documentation on the subject. You can find a lot by browsing the Hibernate
web pages since they changed all exceptions of Hibernate 2.x from checked to unchecked in version 3.x
I recently had a problem with exceptions, code threw NullPointerException and I had no idea why, after some investigation it turned out that real exception was swallowed(it was in new code, so its still being done) and method just returned null. If you do checked exceptions you must understand that bad programmers will just try catch it and ignore exception.
My feeling is that the checked exception is a useful contract that should be used sparingly. The classic example of where I think a checked exception is a good idea is an InterruptedException. My feeling is that I do want to be able to stop a thread / process when I want it to stop, regardless of how long someone has specified to Thread.sleep().
So, trying to answer your specific question, is this something that you absolutely want to make sure that everyone deals with? To my mind, a situation where an Account doesn't have enough money is a serious enough problem that you have to deal with it.
In response to Peter's comment: here's an example using InterruptedException as concrete case of an exception that should be handled and you need to have a useful default handler. Here is what I strongly recommend, certainly at my real job. You should at least do this:
catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
That handler will ensure that the code catches the checked exception and does exactly what you want: get this thread to stop. Admittedly, if there's another exception handler / eater upstream, it's not impossible that it will handle the exception less well. Even so, FindBugs can help you find those.
Now, reality sets in: you can't necessarily force everyone who writes an exception handler for your checked exception to handle it well. That said, at least you'll be able to "Find Usages" and know where it is used and give some advice.
Short form: you're inflicting a load the users of your method if you use a checked exception. Make sure that there's a good reason for it, recommend a correct handling method and document all this extensively.
From Unchecked Exceptions -- The Controversy:
If a client can reasonably be expected
to recover from an exception, make it
a checked exception. If a client
cannot do anything to recover from the
exception, make it an unchecked
exception.
Note that an unchecked exception is one derived from RuntimeException and a checked exception is one derived from Exception.
Why throw a RuntimeException if a client cannot do anything to recover from the exception? The article explains:
Runtime exceptions represent problems
that are the result of a programming
problem, and as such, the API client
code cannot reasonably be expected to
recover from them or to handle them in
any way. Such problems include
arithmetic exceptions, such as
dividing by zero; pointer exceptions,
such as trying to access an object
through a null reference; and indexing
exceptions, such as attempting to
access an array element through an
index that is too large or too small.
A checked exception means that clients of your class are forced to deal with it by the compiler. Their code cannot compile unless they add a try/catch block.
The designers of C# have decided that unchecked exceptions are preferred.
Or you can follow the C-style and check return values and not throw exceptions.
Exceptions do have a cost, so they shouldn't be used for control flow, as noted earlier. But the one thing they have going for them is that they can't be ignored.
If you decide that in this case to eschew exceptions, you run the risk that a client of your class will ignore the return value or fail to check the balance before trying to transfer.
I'd recommend an unchecked exception, and I'd give it a descriptive name like InsufficientFundsException to make it quite clear what was going on.
Simply put, use checked exception only as part of external contract for a library, and only if the client wants/needs to catch it. Remember, when using checked exception you are forcing yourself on the caller. With runtime exception, if they are well-documented, you are giving the caller a choice.
It is a known problem that checked exceptions are over-used in Java, but it doesn't mean that they are all bad. That's why it is such in integral part of the Spring philosophy, for example (http://www.springsource.org/about)
The advantage of checked exceptions is that the compiler forces the developer to deal with them earlier. The disadvantage, in my mind anyway, is that developers tend to be lazy and impatient, and stub out the exception-handling code with the intention of coming back and fixing it later. Which, of course, rarely happens.
Bruce Eckel, author of Thinking in Java, has a nice essay on this topic.
I don't think the scenario (insufficient funds) warrants throwing an Exception --- it's simply not exceptional enough, and should be handled by the normal control flow of the program. However, if I really had to throw an exception, I would choose a checked exception, by extending Exception, not RuntimeException which is unchecked. This forces me to handle the exception explicitly (I need to declare it to be thrown, or catch it somewhere).
IllegalArgumentException is a subclass of RuntimeException, which makes it an unchecked exception. I would only consider throwing this if the caller has some convenient way of determining whether or not the method arguments are legal. In your particular code, it's not clear if the caller has access to balance, or whether the whole "check balance and transfer funds" is an atomic operation (if it isn't then the caller really has no convenient way of validating the arguments).
EDIT: Clarified my position on throwing IllegalArgumentException.
Line is not always clear, but for me usually RuntimeException = programming errors, checked exceptions = external errors. This is very rough categorization though. Like others say, checked exceptions force you to handle, or at least think for a very tiny fraction of time, about it.
Myself, I prefer using checked exceptions as I can.
If you are an API Developer (back-end developer), use checked exceptions, otherwise, use Runtime exceptions.
Also note that, using Runtime exceptions in some situations is to be considered a big mistake, for example if you are to throw runtime exceptions from your session beans (see : http://m-hewedy.blogspot.com/2010/01/avoid-throwing-runtimeexception-from.html for more info about the problem from using Runtime excpetions in session beans).

Categories