Instead of throwing new Exception(\"Some message\", maybeSomeCause)
, which means that all callers of my method will need to catch Exception (which can include Runti
Most core exceptions are too specialized to be used directly, unless you're duplicating existing functionality in the core libs. For instance, you'll probably never need to create an an instance of UnknownHostException
; if host resolution fails, the InetAddress
or SocketFactory
method you called would have already created and thrown the exception.
The only exceptions I've found to be generally usable are IOException
, IllegalArgumentException
, IllegalStateException
, and UnsupportedOperationException
.
IOException
- All problems with interfaces, networking, and hard drive access fall under this. If you're writing code to access external data or hardware, you should be using this. For instance, if you're implementing an API to access a certain type of network device, you can make a MyDeviceException
subclass to be thrown when the device returns an error status or does something strange. There are also some cases where you want to catch an IOException
from one or more low-level library calls and wrap it in another IOException
with a higher-level message, such as a connectivity check throwing a "Device not available" exception caused by a "Request timed out" exception.
IllegalArgumentException
- Any parameter checks should throw this. For example, a negative integer for a size parameter, or an unexpected null
. This is an unchecked exception, but I recommend documenting it anyway to make the method preconditions more clear. You can find lots of examples in the core libs.
IllegalStateException
- You can use this when the method parameters are valid, but some internal data or functionality required by the method is unavailable, and there isn't a more appropriate checked exception (like IOException
). It's often better to design things so that this isn't necessary.
UnsupportedOperationException
- If you make a subclass of something and one of the superclass methods is conceptually invalid for it, override it and throw one of these. Guava uses this for its immutable collection classes, since Java's collection interfaces aren't designed to support immutability. This tends to be a sign of bad design in the superclass. Don't use it if just doing nothing or returning null/empty would be an appropriate and unsurprising result.
If users of your code might need to do different things on two different exceptions, then those should be distinct exception types. That said, the JDK exceptions cover most of the "programmer error" exceptions -- if an IllegalArgumentException
is getting thrown, for example, that indicates a programming mistake, not something that should be handled at runtime.
Absolutely it makes sense to reuse Exception
classes when they reasonably describe the scenario that caused the exception to be thrown.
The lists provided in your question are not very usable as quick-reference material, and most descriptions in the dev docs seem cryptic to me.
I haven't run across any short-ish lists of the most reusable built-in exceptions. I've done my best to create one below, but I'm sure it is far from perfect.
github gist link (or see current content below)
organized by estimated utility
Thrown to indicate that a method has been passed an illegal or inappropriate argument.
Thrown to indicate that an index of some sort (such as to an array, to a string, or to a vector) is out of range.
Thrown when the requested mathematical operation is non-sensical or impossible.
example: int x = 1/0
;
The application is not in an appropriate state for the requested operation. example: trying to save before file is loaded or created.
Throw this when you have recieved improperly formatted data.
example: MyClass.applyJSONString("{non:sense,all,garbled=definitely.not;json{{{")
Throw this if something took too long and you're giving up.
I think it makes sense to throw this if you are trying to looking for an object using a key and it was not found or the key is otherwise invalid, but I don't really understand the dev docs on it.
example: myDataStructure.get("lookup_key");
when lookup_key
is not in the data structure.
Having some problem reading/writing? Throw this exception.
Running a script of some form and found a problem with it (not I/O or parsing)? Throw this exception.
Throw this if you encounter a security-related issue.
Use this for some runtime-error that doesn't fit well into any other category.
Yes, it's very good to do that. In fact, it's even written about in Effective Java, 2nd ed. See item 60 on page 248: "Favor the use of standard exceptions"
Reusing preexisting exceptions has several benefits. Chief among these, it makes your API easier to learn and use because it matches established conventions with which programmers are already familiar. A close second is that programs using your API are easier to read because they aren’t cluttered with unfamiliar exceptions. Last (and least), fewer exception classes mean a smaller memory footprint and less time spent loading classes.