I am wondering how in practice other SOers tend to deal with and/or prevent exceptions.
In what situations do you prevent exceptions, and how? In what situations do you catch exceptions?
I usually prevent 'NullPointerExceptions' (and other similar ones) by, well, essentially saying if(foo!=null) {...}
I find that in most situations this is less bulky than everything involved in using a try-catch block.
I use try-catch blocks when the potential exceptions are more complex, or more numerous.
In general, I use exceptions when the exception should cause a process to abort. When I'm going to do something about the problem and recover in some way, I try to prevent the exception from ever happening.
Like, if a parameter is passed in to a subroutine and I reasonably expect that it might be null, I'll check it for null. In real life, for example, a null String often is equivalent to a zero-length String, in which I'll just write < if (s==null) s=""; >.
But if a null String means that something has gone badly wrong and we should just quit the whole process and display a "Panic -- Abort -- World ending soon" type of message to the user, then an exception is very handy. You can throw the exception way down deep inside many layers of subroutines, and just catch it at the top, display the message, and you're done.
I often create my own exceptions for such conditions. Many of my programs are sprinkled with code like < throw new BadInputException("Customer number not found") > to just get me out, display a message, and quit. This really saves on deep nesting of IFs and constant checking of return values from subroutines.
I use the following class throughout my code to validate and abort processing:
This way you can validate or catch exceptions immediately, log them and return the abort object.
In general, if it is reasonable to do so, you should try to prevent the exception from occurring in the first place. Quite frequently, it's not reasonable or possibly flat-out impossible (especially when io in concerned), but that's what try/catch are for. In particular, this means that you should always check your pointers and your array indexes to prevent the NullPointerException and ArrayIndexOutOfBoundsException. Unless, of course, there is nothing you can do about it and would have to rethrow it anyway.
There are three kinds of exceptions.
Runtime exceptions are always preventable. You just have to program correctly.
Checked exceptions should be transformed to the right level of abstraction if possible ( not throw a SQLException to the user if he doesn't know/care about SQL exceptions ) or handled at the higher level ( that is, let them pop up ) and display/log proper message.
Errors should not be handled at all.
See the link for more details on how to prevent RuntimeExceptions
I will check the input parameters at the beginning of a method and throw an IllegalArgumentException if they are outside what should be passed to the method. The idea being that it's a programming error and it should be fixed. Better now than when it's out in the field. If in the middle of a method I get an unexpected condition (null in a list, etc) I will log a fatal message and do a System.exit(2). Again this forces you to fix an issue vs. just logging it and moving on.
In general, exceptions should be something exceptional, e.g. unforeseeable or due to programming errors. The problem is, there are a couple of dubious design descisions in the Java class library so you end up with idioms like:
Clearly that code isn't perfect (will throw a NullPointerException on EOF) but it demonstrates the issue of using exceptions for things that aren't actually exceptional.