Open In App

Error Handling in Programming

Last Updated : 21 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In Programming, errors occur. Our code needs to be prepared for situations when unexpected input from users occurs, division by zero occurs, or a variable name is written incorrectly. To prevent unexpected events from crashing or having unexpected outcomes, error handling involves putting in place methods to identify, report, and manage problems.

Error Handling in Programming

Error Handling in Programming

What is Error Handling in Programming?

Error handling in Programming is a fundamental aspect of programming that addresses the inevitable challenges associated with unexpected issues during code execution. These issues may range from simple typographical errors to more intricate runtime errors that manifest during the program’s operation. The effectiveness of error handling is crucial in the development of software that is not only functional but also resilient and dependable.

Try, Catch/ Except and Finally Blocks:

Within the domain of programming languages, error handling commonly incorporates constructs such as ‘try’, ‘catch’ (or ‘except’), and ‘finally’ blocks. The ‘try’ block encapsulates the code where an error might occur, while the ‘catch’ (or ‘except’) block is responsible for capturing and handling the error. The optional ‘finally’ block ensures the execution of specific code, irrespective of whether an error occurs or not.

This arrangement allows programmers to adeptly navigate through errors, averting potential catastrophic crashes.

Example: (Zero Division Error)

C++
#include <iostream>
#include <stdexcept>
using namespace std;

int main() {
    int divisor = 0;

    try {
        // Code that might raise an error
        if (divisor == 0) {
            // This will throw a std::runtime_error
            throw runtime_error("Error: Division by zero");
        } else {
            // Code to be executed if no error occurs
            int result = 10 / divisor;
            cout << "Result: " << result << endl;
        }
    } catch (const std::runtime_error& e) {
        // Handle the error
        cerr << e.what() << endl;
    } catch (...) {
        // Handle other types of exceptions if needed
    }

    // Code to be executed regardless of whether an error occurred
    cout << "Finally block executed" << endl;

    return 0;
}
C
#include <stdio.h>

int main()
{
    int divisor = 0;

    // Code that might raise an error
    if (divisor == 0) {
        // Handle the error
        fprintf(stderr, "Division by zero!");
        exit(-1);
    }
    else {
        // Code to be executed if no error occurs
        int result = 10 / divisor;
        printf("Result: %d\n", result);
    }

    // Code to be executed regardless of whether an error
    // occurred
    printf("Finally block executed\n");
    exit(0);

    return 0;
}
Java
public class Main {
    public static void main(String[] args)
    {
        int divisor = 0;

        try {
            // Code that might raise an error
            if (divisor == 0) {
                // This will throw an ArithmeticException
                throw new ArithmeticException(
                    "Error: Division by zero");
            }
            else {
                // Code to be executed if no error occurs
                int result = 10 / divisor;
                System.out.println("Result: " + result);
            }
        }
        catch (ArithmeticException e) {
            // Handle the error
            System.err.println(e.getMessage());
        }
        catch (Exception e) {
            // Handle other types of exceptions if needed
        }
        finally {
            // Code to be executed regardless of whether an
            // error occurred
            System.out.println("Finally block executed");
        }
    }
}
Python
divisor = 0

try:
    # Code that might raise an error
    if divisor == 0:
        # This will raise a RuntimeError
        raise RuntimeError("Error: Division by zero")
    else:
        # Code to be executed if no error occurs
        result = 10 / divisor
        print("Result:", result)
except RuntimeError as e:
    # Handle the error
    print(str(e))
except:
    # Handle other types of exceptions if needed
    pass

# Code to be executed regardless of whether an error occurred
print("Finally block executed")
C#
using System;

class Program {
    static void Main(string[] args)
    {
        int divisor = 0;

        try {
            // Code that might raise an error
            if (divisor == 0) {
                // This will throw an exception
                throw new DivideByZeroException(
                    "Error: Division by zero");
            }
            else {
                // Code to be executed if no error occurs
                int result = 10 / divisor;
                Console.WriteLine("Result: " + result);
            }
        }
        catch (DivideByZeroException e) {
            // Handle the error
            Console.WriteLine(e.Message);
        }
        catch (Exception) {
            // Handle other types of exceptions if needed
        }

        // Code to be executed regardless of whether an
        // error occurred
        Console.WriteLine("Finally block executed");
    }
}
JavaScript
function main() {
    let divisor = 0;

    try {
        // Code that might raise an error
        if (divisor === 0) {
            // This will throw an Error object
            throw new Error("Error: Division by zero");
        } else {
            // Code to be executed if no error occurs
            let result = 10 / divisor;
            console.log("Result: " + result);
        }
    } catch (error) {
        // Handle the error
        console.error(error.message);
    } finally {
        // Code to be executed regardless of whether an error occurred
        console.log("Finally block executed");
    }
}

main();

Comparison Between Try, Catch/ Except and Finally Blocks:

BlockPurposeExecution Flow
tryEncloses the code where an exception might occur.Code inside the try block is executed.
catch/exceptCatches and handles exceptions raised in the try block.If an exception occurs in the try block, the corresponding catch/except block is executed.
finallyContains code that will be executed regardless of whether an exception occurred or not.Executed after the try block, whether an exception occurred or not.

Common Errors and Debugging:

Understanding common errors is essential for proficient error handling. Syntax errors emerge during the compilation phase and are relatively easy to identify. In contrast, runtime errors manifest during program execution and can involve a wide range of issues, such as division by zero, file not found, or invalid input.

Debugging is the process of identifying and rectifying errors. Some tried-and-true debugging techniques include:

  • Print Statements: Placing print statements in the code strategically helps in tracing the program’s execution and identifying errors more effectively.
  • Logging: Using logging libraries captures important details about how the program is running, making it easier to trace errors.
  • Code Reviews: Having someone else review your code can reveal possible problems that might cause errors.

Lets see some common errors and how are they handled:

1. Handling File Not Found Error:

C++
//Handling File Not Found Error:

#include <iostream>
#include <fstream>
using namespace std;

int main() {
    try {
        ifstream file("nonexistent_file.txt");
        if (!file.is_open()) {
            throw ios_base::failure("FileNotFoundError");
        }
        // Rest of the code
    } catch (const ios_base::failure& file_error) {
        cerr << file_error.what() << endl;
    }
    return 0;
}
C
//Handling File Not Found Error:

#include <stdio.h>

int main() {
    FILE *file = fopen("nonexistent_file.txt", "r");
    if (file == NULL) {
        perror("FileNotFoundError");
    }
    // Rest of the code
    return 0;
}
Java
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        File file = new File("nonexistent_file.txt");
        try {
            Scanner scanner = new Scanner(file);
            // Rest of the code
            scanner.close();
        } catch (FileNotFoundException e) {
            System.err.println("FileNotFoundError: " + e.getMessage());
        }
    }
}
Python
#Handling File Not Found Error:

try:
    with open("nonexistent_file.txt", "r") as file:
        content = file.read()
except FileNotFoundError as file_error:
    print(f"FileNotFoundError: {file_error}")
C#
using System;
using System.IO;

class Program
{
    static void Main()
    {
        try
        {
            // Open the file for reading
            using (StreamReader file = new StreamReader("nonexistent_file.txt"))
            {
                // If the file is opened successfully, read its contents
                Console.WriteLine(file.ReadToEnd());
            }
        }
        catch (FileNotFoundException)
        {
            // Handle the FileNotFoundException
            Console.WriteLine("FileNotFoundError: File not found.");
        }
        catch (IOException e)
        {
            // Handle other IO exceptions
            Console.WriteLine($"IOException: {e.Message}");
        }
        catch (Exception e)
        {
            // Handle other exceptions
            Console.WriteLine($"An error occurred: {e.Message}");
        }
    }
}
JavaScript
const fs = require('fs');

// Main function
function main() {
    const filePath = 'nonexistent_file.txt';

    // Attempt to read the file
    fs.readFile(filePath, 'utf8', (err, data) => {
        // If an error occurs, handle it
        if (err) {
            // Check if the error is due to file not found
            if (err.code === 'ENOENT') {
                console.error(`FileNotFoundError: ${err.message}`);
            } else {
                // Print other errors
                console.error(`Error: ${err.message}`);
            }
            return;
        }

        // If file is read successfully, do something with the data
        console.log(data);
    });
}

// Call the main function
main();

2. Handling Invalid Input Error:

C++
// Handling Invalid Input Error:

#include <iostream>
#include <sstream>
using namespace std;

int main()
{
    string user_input;
    cout << "Enter a number: ";
    getline(std::cin, user_input);
    int value;
    istringstream input_stream(user_input);
    if (!(input_stream >> value)) {
        cerr << "InvalidInputError" << endl;
    }
    // Rest of the code
    return 0;
}
C
// Handling Invalid Input Error:
#include <stdio.h>

int main() {
    char user_input[256];
    printf("Enter a number: ");
    fgets(user_input, sizeof(user_input), stdin);

    int value;
    if (sscanf(user_input, "%d", &value) != 1) {
        fprintf(stderr, "InvalidInputError\n");
    }
    // Rest of the code
    return 0;
}
Java
/* Handling Invalid Input Error */
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        try {
            System.out.print("Enter a number: ");
            String userInput = scanner.nextLine();

            int value;
            try {
                value = Integer.parseInt(userInput);
                // Rest of the code
            } catch (NumberFormatException e) {
                System.err.println("InvalidInputError");
            }
        } catch (Exception e) {
            System.err.println("Error reading input: " + e.getMessage());
        } finally {
            scanner.close(); // Close the scanner to prevent resource leaks
        }
    }
}
Python
# Handling Invalid Input Error:

user_input = input("Enter a number: ")
try:
    value = int(user_input)
except ValueError:
    print("InvalidInputError")
JavaScript
const readline = require('readline');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

rl.question('Enter a number: ', (userInput) => {
  try {
    const value = parseInt(userInput);
    if (isNaN(value)) {
      console.error('InvalidInputError');
    } else {
      // Rest of the code
    }
  } catch (error) {
    console.error('InvalidInputError');
  } finally {
    rl.close(); // Close the readline interface to prevent resource leaks
  }
});

3. Assertion Error:

C++
#include <cassert>
#include <iostream>
using namespace std;

int main() {
    int value = -5;

    // Use assert to check a condition
    assert(value > 0 && "Value must be greater than 0");

    // Rest of the code
    return 0;
}
C
#include <assert.h>

int main() {
    int value = -5;

    // Use assert to check a condition
    assert(value > 0 && "Value must be greater than 0");

    // Rest of the code
    return 0;
}
Java
/* Assertion Error */

public class Main {
    public static void main(String[] args) {
        int value = -5;

        // Use assert to check a condition
        assert value > 0 : "Value must be greater than 0";

        // Rest of the code
        System.out.println("Program continues");
    }
}
Python
# Assertion Error
value = -5

# Use assert to check a condition
assert value > 0, "Value must be greater than 0"

# Rest of the code
print("Program continues")
JavaScript
// Custom assert function to check a condition
function assert(condition, message) {
    if (!condition) {
        throw new Error("AssertionError: " + message);
    }
}

// Main function
function main() {
    let value = -5;

    // Use assert to check a condition
    assert(value > 0, "Value must be greater than 0");

    // Rest of the code
    console.log("Program continues");
}

// Call the main function
main();

Debugging Techniques in Programming:

1. Breakpoints:

By setting breakpoints in the code, you can pause the program at specific points, check variables, and closely examine the program’s current state.

Using Breakpoints in python:

Python
import pdb

def example_function():
    # Code to be executed before breakpoint
    x = 5
    y = 10

    # Set a breakpoint
    pdb.set_trace()

    # Code to be executed after breakpoint
    result = x + y
    print("Result:", result)

# Call the function
example_function()

2. Step Through:

Examining the code line by line aids in identifying the precise location of an error.

Stepping Through Code in C:

C
#include <stdio.h>

int main() {
    // Sample variables
    int a = 5;
    int b = 10;
    int result;

    // Set a breakpoint by adding a dummy condition
    if (a == 0) {
        printf("Breakpoint\n");
    }

    // Code to be executed before breakpoint
    result = a + b;

    // Output the result
    printf("Result: %d\n", result);

    // Rest of the code

    return 0;
}

Output
Result: 15

3. Watch Variables:

Observing variable values while the program runs provides insights into any unexpected behavior.

Watching Variables in C++:

C++
#include <iostream>
using namespace std;

int main() {
    // Sample variables
    int a = 5;
    int b = 10;
    int result;

    // Set a breakpoint by adding a dummy condition
    if (a == 0) {
        cout << "Breakpoint" << endl;
    }

    // Code to be executed before breakpoint
    result = a + b;
    
    // Output the result
    cout << "Result: " << result << endl;

    // Rest of the code

    return 0;
}

Watching Variables in Java:

Java
public class Main {
    public static void main(String[] args) {
        // Sample variables
        int a = 5;
        int b = 10;
        int result;

        // Set a breakpoint by adding a dummy condition
        if (a == 0) {
            System.out.println("Breakpoint");
        }

        // Code to be executed before breakpoint
        result = a + b;

        // Output the result
        System.out.println("Result: " + result);

        // Rest of the code
    }
}



Output
Result: 15

Debugging Tools in Programming:

There are many tools available to help in debugging:

  • Integrated Development Environments (IDEs): IDEs frequently come with built-in debugging tools, offering a user-friendly interface for easy debugging.
  • Profilers: Profiling tools are essential for pinpointing performance bottlenecks and memory issues.
  • Linters: Linters examine code for potential errors and style issues, addressing problems early in the development phase.

Best Practices for Error Handling in Programming:

To enhance error handling, follow these best practices:

  • Specificity: Focus on identifying and handling various error types specifically to provide accurate feedback and responses.
  • Graceful Degradation: Design programs to handle errors gracefully, avoiding sudden crashes and ensuring a smoother user experience.
  • Logging: Incorporate comprehensive logging to document errors and relevant information for future analysis.

In conclusion, Error handling serves as a crucial element in programming, playing a pivotal role in guaranteeing software reliability and resilience. By acquainting yourself with common errors, using effective debugging techniques, utilizing tools, and embracing best practices, you can develop applications that not only perform well but also remain resilient in the face of unexpected challenges. Giving importance to error handling goes beyond enhancing user experience; it sets the foundation for easier maintenance and future development of software systems.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads