Exceptions allow you to make the code cleaner and clearer, since they can be used to separate the execution of actions and error handling. In Martin’s Pure Code book, this aspect is described first.
At the same time, in my experience, it is necessary to separate the code: carry out the try
/ catch
in a separate method. The programmer who will deal with your program will say thank you. This construction is quite cumbersome, even in the simple form of try
/ finally
, and in the middle of a large method will puzzle anyone.
The second plus of exceptions is that they allow the transfer of additional information. The atoi
function from C could not say anything about why it was not possible to convert the string to an integer.
int result; result = atoi("123"); /* в result 123 */ . . . result = atoi("foo"); /* что в result? */
In languages such as Java and C #, you can add necessary properties to your exception class, combining any error codes with call contexts and something else . Example:
. . . catch (SqlException e) { Console.WriteLine("Ошибка '{2}' в строке {0} процедуры {1}", e.LineNumber, e.Procedure, e.Message); } . . .
Developers who have long and firmly passed to the exceptions, make their code even cleaner, without returning any error codes, in particular, the notorious null :
// Что будет, если в хранилище нет пользователя с указанным userid? // Вернёт null или сгенерирует исключение? User user = userRepository.GetById(userId);
At present, it is considered that it is more correct to create an exception (referring again to the book “Clean Code” for arguments). If the method is used to check the presence of a user, it is recommended to convert it into a TryX
form. It is clumsy, but already familiar, at least for .NET programmers:
User user; if (userRepository.TryGetById(userId, out user)) { . . . }
What is more valuable, it is unequivocal: looking at the code, you do not think: “what if there is no such user?”
Now let's look at the situation from the other side - and when should we not use exceptions? In my opinion, when they make it difficult to understand the code. If the situation is not exceptional , then the program text should be a regular check.
For example, the application for the new document generates the names Untitled.foo , Untitled1.foo , Untitled2.foo , etc.
The situation that a file with the same name already exists is quite ordinary, not exceptional, therefore, it is more correct to implement the code using the usual check:
public string GetNewDocumentName(string prefix) { var filename = prefix + ".foo"; if (!File.Exists(filename)) return filename; int suffix = 0; do { filename = prefix + (++suffix).ToString() + ".foo"; } while (File.Exists(filename)); return filename; }
This code is not only faster than similar code with the use of exceptions, but more importantly, it is more understandable to other programmers, because it implicitly conveys additional information to them: this thing will happen regularly, and we are ready for it.
And here, for example, is an incredible situation that 2 billion untitled files have accumulated in the folder - an undoubted exception.
public string GetNewDocumentName(string prefix) { var filename = prefix + ".foo"; if (!File.Exists(filename)) return filename; int suffix = 0; do { if (suffix == int.MaxValue) throw new InvalidOperationException("You're crazy!"); filename = prefix + (++suffix).ToString() + ".foo"; } while (File.Exists(filename)); return filename; }
This code looks more confusing. Fortunately, we can put some of the checks on the C # compiler:
public string GetNewDocumentName(string prefix) { var filename = prefix + ".foo"; if (!File.Exists(filename)) return filename; int suffix = 0; do checked { filename = prefix + (suffix++).ToString() + ".foo"; } while (File.Exists(filename)); return filename; }
Whence another rule arises: the code can be made cleaner if one knows the language, platform, library, and relies on their exceptions.
I wrote above that exceptions are performed more slowly than checks, and I want to clarify my point: do not rely on performance when making decisions. The correct transfer of meaning to another programmer, the purity of the code is what you should strive for. The difference in performance, although it exists, has never been so great that users notice it. Well, if only you do not write the code for the most nested loop in any graphics engine.