Language: EN

gestion-excepciones-try-catch

Exception handling with Try Catch

Error handling is a fundamental part of software development that allows us to detect, handle, and correct unexpected or exceptional situations during program execution.

An error, also known as an EXCEPTION, is an abnormal or unexpected condition that interrupts the normal flow of a program’s execution.

Error handling is part of the flow control structures because they modify the normal program procedure. Whether intentionally or unintentionally.

The appearance of an EXCEPTION can occur for various reasons. For example,

  • Syntax error: That is, you have messed up in a part of the code
  • Accessing invalid memory: Such as an undeclared variable, or exceeding the length of a collection
  • Accessing an unavailable resource: Such as a file, a database, or a web request
  • Voluntarily thrown
  • Many other causes

Whatever the reason, the important thing is that an error has occurred. Then the program throws a warning that an anomaly has occurred. This warning is generally called EXCEPTION.

try-catch

Your functions dealing with the bomb 💣

When an exception occurs, two things can happen,

  • You can catch it, and try to contain the error
  • If you don’t catch it, it will propagate to the function that called the current function

If the exception continues “climbing” through calls until it reaches the main function, an error will be thrown at the user. In this case, it is normal for the program to crash and stop working, or even to close abruptly.

error-message-exception

Example of error message 💥

Exception Throwing and Catching

In most programming languages, exceptions are thrown when an error occurs using the throw statement.

throw new Exception("This is a manually thrown exception!");

These exceptions can be caught and handled by other parts of the code using try-catch or try-catch-finally blocks.

try
{
    // Code that can throw an exception 💣
}
catch (Exception ex)
{
    // Exception handling, will only jump if an error occurs 💥
}
finally
{
	// Optional final block, always executed, whether an error occurs 💥 or not 👍
}
  • Try Block: The try block contains the code to be executed and that could throw an exception. This code is executed normally, but if an exception occurs within the try block, program control is immediately transferred to the catch block, bypassing any remaining code in the try block.
  • Catch Block: The catch block is executed only if an exception occurs within the try block. It specifies how to handle the exception, such as displaying an error message, logging the exception, or performing recovery actions.
  • Finally Block (optional): The finally block is always executed, whether an exception occurs in the try block or not. It is used to specify code that should be executed after the execution of the try block, regardless of whether an exception occurs. This is useful for resource cleanup, such as closing files or database connections, that must be performed regardless of whether an error occurs.

Example of Exceptions in different languages

Let’s see how to use a try-catch block to catch exceptions and handle them in a controlled manner in different languages, and how to manually throw an Exception with throw (or similar).

For the example, we are going to simply divide by zero, which is a not allowed operation that generates an error. It is a very simple way to force the exception to be thrown for the example.

In C#, Exceptions are used with the Exception object. They are caught with a try-catch-finally block.

// Example in C#
try
{
    // Code that can throw an exception
    int result = 10 / 0; // Division by zero 💥
}
catch (Exception ex)
{
    // Exception handling
    Console.WriteLine("Error: " + ex.Message);
}

While throwing an exception manually would be done like this.

throw new Exception("This is a manually thrown exception!");

In C++, the creation of a try-catch block is identical. In this case, Exceptions are part of the std namespace.

// Example in C++
try
{
    // Code that can throw an exception
    int result = 10 / 0; // Division by zero 💥
}
catch (const std::exception& ex)
{
    // Exception handling
    std::cout << "Error: " << ex.what() << std::endl;
}

While manually throwing an Exception would be done like this.

throw std::runtime_error("This is a manually thrown exception!");

In JavaScript, it also uses the same try-catch syntax for error handling.

// Example in JavaScript
try {
    // Code that can throw an exception
    let result = 10 / 0; // Division by zero 💥
} catch (error) {
    // Exception handling
    console.log("Error: " + error.message);
}

Manually throwing Exceptions is also similar. In this case, the Exception is called Error.

 throw new Error("This is a manually thrown exception!");

Finally, in Python, as always it has its own syntax, and does the block with try-except

# Example in Python
try:
    # Code that can throw an exception
    result = 10 / 0  # Division by zero 💥
except ZeroDivisionError as ex:
    # Exception handling
    print("Error:", ex)

While manually throwing an Exception is done with raise.

 raise Exception("This is a manually thrown exception!")

As usual, apart from the small syntax differences, most programming languages include Exception handling, with more similarities than differences.

Tips on using Exceptions Tips

You should not abuse the use of the try-catch block. Its use should be limited to truly exceptional or unforeseeable situations, and not as a mechanism to control the normal program flow.

If it is foreseeable that an error will occur in a process, you should check the possible causes of the errors beforehand. The try-catch block should only be used for things that we cannot check.

For example, imagine you want to access a file. Reading a file is a process that is always susceptible to generating Exceptions, because it is a resource of the operating system that we do not control.

try
{
	string content = File.ReadAllText(file);
	Console.WriteLine("File content: " + content);
}
catch (Exception ex)
{
	Console.WriteLine("Error reading the file: " + ex.Message);
}

One possible cause is that the file does not exist. That is not an Exception, it is a clear, evident, and known reason why we cannot read it. Therefore, it is best to check this beforehand.

if (File.Exists(file))
{
	try
	{
		string content = File.ReadAllText(file);
		Console.WriteLine("File content: " + content);
	}
	catch (Exception ex)
	{
		Console.WriteLine("Error reading the file: " + ex.Message);
	}
}
else
{
	Console.WriteLine("The file does not exist.");
}

We only leave the try-catch for reading the file. Which can give an error, even if the file exists. This is already an unpredictable or unforeseeable situation, and this is where it makes sense to wrap it in a try-catch.

This is so, first of all, for cleanliness. But, on the other hand, because the try-catch has a significant impact on the program’s performance. So we should only use it for what it is, management of unforeseen errors, and not for everything.