I'm currently working on a project and I've come upon a bit of a head scratcher. I've been programming in Java for about two years, and I've covered exceptions, but never properly understood them.
In my current situation I've got my main method which initializes a class
WikiGraph wiki = wiki = new WikiGraph(getFile());
The Wikigraph constructor takes a filename which I get via a DialogBox in the getFile() method.
The constructor for wikigraph then calls a method called loadfile(filename) which attemps to load and parse the file given.
The loadfile() method is where I will throw an IncorrectFileTypeError.
My question is, where should I handle this?
At the moment I catch it in the loadfile() method
try {
//load file
} catch (IncorrectFileTypeError e){
System.out.println("Incorrect file type: "+filename+": "+e.getMessage());
throw new IncorrectFileTypeError();
}
But I also catch it at the WikiGraph initialization like so:
while(wiki==null){ //While There is no valid file to add to the wikigraph
try {
wiki = new WikiGraph(getFile()); //Try to load file
} catch (IncorrectFileTypeError e) { //If file cannot be loaded
JOptionPane.showMessageDialog(null, "Incorrect File Type Given. Please Choose another file."); //Display error message
getFile(); //Prompt user for another file
}
}
Now is the way I've handled the error the correct/best way? Or should it be handled elsewhere, such as in the getFile() method?
EDIT: I suppose I should make the file issue a bit clearer.
The File extension is not what the IncorrestFileTypeError is based on, and thus it may be a misleading error name.
The file given may have pretty much any extension, its the contents of that must be well formed.
In this case, I would avoid using exceptions as your primary method of dealing with incorrect file types. If an exception can regularly be triggered by user input, it really shouldn't be treated as an exception. Here's the approach I would take:
Check the file type and alert the user if the file type is invalid, through standard control flow. You might consider a static method on WikiGraph like IsFileValid(filename)
In the WikiGraph initialization, throw an exception if the file type is invalid.
This approach gives you the best of both worlds - you have the opportunity to alert users when invalid data is provided, while still ensuring from WikiGraphs perspective that the information provided is accurate. It gives developers working against a WikiGraph a way to ensure their input is valid without necessarily requiring exception handling.
One of the main benefits of exceptions is that they give you convenient means to handle an exception far from where it occurs. In languages that don't support it, you would have had to have each call on the path check the return value, break and return, so that you are manually propagating.
It makes sense to handle the exception where you feel you can either recover from it or best report it and cancel the operation.
My understanding is that the interaction starts with UI input and that if the file type is inappropriate, you cannot really recover. Therefore, I would have whatever UI task that initiated the file open catch the exception, report to the user that an error occurred, and either cancel or ask for a different input.
On a second reading, it seems like you are opening the dialog after you've already started trying to create the graph. I personally like to isolate UI interaction. I would therefore personally first handle all UI input, get the expected file name, verifies that it meets my needs, report to the user if not, and only continue further if the file is ok, then reporting only critical and unexpected errors.
I don't think it makes sense to catch it in loadfile. You can still write a log message (use System.err), just do it before throwing the exception. You're on the right track with catching the exception where you can do something about it (in this case prompting the user again).
If the problem is that the user has choosen a file of the wrong type then I don't think you should let the code proceed that far at all. This does not really seem like it should be an Exception at all but more a path in the program. If the user has selected an incorrect file type then he should be presented with the choice of choosing the file again. Obviously you should limit the choices in the JFileChooser to files of the correct type if it is as easy as looking at the extension.
I think this is the type of situation that checked exceptions are designed for (whether you agree with them or not.) I assume IncorrectFileTypeError extends Error? Extending RuntimeException would be more appropriate, and extending IOException would be better still, because this kind of error can be triggered by valid user input (i.e. typing the name of a file that exists but has the wrong type.)
I believe this type of error (IncorrectFileTypeError) can be resolved in the User Input Form avoiding an unnecessary roundtrip to filesystem service layer.
Related
I am in my app trying to load level which can be created by user and I want to protect my app against crash when it will get file with bad input. How should I do it?
This is my current code:
Json json = new Json();
json.setIgnoreUnknownFields(true);
JsonWorldValueCache jsonWrldCache = json.fromJson(JsonWorldValueCache.class, jsonWorld);
You can approach the problem on two fronts:
First, you can surround the Json#fromJson() call with a try-catch statement as #Elliott suggested. If you catch an exception, politely tell the player that there is something wrong with the level they created, and ask them if they want to try loading it again (presumably after they've fixed it) or go back.
Second, you can provide the user with a level editor so they don't have to modify the JSON file directly. While this won't remove the possibility of failure (users are pretty good at breaking things), it will remove the majority of issues since your editor can ensure the proper structures and values are adhered to in the level file.
I have my program working and all done (java). It's a short and easy program for a job interview. I handle stuff like improper input format by throwing a custom exception. Is that the best way to do it or should I just make a print statement?
Exceptions are only useful if they will be handled by other code.
If you're writing a reusable library, you should by all means throw an exception.
There is nothing more frustrating than calling a third-party library that logs errors to the console instead of telling your code about them.
However, if you're writing a standalone utility, it's nicer to print friendly error messages than an ugly stack trace.
The most flexible approach is to write reusable code that throws exceptions, then add catch blocks in main() (or elsewhere in the standalone portion) that prints friendly messages.
If you handle improper format inline is the code readable? If so - fine, if not - throw an exception and handle it elsewhere
Are you able to handle improper format properly in the place you are parsing it or maybe some more generic method/class/module is actually calling your routine and should decide what to do? If the latter is the case -> throw an exception
In general - it depends. If you can handle this special situation "inline" - you can do it (make sure it's readable). If not - throw an exception.
Here's a good reference on exception best practices. You should make sure you are following these.
In your particular case (based on the details you have provided) a user may upload/select a file that has bad data. You program should handle that by catching any basic Java runtime issues and returning information to the user (not "Exception in thread..." but something more readable to a user). If you are checking for these alpha characters then you should just handle that (with an error to the user) without throwing an exception - unless this is truly the behavior you want.
Exception are cause when the program cannot work in a normally correct manner.
The exceptions get more complicated and increase in numbers when you evolve from j2se to j2ee.
For a stand alone application
If your application is just a extremely simple calculator then you may just completely forget about exception because your user input would be filtered and one of the few exception would be division by zero
If your application is a simple utility tool say screen capture , then if your file cannot be saved (exception at file i/o) then all you need to do is simply terminate all your task and say some error message to the user.
For an advanced project of example 2 , you need to save the image in a temp , and perform saving of file once the issue is rectified
For a enterprise scaled and distributed application
Here transaction(inter related activities) is involved . Here a simple message to the user is also needed at times and also handle(do needed changes to related transactions) the exception !
If the application is distributed in many countries then exception in one traction needs alteration in another server in another country , this demands optional incorporation of a some thing that uses JMS API(message sending inside application)
JPA (java persistence api) implicitly rolls back the database on event of a exception and provides facility to do so for interrelated transactions . But still the roll back only affects the database and not the instance variable(object values)
and at all times you don't want to user to read your exact stack trace that says error at line number .....
I'm a little lost on how to handle unchecked exceptions in my GUI application.
I e.g. have a function that saves a company newly created by the user in a (embedded) database.
The function for saving the newly created company throws 3 Exceptions:
IllegalArgumentException: If the company or a not null field is null (Manually checked and thrown).
EntityExistException: If the company (it's name) already exists. (Also manually checked and thrown).
PersistenceException: If something went wrong when trying to save. (Catched and rethrown).
The function that calls the saveCompany method catches all 3 Exceptions and then logs them and shows a dialog to the user that an error had occurred.
Im now wondering if i need to catch them at all? Or would it be ok to just let them run up to the globalExceptionHandler (where i can also look them)?
And im also wondering what my reaction should be?
Should I tell the user that there was an error and let the program run (cause other parts of the program should function properly) or should I tell him and then end the program (cause it's a programmers error that shouldn't be in there)?
In case of the IllegalArgumentException you should catch the exception and tell the user to correct the data (do not print the stacktrace).
In case of the EntityExistException the user should be informed that the company already exists, and perhaps he or she should consider updating it.
When the user receives the PersistenceException they should be presented with a dialog window with the stacktrace (and perhaps other data relevant for the developer) and informed to submit a bug report.
So the good news is you're asking all the right questions.
Should i tell the user that there was an error and let the program run (cause other parts of the program should function properly) or should i tell him and then end the program (cause it's a programmers error that shouldn't be in there)?
That is a design question you need to think carefully about. If it is a recoverable error and there is nothing the program can do to continue running, then the program should shutdown without the user having the option. If part of the program must die but other parts may go one, the user should be informed. If the user needs to fix some data so the program can run, the user should be informed as such. Etc. Yes, you are asking the right questions though, you just do actually have to think about them and be judicious.
In my opinion , do the following
EntityExistException : Let user know that entity already exists. Continue with the app.
PersistenceException and IllegalArgumentException : Give user a generic message, and stop the app.
I hope you see the difference in how the above two exceptions are being handled. One is something that can be caused and fixed by the user. The other is something the user cannot do anything about.
I need to rename a file (keeping it in the same directory);
I can't seem to find a way to see if my program has the required permissions:
Files.isWritable(directory) && Files.isWritable(oldFile);
always returns true, wether or not the running user has the permission to write the file (I guess they only check if the file is read-only, even if this violates the contract stated in the javadoc);
I'm not running under a security manager so I can't call
System.getSecurityManager.checkDelete(oldFile.toString());
I need to check if the renaming of several files will (probably) succeed so I can't just try and catch the exception.
Is there a way out? Obviously a portable solution would be lovable but I would settle for a windows-specific one...
Well, you can't check Windows ACLs that way. The "native" solution is fairly easy, since Windows supports transactions on the file system. Just call DeleteFileTransacted, and roll back the transaction if any one deletion fails.
If you're not using tranactions, then the second option is to first open handles with explicit DELETE desired access (DELETE is one of the standard WinNT access rights), denying any sharing. If and only if this succeeds for all files, delete them all with SetFileInformationByHandle(handle, FileDispositionInfo, &fdiObj, sizeof(fdiObj));
(The latter is not a transaction and may have Isolation issues as a result, which in turn affect Atomicity).
Try new SecurityManager().checkDelete(oldFile.toString()).
Just try to move it! If the move failed, you didn't have permissions, or something else went wrong.
This is a general principle. Don't try to foretell the future, guessing whether an impending operation will succeed. Try the operation. Otherwise you introduce all sorts of extra problems:
You might make the wrong test.
The condition might change between the test and the operation.
The operation usually returns an error or throws an exception anyway, which you have to write code to handle: why write it all twice?
I'm developing a swing application and I'm a bit confused how can I handle exceptions for example lately a part of my code rename files, So when I was testing it I came up with a "you don't have permission to rename file" as I got it from print exception message. So How Could I express this message to user? and should I use JOptionPane message or just show it on the status bar?
Thanks
From your question it sounds like you already know how to handle the exception in the java sense. However you are looking for advice on how to react to exceptions once you have caught them.
In the specific example you give in your question I (as a user) would want that error presented quite clearly so a JOptionPane may be your best bet. I wouldn't just update the status bar as that is very close to silently failing and the user will just be left confused.
A personal rule of thumb is that if the user is likly to be waiting on the code to complete before getting on with their task then they must be informed of the failure strongly i.e. a modal box. If the failure is in a background task that the user can carry on without caring about, or the code can recover from it, or the code is going to retry, then I would go with the more subtle approach of the status bar or icon change depending on the UI.
To elaborate on a comment made by Kevin D - it really depends on your expected user audience. If they are technically proficient you can use the exception text as is. If not then I would prefix the message with "An error has occurred, please contact your technical support personnel with the following information: " then append the error message and ideally a unique identifier for locating an associated log entry... I often use a timestamp for this.
If you really want to get fancy you can email the tech support people with much more detail like the exception and full stack trace, copy of log entry, etc. I have done this in the past but you have to be careful as a frequently occurring error will quickly flood an inbox :)
Of course if the error can be fixed by the user then you can just say so (and how to do so) in your message. That is about as thorough and fancy as you can get...
I don't quite understand the first part of your question, but I try to answer the second one. In general, how you want to display an error to the user depends of the software and error. In most cases JOptionPane or similar is appropriate. However, in some cases a modal dialog might be too intrusive and status bar might be a better way to go. But again, this depends on what kind of software you're writing.
If you anticipate an exception could occur as a result of a user action, then you should explicitly catch it at the point that makes sense and ensure your program recovers correctly.
For example if the user can rename a file, you might invoke a rename() method which returns a status code to indicate success or a failure error code. Inside the method one of these codes might actually be triggered by an exception but the calling code doesn't care. Once the call returns, the status code can be used to determine which error message to show (if any).
enum RenameStatus {
Success,
Failed,
SecurityFailed
}
void doRename(File fromFile, File toFile) {
switch (rename(fromFile, toFile)) {
case Success:
break;
case Failed:
// todo generic dialog rename operation failed
break;
case SecurityFailed:
// todo security dialog rename operation failed due to permission
break;
}
}
RenameStatus rename(File fromFile, File toFile) {
try {
if (!fromFile.renameTo(toFile)) {
return RenameStatus.Failed;
}
return RenameStatus.Success;
}
catch (SecurityException e) {
// Error - permission error
return RenameStatus.SecurityFailed;
}
catch (Exception e) {
return RenameStatus.Failed;
}
}
If you catch the expression (enclosed in a try - catch - block) you get notified when this exception occurs. Then you have to decide: Is there a way to make things work again? Could you, for example, ask the user for another file name? Then do that! But if there is no sensible way of circumventing the error, then just have the program abort.
File permission is kind of a "normal" exception, not a truly "exceptional" one as "disk full" would be, so you'd probably just use JOptionPane instead of sending an error report. That being said, some earlier answers are very informative and should be adopted for the general cases.
In addition, my main() always start with this:
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler()
{
public void uncaughtException(Thread t, Throwable e)
{
// do your things: see earlier answers
}
}
Use Try-Catch handling...
http://tutorials.jenkov.com/java-exception-handling/basic-try-catch-finally.html
When you catch the exception you can do whatever you want with it. Display it to the user, do something else in the code, display another message to the user based on the exception, etc.