I thought that IOException and FileNotFoundException are exactly such kind of exceptions
Nope, those are actually the "other" type of exceptions, the kind that go beyond your programming skills. No matter how good do you program, the compiler and the libraries make you be "conscious" that something might happen.
Think about this scenario:
You create an application that saves data to a temp folder.
Everything is alright, you have checked the folder exists, and if not, you create it your self.
And then you're writing 2 mb to that temp folder.
Suddenly, other system process, deletes your temp folder, and you cannot write anymore.
There is nothing you can do to prevent this programmatically, in some systems that operation could happen ( In unix the root user may perform rm -rf /tmp and there is nothing you can do about it. In windows I think the system won't let other process delete a file is is being used )
By forcing you to check this kind of exceptions in the code, the platform designers thought that at least you're aware of this.
Jon is correct sometimes there is nothing you can do about it, probably logging before the program dies, that is considered as "handle the exception" ( poor handle yes, but handle at least )
try {
....
} catch( IOException ioe ) {
logger.severe(
String.format("Got ioe while writting file %s. Data was acquired using id = %d, the message is: %s",
fileName,
idWhereDataCame,
ioe.getMessage()) );
throw ioe;
}
Another thing you can do is to "chain" the exception to fit the abstraction.
Probably your application, is has a GUI, showing a IOException to the user won't mean anything or could be a security vulnerability. A modified message could be sent.
try {
....
} catch( IOException ioe ) {
throw new EndUserException("The operation you've requeste could not be completed, please contact your administrator" , ioe );
}
And the EndUserException could be trapped somewhere in the gui and presented to the user in a Dialog message ( instead of just disappearing the app in his eyes without further information ). Of course there was nothing you can do to recover that IOException, but at least you die with style :P
Finally a client code, could use different implementations, and not all the exceptions would make sense.
For instance, think again on the fist scenario. That same "operation" could have three kinds of "plugins" services to perform the data saving.
a) Write the data to a file.
b) Or, write to a db
c) Or write to a remote server.
The interface should not throw:
java.io.IOException
java.sql.SQLException
nor
java.net.UnknownHostException
But instead something like
my.application.DataNotSavedException
and the different implementations would handle the exception at the correct level, and transform it to the appropriate abstraction:
Client code:
DataSaver saver = DataServer.getSaverFor("someKeyIdString");
try {
saver.save( myData );
} catch( DataNotSavedException dnse ) {
// Oh well... .
ShowEndUserError("Data could not be saved due to : " dnse.getMessage() );
}
Implementation code:
class ServerSaver implements DataSaver {
....
public void save( Data data ) throws DataNotSavedException {
// Connect the remore server.
try {
Socket socket = new Socket( this.remoteServer, this.remotePort );
OuputStream out = socket.getOut....
....
....
} catch ( UnknownHostException uhe ) {
// Oops....
throw new DataNotSavedException( uhe );
}
}
}
FileSaver and DatabaseSaver would do something similar.
All of these are Checked Exceptions because the compiler make you check them.
When to use one or the other ( checked / unchecked): here
There are other two kinds: here
And finally a much simpler explanation of the Runtime is: here