Error Handling in Programming
Last Updated :
21 Apr, 2024
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 ProgrammingWhat 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:
Block | Purpose | Execution Flow |
---|
try | Encloses the code where an exception might occur. | Code inside the try block is executed. |
---|
catch /except | Catches and handles exceptions raised in the try block. | If an exception occurs in the try block, the corresponding catch /except block is executed. |
---|
finally | Contains 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;
}
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
}
}
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.
Similar Reads
Basics & Prerequisites
Data Structures
Array Data StructureIn this article, we introduce array, implementation in different popular languages, its basic operations and commonly seen problems / interview questions. An array stores items (in case of C/C++ and Java Primitive Arrays) or their references (in case of Python, JS, Java Non-Primitive) at contiguous
3 min read
String in Data StructureA string is a sequence of characters. The following facts make string an interesting data structure.Small set of elements. Unlike normal array, strings typically have smaller set of items. For example, lowercase English alphabet has only 26 characters. ASCII has only 256 characters.Strings are immut
2 min read
Hashing in Data StructureHashing is a technique used in data structures that efficiently stores and retrieves data in a way that allows for quick access. Hashing involves mapping data to a specific index in a hash table (an array of items) using a hash function. It enables fast retrieval of information based on its key. The
2 min read
Linked List Data StructureA linked list is a fundamental data structure in computer science. It mainly allows efficient insertion and deletion operations compared to arrays. Like arrays, it is also used to implement other data structures like stack, queue and deque. Hereâs the comparison of Linked List vs Arrays Linked List:
2 min read
Stack Data StructureA Stack is a linear data structure that follows a particular order in which the operations are performed. The order may be LIFO(Last In First Out) or FILO(First In Last Out). LIFO implies that the element that is inserted last, comes out first and FILO implies that the element that is inserted first
2 min read
Queue Data StructureA Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific order. It follows the principle of "First in, First out" (FIFO), where the first element added to the queue is the first one to be removed. It is used as a buffer in computer systems
2 min read
Tree Data StructureTree Data Structure is a non-linear data structure in which a collection of elements known as nodes are connected to each other via edges such that there exists exactly one path between any two nodes. Types of TreeBinary Tree : Every node has at most two childrenTernary Tree : Every node has at most
4 min read
Graph Data StructureGraph Data Structure is a collection of nodes connected by edges. It's used to represent relationships between different entities. If you are looking for topic-wise list of problems on different topics like DFS, BFS, Topological Sort, Shortest Path, etc., please refer to Graph Algorithms. Basics of
3 min read
Trie Data StructureThe Trie data structure is a tree-like structure used for storing a dynamic set of strings. It allows for efficient retrieval and storage of keys, making it highly effective in handling large datasets. Trie supports operations such as insertion, search, deletion of keys, and prefix searches. In this
15+ min read
Algorithms
Searching AlgorithmsSearching algorithms are essential tools in computer science used to locate specific items within a collection of data. In this tutorial, we are mainly going to focus upon searching in an array. When we search an item in an array, there are two most common algorithms used based on the type of input
2 min read
Sorting AlgorithmsA Sorting Algorithm is used to rearrange a given array or list of elements in an order. For example, a given array [10, 20, 5, 2] becomes [2, 5, 10, 20] after sorting in increasing order and becomes [20, 10, 5, 2] after sorting in decreasing order. There exist different sorting algorithms for differ
3 min read
Introduction to RecursionThe process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. A recursive algorithm takes one step toward solution and then recursively call itself to further move. The algorithm stops once we reach the solution
14 min read
Greedy AlgorithmsGreedy algorithms are a class of algorithms that make locally optimal choices at each step with the hope of finding a global optimum solution. At every step of the algorithm, we make a choice that looks the best at the moment. To make the choice, we sometimes sort the array so that we can always get
3 min read
Graph AlgorithmsGraph is a non-linear data structure like tree data structure. The limitation of tree is, it can only represent hierarchical data. For situations where nodes or vertices are randomly connected with each other other, we use Graph. Example situations where we use graph data structure are, a social net
3 min read
Dynamic Programming or DPDynamic Programming is an algorithmic technique with the following properties.It is mainly an optimization over plain recursion. Wherever we see a recursive solution that has repeated calls for the same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the results of
3 min read
Bitwise AlgorithmsBitwise algorithms in Data Structures and Algorithms (DSA) involve manipulating individual bits of binary representations of numbers to perform operations efficiently. These algorithms utilize bitwise operators like AND, OR, XOR, NOT, Left Shift, and Right Shift.BasicsIntroduction to Bitwise Algorit
4 min read
Advanced
Segment TreeSegment Tree is a data structure that allows efficient querying and updating of intervals or segments of an array. It is particularly useful for problems involving range queries, such as finding the sum, minimum, maximum, or any other operation over a specific range of elements in an array. The tree
3 min read
Pattern SearchingPattern searching algorithms are essential tools in computer science and data processing. These algorithms are designed to efficiently find a particular pattern within a larger set of data. Patten SearchingImportant Pattern Searching Algorithms:Naive String Matching : A Simple Algorithm that works i
2 min read
GeometryGeometry is a branch of mathematics that studies the properties, measurements, and relationships of points, lines, angles, surfaces, and solids. From basic lines and angles to complex structures, it helps us understand the world around us.Geometry for Students and BeginnersThis section covers key br
2 min read
Interview Preparation
Practice Problem