问题
I wish to handle Exceptions in a meaningful way in a Swing application.
The following is inside an actionPerformed
method. The UiUtils#showError
displays a JOptionPane with a button that shows/hides the stack trace. ApplicationException is a custom class to translate low level Exceptions to something a user would understand.
One issue is that I'm not sure how to handle a NullPointerException
that propagates up if a user doesn't select a file in the JFileChooser
before this code. The exportData
method purposefully checks for null on entry so no file handling is done.
Also, it seems that it would be a good approach to wrap a low level Exception
(from the data layer for example). I'd like to modify ApplicationException
to keep an instance instead of doing this in the showError
method.
Finally, there's one thing that's bothering me and that's the possibility that a few Exceptions could happen simultaneously. I have no idea how to handle this so I'm open to any suggestions.
try {
dataService.exportData(list, selectedFile);
} catch (IOException e) {
UiUtils.showError(new ApplicationException("Input/Ouput error"), e );
} finally {
if( list == null){
UiUtils.showError(new ApplicationException("No data to export"), null );
}
if( selectedFile == null ){
UiUtils.showError(new ApplicationException("No file selected"), null );
}
}
回答1:
To catch NullPointerException (or any RuntimeException for that matter) as well as your IOExceptionjust catch the most general exception type:
try {
dataService.exportData(list, selectedFile);
} catch (Exception e) {
UiUtils.showError(new ApplicationException(e), e );
} finally {
...
}
You can wrap the original exception into your ApplicationException by adding it as a "cause" parameter to the constructor, e.g.:
public class ApplicationException extends RuntimeException {
public ApplicationException(Exception cause) {
super(cause);
}
...
}
Then the original exception would be always available via the getCause() method.
If you program is not multithreaded, I wouldn't worry about simultaneous exceptions.
回答2:
Users don't understand exceptions however nicely you coat or layer them ;-) Design every end-user targeted application in a way that there are none. And keep in mind that exceptions are for .. well .. exceptional state, nothing else.
F.i, empty selection is a perfectly valid state of a ui which allows to select something (and act on the selected item). If acting on empty-selection bubbles up as a NPE, the acting logic is incorrect - it must cope with any valid state. One option to cope might be to be disabled (as trashgod already suggested), another might be to show a warning label as long as there's nothing selected.
回答3:
For reference, nothing happens "simultaneously" on the event dispatch thread; the EventQueue enforces this. Moreover, Swing restarts the EDT on uncaught exceptions, but you can substitute your own handler, as shown here.
Addendum: @Sasha O has helpfully addressed the question directly. Alternatively, if you can arrange never to call the method with a null
file handle, you can assert
that fact as a precondition. See Programming With Assertions for details.
This leaves me wondering in what cases inputs should be checked before a method call or inside a method.
A lot depends on the design. Instead of dealing with "No file selected," disable affected controls until a valid file has been selected. Instead of dealing with "No data to export," filter files by type, size or content in the chooser dialog. You still have to deal with I/O faults, but that's inevitable, as they are external to your program.
Addendum: This raises the problem of helping the user understand why a control is disabled. Some applications use a status bar to show such information. A tooltip can help, as shown here, even on a disabled control.
You should not use assertions to check the parameters of a public method.
来源:https://stackoverflow.com/questions/5774437/handling-exceptions-in-a-swing-ui-low-level-to-high-level-and-exception-wrappin