GeeCON Prague 2014*
The moose likes Java in General and the fly likes IOException rant - good idea or 'lazyman' solution? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


JavaRanch » Java Forums » Java » Java in General
Bookmark "IOException rant - good idea or Watch "IOException rant - good idea or New topic
Author

IOException rant - good idea or 'lazyman' solution?

Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

This is one of those "why did the designers do this" questions; so I'm quite happy if you just tell me to get a life and e-mail them.
However, we've had quite a few questions about Exception handling in general, so this rant is my attempt to spark a bit of discussion.

First: I like Java Exceptions; and I congratulate Java as one of the first languages to recognise them as being an important part of program control.

My rant is directed at the person who decided that IOException is not an Error. What were they thinking? Java, as a language, wasn't even supposed to know about things like files (or I/O) intrinsically, so what flight of fancy suggested that an IOException could possibly be recoverable?

That choice - and Java's stubborn refusal to rectify (or even modify) it - have condemned a generation of Java programmers to either use try...catch blocks when they shouldn't need to, or redundantly declare methods as throwing IOException.

My opening shot. Bring it on...

Winston


Isn't it funny how there's always time and money enough to do it WRONG?
Articles by Winston can be found here
Paul Clapham
Bartender

Joined: Oct 14, 2005
Posts: 18570
    
    8

What? Java "wasn't supposed to know ... about I/O"? I can't imagine what the basis for such a statement would be.

And I also don't know why you think that an IOException couldn't possibly be recoverable. Suppose my code gets a file name from a configuration property, and it turns out that when my code tries to read the file, it doesn't exist. So why shouldn't the code recover by asking the user to provide the name of a suitable file which does exist? So there. It could possibly be recoverable.

And then there's socket programming -- one of the things which Java was definitely designed for -- where you need to know when the process at the other end of the connection goes away, so you can react accordingly. Note that "react accordingly" doesn't mean "recover" from the error, there's no need to try to get the other end to reconnect, but instead it means to do something reasonable instead. This is a lot different from Error, which as the API docs say "these errors are abnormal conditions that should never occur". You could hardly say that a dropped connection should never occur, it happens regularly.
Martin Vajsar
Sheriff

Joined: Aug 22, 2010
Posts: 3610
    
  60

I sometimes feel very similar about SQLException. Every single method in my application which touches the database has the following general structure:

(The DaoException is a custom, unchecked exception of mine.)

In other words, (nearly) every occurrence of SQLException in my application is unexpected and generally unrecoverable. It is logged and the current processing is terminated. (There are a few exceptions to this rule, such as when I check for possible database constraint violations.) I wouldn't mind if SQLException was unchecked. However, given that I have to use the finally clause anyway to close resources, the need to handle SQLException is sometimes a welcome reminder for me to do so.

On the other hand, if I was writing an SQL client in Java (something like TOAD, for example), I would probably want to check and handle every SQLException that occurred, at the very least to be able to show the user a meaningful and useful error message. If the exception was not checked in this situation, I would be probably missing it a lot.

So I'd say that it after all depends on the needs of the application you're creating. And since there are valid reasons for these exceptions to be checked (Paul has provided some for the IOException), it was probably a good decision to make them checked after all.
Matthew Brown
Bartender

Joined: Apr 06, 2010
Posts: 4396
    
    8

When I think about checked exceptions, I don't think of them in terms of recoverability. I think of it like this: is this something that might happen, that is beyond the control of the programmer? If so, then you better plan what you're going to do when it happens - hence making it checked. Whereas runtime exceptions should indicate a bug - you don't plan for bugs, you fix them.

Given that, I think IOException fits the bill perfectly. I'd go so far as to say it's the example I'd use to explain what checked exceptions are for. You try to write a file, but your app doesn't have write permission to the file system? You try to connect to a server, but it's turned off? What are you going to do? That's about the application environment - you have no control at all over that when writing the code.

I understand the arguments against checked exceptions (and I'm in two minds over whether I agree with them). But if you're going to have them, then I think IOException should be one.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Paul Clapham wrote:What? Java "wasn't supposed to know ... about I/O"?...

That's a good start.

For one: the language doesn't contain any native I/O statements OR include any I/O classes in java.lang.

True, java.io has been around pretty much since inception, but everything about the framework (as I see it) has been to provide an interface to I/O, NOT direct interaction with specific devices (indeed, it's one of the major criticisms of the framework; but one that I completely agree with). Argue that if you like; but on that basis alone, I think my rant stands.

And I also don't know why you think that an IOException couldn't possibly be recoverable.

I don't think I said that. I said: why would the designer assume that it IS recoverable. Perhaps we're talking about degree; but most machine-based I/O exceptions are NOT recoverable, so why would anyone assume that it is?
And, by making IOException checked, that is what the designer did: s/he said you MUST deal with this exception. No ifs or buts; no options; here it is: IOException. Deal with it, or throw it.

Suppose my code gets a file name from a configuration property, and it turns out that when my code tries to read the file, it doesn't exist. So why shouldn't the code recover by asking the user to provide the name of a suitable file which does exist? So there. It could possibly be recoverable.

Erm...this is an Exception isn't it? You're quoting to me something that would take at least block of code to determine. There's nothing to stop you creating a custom exception for the type of scenario you're referring to - in fact, I'd say it's a better solution. The problem is that the minute IOException rears its ugly head you HAVE to deal with it.
Personally, I view IOE rather like NPE - an effect, not a cause.

And that's part of my 'lazyman' argument:
Q: You don't want to deal with the specifics of a (supposedly) recoverable Exception?
A: Hand them back a checked exception; let them deal with it.
And hey, IOException is about as generic as it gets, so let's hand 'em that.

And then there's socket programming -- one of the things which Java was definitely designed for...

Unh. And haven't you ever prayed to God for something more specific than an IOException? Or for some way to extract yourself from interminable reliance on an indeterminate checked Exception?
Your "these errors are abnormal conditions that should never occur" situation has a perfectly valid Java alternative: An Error, which is unchecked.

Winston
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Martin Vajsar wrote:In other words, (nearly) every occurrence of SQLException in my application is unexpected and generally unrecoverable...
On the other hand, if I was writing an SQL client in Java (something like TOAD, for example), I would probably want to check and handle every SQLException that occurred.

In which case I come back to 'lazyman'. There is nothing to stop you creating custom exceptions - or even a hierarchy - that defines whatever Exceptions you want.

My contention is that forcing me to deal with every possible exception that might be thrown by a class (say BufferedReader, or FileInputStream), simply because someone decided that I might be able to recover from it, is ridiculous.

Why not just throw an Exception with a decent message? All IOException seems to be to me is an exception that says "Oh, BTW, this is thrown by one of our classes that has something to do with I/O".

Winston
Paul Clapham
Bartender

Joined: Oct 14, 2005
Posts: 18570
    
    8

Winston Gutkowski wrote:
And I also don't know why you think that an IOException couldn't possibly be recoverable.

I don't think I said that. I said: why would the designer assume that it IS recoverable.


Well, I know what you said because I scrolled back to look. And you said

Winston Gutkowski wrote:so what flight of fancy suggested that an IOException could possibly be recoverable?
Paul Clapham
Bartender

Joined: Oct 14, 2005
Posts: 18570
    
    8

Winston Gutkowski wrote:In which case I come back to 'lazyman'. There is nothing to stop you creating custom exceptions - or even a hierarchy - that defines whatever Exceptions you want.


So you're in favour of more-specific Exceptions being thrown.

Why not just throw an Exception with a decent message? All IOException seems to be to me is an exception that says "Oh, BTW, this is thrown by one of our classes that has something to do with I/O".


So you're in favour of less-specific Exceptions being thrown.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Matthew Brown wrote:Given that, I think IOException fits the bill perfectly. I'd go so far as to say it's the example I'd use to explain what checked exceptions are for. You try to write a file, but your app doesn't have write permission to the file system? You try to connect to a server, but it's turned off? What are you going to do? That's about the application environment - you have no control at all over that when writing the code.

I hear what you said in your first para (which I basically agree with), and I only removed it for space; hope you don't mind. The rest I can't agree with, for reasons I've tried to explain above.

Why have exceptions at all, other than for system or security concerns? Surely, to allow a program to fail in a manner that best describes its failure.
And, in my view, IOException fails miserably on that score.
It's like NPE: all it says is: Something happened that caused an error; and BTW, this is an I/O class.

And the worst part of it is that it's checked; so you have to deal with it. No choice; no explanation; no differentiation. Sorry folks, we deemed this an IOException so you've got to throw it - which, let's face it, is what we end up doing most of the time.

I'd also like to make it clear that my argument is only with IOException:
1. I think it should never have been made checked.
2. If someone can convince me that it should have been, then the Exception returned by the classes that do should never have been made public.

Winston
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Paul Clapham wrote:So you're in favour of more-specific Exceptions being thrown.

For checked Exceptions - absolutely.

Winston
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Paul Clapham wrote:So you're in favour of less-specific Exceptions being thrown.

Hmmm. Sophistry. Like it.

God, it's fun arguing with programmers.

Winston
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Paul Clapham wrote:Well, I know what you said because I scrolled back to look. And you said
Winston Gutkowski wrote:so what flight of fancy suggested that an IOException could possibly be recoverable?

You're quite right, and let me correct it now: what flight of fancy suggested [to the designers] that an IOException SHOULD be recoverable?

And, for anyone wondering about the semantics, a checked exception MUST be caught or thrown; so they are usually only used in situations when the user has (wonderful legal term) a "reasonable expectation" that the Exception is recoverable.

Tell me Paul: When was the last time you wrote a try...catch block simply to get rid of an IOException? And when you did it, did you always remember to write another one for the close() statement (if it was needed)?

IOException is a generic checked Exception, and I say it's a bad pattern - and one I hope I don't run into too many times in my programming career.

Winston
Paul Clapham
Bartender

Joined: Oct 14, 2005
Posts: 18570
    
    8

It seems you're only in favour of checked exceptions if there will ALWAYS be something the programmer needs to do when the exception is thrown. Let me show you my favourite example of when this fails:



Junilu Lacar
Bartender

Joined: Feb 26, 2001
Posts: 4474
    
    6

Just my $0.02 -- I won't jump in on the discussion on the merits or lack thereof of checked exceptions in general and IOException in particular. There's not really much I can do about that from a language perspective: it's there, it's like that, and we just have to deal with it. I think the problem really is that programmers don't deal with checked exceptions consistently. We've all seen the results of this lack of consistency, especially in applications written by more than one developer. The most common anti-patterns that come out of the inconsistency are perhaps 1) empty catch blocks and 2) long chains of checked exceptions that span multiple application layers.

That said, I'm a big user of Spring and whichever way Spring goes, so goes Junilu. This article: http://www.manageability.org/blog/stuff/exceptional-exception-handling-techniques has some good advice on dealing with exceptions. In particular, I usually go with #2 - Soften checked exceptions and #7 - Build default and provide for custom error handlers. On my teams, we have a section specifically for exception handling in our Coding Standards that calls out the different strategies to take. In our code reviews, we make sure exceptions are handled properly and according to the Coding Standards. That's about the best way right now I have found to try to deal with it and for the most part, it has worked out pretty good.


Junilu - [How to Ask Questions] [How to Answer Questions]
James Boswell
Bartender

Joined: Nov 09, 2011
Posts: 1025
    
    5

I haven't read all the responses here but my initial gut feeling is that the OP has linked an IOException exclusively to accessing files which is of course, not the case.

As for lazy, I think that might apply more to programmers moaning about such issues, the "cant be bother to write a try/catch block" brigade.

And of course, there are situations when IOExceptions are recoverable.
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19697
    
  20

I disagree in general with Winston on this, but with two remarks:

- FileNotFoundException is misused quite a bit. I try to open a file I don't have access to (because some other process has it locked)? FNFE. Opening a FileOutputStream / PrintStream / PrintWriter (yes, FileWriter is missing here in the API)? FNFE. I expect it to be thrown if I want to access a file but it's not there. If it's locked - FileLockedException. If I don't have permission? FilePermissionException. In other words - a proper sub class for each different type of error.

- close() throws an exception; not just in java.io but also java.sql and every other use of Closeable or AutoCloseable. I try to close a file / connection / whatever. It fails. So what do you want me to do, give up? Terminate my application? If it fails, then it fails, and I can't be bothered. So my application probably holds some resources it can't release anymore. Do I really need to let my entire application be terminated? The alternative is what almost everybody does already - log and ignore. So why not do that from the start? It would also have cleaned up a lot of code before try-with-resources, where either there were two nested try statements (*) or a try-catch around the closing (**).

* **


SCJP 1.4 - SCJP 6 - SCWCD 5 - OCEEJBD 6
How To Ask Questions How To Answer Questions
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19697
    
  20

Winston Gutkowski wrote:IOException is a generic checked Exception, and I say it's a bad pattern - and one I hope I don't run into too many times in my programming career.

I agree on this statement. Like I said in my previous post, there should be more specific sub classes. That way you can catch the ones you want instead of catch every single IOException and then try to filter on the message - which is different for different locales. I've seen both Dutch and English error messages for the same type of error, depending on the language of the OS.

SQLException has the same problem. Java 6 finally added SQLIntegrityConstraintViolationException which should be used if a unique key or foreign key problem occurs, or SQLInvalidAuthorizationSpecException if login fails. However, because it took so long to be added, almost no JDBC driver vendor uses it. In other words - we have to catch SQLException and again check for the error message / code.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Paul Clapham wrote:It seems you're only in favour of checked exceptions if there will ALWAYS be something the programmer needs to do when the exception is thrown.

Hmmm. Don't think I've said that, but I'm certainly in favour of throwing a checked exception ONLY when when the client has a chance of actually doing something about it.

As for your example, I would hope that, if it's checked, the Exception is so unlikely to be thrown that I can simply wrap it and re-throw it as an unchecked Exception - which then begs the question: Why make it checked in the first place? Which may be your question; and it's definitely mine as regards IOException.

Winston
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Junilu Lacar wrote:There's not really much I can do about that from a language perspective: it's there, it's like that, and we just have to deal with it....

Yes, and I hope I started this thread off right with my first post.
IOE is what it is; just the same as many other anomalies in Java are. I guess what I'm trying to understand is how the people who thought up the whole business of an Exception hierarchy (which I think is great) could have made such a fundamental error with one of the first major Exceptions we all have to deal with.

Someone, somewhere must have said: Yes, this (IOException) needs to be checked. And the die was cast.

Winston
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

James Boswell wrote:As for lazy, I think that might apply more to programmers moaning about such issues, the "cant be bother to write a try/catch block" brigade.

No. 'Fraid you got me wrong there. I'm saying IOException is the 'lazyman' designer's friend:

Hey, I'm designing a Stream, I've got to give it a close() method...darn, I can't close it...oh, wait a minute, I can throw this wonderful catchall IOException that everybody knows about, and now it's somebody else's problem. Simple, eh? OO design in action.

Winston
Junilu Lacar
Bartender

Joined: Feb 26, 2001
Posts: 4474
    
    6

Winston Gutkowski wrote:Someone, somewhere must have said: Yes, this (IOException) needs to be checked. And the die was cast.

Maybe that's not even how it went down... did the one ring to rule them all come first or last?
Paul Clapham
Bartender

Joined: Oct 14, 2005
Posts: 18570
    
    8

Winston Gutkowski wrote:I guess what I'm trying to understand is how the people who thought up the whole business of an Exception hierarchy (which I think is great) could have made such a fundamental error with one of the first major Exceptions we all have to deal with.

Someone, somewhere must have said: Yes, this (IOException) needs to be checked. And the die was cast.


But of course it needs to be checked. It isn't like an Error, which occurs when your application is already on its way over the cliff. And it isn't like a RuntimeException, which occurs when you've made a programming mistake like trying to access a nonexistent array element. That means it has to be a checked exception, you only have the three choices in Java.

I understand your desire to get more information from an IOException, in the form of subclasses thereof. That sounds perfectly reasonable to me. I'd like the same for SQLException too. (Although there you're limited by the shoddy error-reporting capabilities of database software.) But saying that since you don't get as much information as you would like, you think that therefore you shouldn't have to catch it at all, I don't see the logic behind that point of view.

Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Paul Clapham wrote:But of course it needs to be checked. It isn't like an Error, which occurs when your application is already on its way over the cliff.

It isn't? In 11 years I've never written an application that could recover from a critical read/write error. And that's the problem: it doesn't matter if it's reading, writing, opening, closing, something that you might be able to recover from, something you might not. Nope. IOException. That's what you got. Wanna parse the message? Hey, be our guest...

And it isn't like a RuntimeException, which occurs when you've made a programming mistake like trying to access a nonexistent array element.
That means it has to be a checked exception, you only have the three choices in Java.

Says who? 99% of the time, in my experience, an IOException should have been an Error, so why not treat it as such?
If that offends your sensibilities, at least make it an unchecked exception - of which we have only two types: RuntimeException or Error. I didn't design the hierarchy, or the 'mantras' that go with it; but don't force me into redundant throwing simply because you (ie, Java designers) got it wrong. If it was unchecked, I could have caught it if and when my program thought it was worth catching; but no, I'm forced to catch 'em all (or throw 'em).

However, like Junilu said, it is what it is, so I'm probably barking at the moon. I notice that v7 seems to have some unchecked alternatives now, so maybe I'm not barking alone.

Winston
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Junilu Lacar wrote:Maybe that's not even how it went down... did the one ring to rule them all come first or last?

Very good point. If last, I'd say it tends to support my 'lazyman' theory though...

Winston
Pat Farrell
Rancher

Joined: Aug 11, 2007
Posts: 4659
    
    5


close() throwing an exception is evil.

And the UTF-8 is missing code makes me cringe because I too have written it a zillion times.
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Thanks everybody for your contributions. Paul - hope you didn't mind butting heads; I really appreciated your posts, even if we can't agree on this one.

Beddie-byes for me now.

Thanks again all. Feel free to add more, I'll check in tomorrow morn.

Winston
Paul Clapham
Bartender

Joined: Oct 14, 2005
Posts: 18570
    
    8

Winston Gutkowski wrote:Says who? 99% of the time, in my experience, an IOException should have been an Error, so why not treat it as such?


I think I have started to understand what you're on about. Yeah, most of the time I encounter IOException (based on my actual survey of an application I wrote comprising several thousand lines of code) is because my XML parsers and transformers are saying they might throw it. And yeah, in that case I just ignore it because it isn't going to be thrown by those classes the way I'm using them.

And it's the same with SQLException. It's never going to be thrown in my code (unless I do something stupid like deleting some of my database tables) so I just catch it and display a brief message.

But it's like I said earlier: you've only got three classes of exception in Java, the Error for when things are totally snafu, the RuntimeException for when you made a programming error, and the rest, which are all checked exceptions by design. The latter group can't be treated as Errors because that category is reserved for VM-level problems, so you're pretty much stuck. (Interestingly there is a subclass of Error named IOError, which was new in Java 6.) Perhaps you would like to revise your opinion and say that IOException should be treated as a RuntimeException? (And perhaps you'd like to look a little harder and see if you can identify any exceptions you think should be checked?)

As for that application I mentioned: I did a scan of it and found a couple of hundred catch-clauses in it. Around 90% of them are SQLException, which like I said I don't bother with. In fact I only found a small number of catch-clauses where I was doing anything other then writing out the stack trace, and ironically they were all handling NumberFormatException, which is actually unchecked because it's a RuntimeException. (This wasn't a thorough review but I don't think I missed anything major.)
Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Paul Clapham wrote:Interestingly there is a subclass of Error named IOError, which was new in Java 6.

Hmmm, I wonder whether it was added as prep for nio?

Perhaps you would like to revise your opinion and say that IOException should be treated as a RuntimeException? (And perhaps you'd like to look a little harder and see if you can identify any exceptions you think should be checked?)

Yep, maybe I didn't make myself clear. I think IOE should have been a RuntimeException; and I also think that it should have been made a hierarchy, so that things like open and close errors could have been differentiated from "other sundry" errors.

As for ones that should be: Of the "vaguer" ones, I think ParseException is reasonable; particularly if it can provide useful status information to a client.
I also think it's a perfectly valid design tool for internal exception handling. If, for example, I was managing a large project, I might specify that a particular method or module throw a checked exception to ensure that programmers can't forget about it. Obviously, it would be for situations that can be reasonably expected to be dealt with.

Oh, and totally agree about SQLException. I think of it as 'java.sql.IOException'.

Thanks again for your contributions.

Winston
Michael Parmeley
Greenhorn

Joined: Aug 20, 2004
Posts: 14
I won't disagree that IOException should be split into more specific exceptions. However, as the API is now IOException should most certainly be checked because you can frequently recover from it. The most common place it can be recovered from is socket programming. IOExceptions frequently trigger reconnect or failover logic when dealing with network connections.

Now there are exceptions in the JDK that are currently checked that most certainly should be unchecked, the 3 that immediately come to mind are:

MalformedURLException
UnsupportedEncodingException
NumberFormatException

Winston Gutkowski
Bartender

Joined: Mar 17, 2011
Posts: 7892
    
  21

Michael Parmeley wrote:I won't disagree that IOException should be split into more specific exceptions. However, as the API is now IOException should most certainly be checked because you can frequently recover from it. The most common place it can be recovered from is socket programming. IOExceptions frequently trigger reconnect or failover logic when dealing with network connections.

Right, but there would be nothing to stop you from catching an IOException even if it subclassed RuntimeException.

I totally agree with you about the API though. Personally, I think that CheckedException should have been a marker interface rather than an implicit hierarchy.

What you say also suggests to me that sockets should probably throw specific checked exceptions rather than IOException; and that's part of my rant. IOE just seems to me to be this vague bottomless pit of "something happened" - except that you can't ignore it.

Winston
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 39044
    
  23
NumberFormatException always used to be unchecked.
Paul Clapham
Bartender

Joined: Oct 14, 2005
Posts: 18570
    
    8

Campbell Ritchie wrote:NumberFormatException always used to be unchecked.


And it still is.
Paul Clapham
Bartender

Joined: Oct 14, 2005
Posts: 18570
    
    8

Winston Gutkowski wrote:What you say also suggests to me that sockets should probably throw specific checked exceptions rather than IOException; and that's part of my rant. IOE just seems to me to be this vague bottomless pit of "something happened" - except that you can't ignore it.


You mean like SocketException, which is thrown by all kinds of socket-related classes and methods?
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: IOException rant - good idea or 'lazyman' solution?