Best way to exit a program when I want an exception to be thrown?
I'm writing a Java program th开发者_运维知识库at reads in a file of words. The program crucially depends on this file, so I really do want the program to end if for whatever reason there's an IOException when reading the file.
What's the best way to end the program? I think I'm forced to surround my file-reading inside a try/catch block, so should I add a System.exit(0)
inside my catch? For example, should I do something like the following?
try {
BufferedReader br = new BufferedReader(new FileReader("myfile.txt"));
String line;
while ((line = br.readLine()) != null) {
// process...
}
} catch(IOException e) {
System.out.println("Error: " + e);
System.exit(0); // ???
}
If you let the exception propagate all the way up to the main()
method, the program will end. There's no need to call System.exit
, just allow the exception to bubble up the stack naturally (by adding throws IOException
) to the necessary methods.
Edit: As @Brian pointed out, you may want to catch the IOException
in your main
method, and call System.exit
there instead, supplying a human-readable error message (stack traces can scare people). Also, as @MeBigFatGuy said, calling System.exit
from inside your code stack is bad practice, and limits the reuseability of the code. If you must use System.exit
, then keep it inside the body of the main
method.
That's fine. However 0
as an exit code means the program ended as expected. You'll want to use a different number ;)
If you really do wish to terminate the program immediately, rather than letting upper levels of the program decide what to do (maybe the core of your program will be extended some day to allow selecting a source for myfile.txt
from various websites, or speech-to-text synthesis, or direct brain transfer), you should call: System.exit(1)
(or some other non-zero exit status).
An exit code of 0
says to the shell (and parent processes) that execution completed normally. Non-zero exit codes report that there was an error. This is vital for making excellent tools to notify admins of abnormal execution faults, or for writing friendly little programs:
./fiddle_with_words myfile.txt || mail -s "program failed" grautur@example.com
@gratur asks in a comment on @skaffman's answer.
So if I understand correctly, I let the exception bubble up by removing the try/catch block and adding a "throws IOException" to that method (and methods that call that method, and so on)? I feel kind of icky doing that, because now I have to add a bunch of "throws IOException"s everywhere -- is my ickiness misguided?
I think it depends. If the exception only has to bubble up a small number of levels, and it makes sense for the methods to propagate an IOException
, then that's what you should do. There is nothing particularly "icky" about allowing an exception to propagate.
On the other hand, if the IOException
has to propagate through many levels and there is no chance that it might be handled specifically beyond a certain point, you may want to:
- define a custom
ApplicationErrorException
that is a subclass ofRuntimeException
, - catch the
IOException
near its source and throw anApplicationErrorException
in its place ... with thecause
set of course, and - catch the
ApplicationErrorException
exception in yourmain
method.
At the point in main
where you catch the ApplicationErrorException
, you can call System.exit()
with a non-zero status code, and optionally print or log a stack trace. (In fact, you might want to distinguish the cases where you do and don't want a stack trace by specializing your "application error" exception.)
Note that we are still allowing an exception to propagate to main
... for the reasons explained in @skaffman's answer.
One last thing that complicates this question is exceptions that are thrown on the stack of some thread other than the main
thread. You probably don't want the exception to be handled and turned into a System.exit()
on the other thread's stack ... because that won't give other threads a chance to shut down cleanly. On the other hand, if you do nothing, the default behaviour is for the other thread to just terminate with an uncaught exception. If nothing is join()
-ing the thread, this can go unnoticed. Unfortunately, there's no simple "one size fits all" solution.
精彩评论