How to best treat exceptions in Java?

Asked

Viewed 3,305 times

35

Who has created great programs in Java knows of a very common headache: Do not know where to play the flow of Exceptions. Many decide to do things like:

Treat everything as Exception (the superclass of any Exception) and when a come, give any message to the user and play the Stacktrace in a log file.

Treat everything as Exception, but this time, since the program is really very large and the customer is probably not looking at the console, print the Stacktrace and continue as normal.

Warn the user that an error has occurred and give a generic treatment.

Among others.

Despite what I said above being very present in the professional environment these above approaches sound very much "POG".

If these exceptions have been made, something has gone wrong! But the problem is that in a simple operation so many things can happen, it’s really tedious to take care of everything. In addition, most of the possible "errors" are extremely unlikely.

What’s more, the Java error mechanism is not accurate at all: A Ioexception was launched? Yes, but in reality there are so many subclasses that it is difficult to know what to do: Filenotfoundexception, Eofexception, etc... if a Ioexception was launched, as properly treat the error without any specification of what precisely happened?

Within all this, I ask: What is the most efficient and elegant way to treat Exceptions in Java?

  • 3

    Much of what you mentioned is currently solved with GHP (go Horse process) or XGH (Extreme go Horse), very suitable for PHP and Java. Although PHP itself is developed with POG principles, which is different from GHP.

  • 1

    +1 for the POG :D link only

2 answers

25


References

I have talked a lot about it. Even though I am not specific about Java the essence holds for it. See in:

Evidently I remember more than I answered but there are cases of others posts very interesting in the same questions or others. It is easy to find on the site.

Importance of the subject

And the subject matter is important because programmers really don’t know how to use it properly. What shows what I say dealing with exceptions is not trivial. I have learned a lot about them by writing these posts. The danger is who thinks he knows everything about the subject and no longer needs to learn anything.

Exceptions are usually defended because, unlike error codes, they require the programmer to treat them. But they do not require proper treatment. So we see so many catch (Exception e). The programmer who doesn’t want to do something won’t do it. Capturing a Exception should be prohibited in the normal flow of a programme (in Main() or near it, it may be ok to give the last action before the application break).

Capturing very general exceptions hides programming errors. When the programmer tries to capture something that he does not know well why and what can come he ends up capturing what he should not, ends up dealing with something that should not be treated or that should be treated differently. The program should capture the most specialized exception possible that can do something useful.

Taking your example:

If you are working with file access and need to do something when you give whichever problem in trying to manipulate the files, no matter if the file does not exist, if it has reached its end unexpectedly or there is no access permission, there is a single action that must be done, what is the most specialized exception needed? Probably the IOException. But what if you need to present an error message on the screen when the file does not exist or have to do a specific task when the end of the file is reached unexpectedly? Here the more specialized exceptions need to be captured before and possibly the IOException then to other IO problems more generally.

Widespread X Specialized Exception

The programmer and only him in the specific case will be able to know if he needs to choose a more specialized or a slightly less specialized exception. There is no cake recipe. Examples may even help but they are often interpreted as cake recipes and misuse perpetuates.

Treat everything as Exception (the superclass of any Exception) and when one comes, give any message to the user and play Stacktrace in a log file

This is no problem if it is done in the right place. Doing this in the core of the program is certainly not right. What you said there is "and then let it break". If the program captures a Exception has a huge chance to have caught a programming error. There is nothing else to do.

Treat everything as Excpetion, but this time since the program is really very large and the client is probably not looking at the console, print Stacktrace and continue normally.

Programmer looking for problems. Just have something worse, totally swallow the exception.

Warn the user that an error has occurred and give generic treatment.

If it is totally generic falls into the above problem.

Knowing what to solve the problem

But the problem is that in a simple operation so much can happen that it’s really tedious to take care of everything

The basic rule is not to capture an exception that you don’t know or can’t do something really useful, that solves the problem in some way. You can’t do it willingly, much less unwillingly. So you can’t use too generic exceptions to the situation. Programmers get bored because they try to capture too many exceptions, exceptions that should not be captured. Programmers have conditioned themselves to believe that capturing exceptions diminish bugs programs. Indiscriminately they tend to complicate the solution of bugs, they hide the bugs.

much of the possible "errors" are extremely unlikely

Unlikely because? Why shouldn’t they happen in production? If so, don’t treat them. If it’s an unexpected situation, but possible, although unlikely, then you have to deal with it, you have no choice to make a robust program.

What you can do is create utility classes centralizing these treatments. Even so as not to violate the DRY. After a while, you practically don’t need to do new treatments, just use your library. Of course, catches still need to be made in the right places.

If an Ioexception was launched, how to properly treat the error without any specification of what precisely happened?

It is a case of a somewhat more generic capture (only sufficient) and use of more specific information generally (presenting it or logging them, for example). It is not because the program captures a IOException that the information specific to FileNotFoundException are not available in the variable used in the capture. It is not a solution for everything, but serves well in some cases. If the action may be the same, but only the message needs to be specific, the capture should be made in this a little more generic.

it’s hard to know what to do

Either you are misinformed or you do not need to do anything with this specific exception.

Java has the debatable advantage of indicating in the API when an exception must be treated. Too bad not all programmers use the resource correctly, then consumers of an API end up suffering to deal with something they shouldn’t. This is another problem. In these cases, the only thing you can’t do is pretend to have nothing to do and simulate an action just to meet the API requirement (the throws).

When you know what to do with the exception it should usually be captured as close as possible to where it was launched. The treatment should be done very close to the error (of course the treatment may be delegated to utility classes).

Handling specific exceptions can be error as well. Capturing a NullReferenceException Why? To forcibly create an instance that could not be created before? The error is elsewhere. And there is still the risk of being capturing the same mistake right, but from the wrong place, unexpected. Exceptions can come from anywhere. In the background will be trying to use the exception to do something that should be part of the normal program flow.

  • Excellent response, but there are cases where the use of the exception is mandatory, as in the handling of files. What to do in such cases?

  • 2

    Treat. It came to talk about it in this final part. But there is a solution in the item "Taking your example:". It says that these cases should be treated as experientially as possible. And that in many cases this is just capturing the IOException. What to do, I think is not the intention of the question, but usually the programmer will try again a few times and/or present a message to the user possibly giving options to choose what to do. Is there any specific question I can supplement the answer?

  • 1

    I’m clear on that. Thank you

19

Note: I will focus specifically on Java and the good practices I know, because this reply from @Maniero (and others) already address very well the issue of exceptions in general.

I consider in the following topics a desktop or web system, but not a system batch ui-less.

Do not show technical errors to the user

It is not uncommon for a user to call support and spend 15 minutes to read IndexOutOfBoundsException or something like that.

Vida de Programador

For situations like this, a system should always have a general catch of exceptions, that is, a catch (Throwable) general for use as a last resort.

Note that this nay means that developers should delegate all exceptions to this "global" treatment, quite the contrary.

This is just a case of not letting something strange pop up for the user on the screen. It would be a case of the "unknown" or "unexpected" error type that requires an administrator intervention and log analysis.

Abuse of logs

A fairy dies every time a programmer leaves one catch emptiness:

try {
    //lógica
} catch (Exception e) {
    //nada aqui!!!
}

This makes finding a mistake harder than playing the Mega-Sena.

Always (repeat: always!) print the error stack, message and values relevant to a log file.

Example:

try {
    Date data = new SimpleDateFormat("dd/MM/yyyy").parse(dataStr);
} catch (ParseException e) {
    log.error("Data informada '" + dataStr + "' inválida! " + e.getLocalizedMessage(), e);
}

This way, even if the error goes unnoticed to the user, it will be easily traceable via log analysis.

Classify and process relevant errors

Don’t spend too much time trying to predict every conceivable kind of mistake.

What if the server hard drive crashes? What if the network crashes? What if the OS crashes?

Mistakes that are not part of your general business rule should not be dealt with.

It is logical that there are cases where you depend on an external resource and need to consider the possibility of something external to the system failing.

Imagine the situation where the system prints to a tax printer. It needs to warn if the printer is having problems, right? But the system is not responsible for diagnosing or fixing the device with problems. Limit yourself to a general treatment, such as the example:

There was an error in the printer and the code returned was 123, please contact the responsible technician or refer to the manual.

The relevant exceptional cases should be provided for in cases of use

A suitable requirements survey has been done for the system. If it was, the errors that the user should be informed will probably be defined in the use cases or in the activity diagrams.

Error handling should evolve with the system

To the extent that the system is being developed, tested and evaluated by the user will likely arise new possible exceptional cases.

Sometimes it’s worth adding more specific treatments to these cases.

For example, imagine that the system reads a file from a shared folder on the network. In the first implementation was made a generic treatment of IOException.

Each time an error occurs in reading the file, one should check if the network is working, if the folder is actually shared, if the server has not crashed, etc. However, after some tests it was noticed that it is common for the user to forget to put the file there, then you spend a lot of time checking where the problem is.

In such a case, it is worth starting to make specific treatments so that the user himself can take action. Here, a FileNotFoundException is of paramount importance.

Final considerations

Each system has its particularities regarding the treatment of exceptions, so we have to identify the relevant cases to deal with individually, leaving only the exceptions of the exceptions for a more generic treatment.

  • It was the necessary complement I was hoping for.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.