In programming, exception handling is a process or method used for handling the abnormal statements in the code and executing them. It also enables to handle the flow control of the code/program. For handling the code, various handlers are used that process the exception and execute the code.
Types of Errors
- Syntax Error: When a user makes a mistake in the pre-defined syntax of a programming language, a syntax error may appear.
- Runtime Error: When an error occurs during the execution of the program, such an error is known as Runtime error. The codes which create runtime errors are known as Exceptions. Thus, exception handlers are used for handling runtime errors.
- Logical Error: An error which occurs when there is any logical mistake in the program that may not produce the desired output, and may terminate abnormally. Such an error is known as Logical error.
Error Object
An error object has two properties:
- name: This is an object property that sets or returns an error name.
- message: This property returns an error message in the string form.
Although Error is a generic constructor, there are following standard built-in error types or error constructors beside it:
- EvalError: It creates an instance for the error that occurred in the eval(), which is a global function used for evaluating the js string code.
- InternalError: It creates an instance when the js engine throws an internal error.
- RangeError: It creates an instance for the error that occurs when a numeric variable or parameter is out of its valid range.
- ReferenceError: It creates an instance for the error that occurs when an invalid reference is de-referenced.
- SyntaxError: An instance is created for the syntax error that may occur while parsing the eval().
- TypeError: When a variable is not a valid type, an instance is created for such an error.
- URIError: An instance is created for the error that occurs when invalid parameters are passed in encodeURI() or decodeURI().
Exception Handling statements
Throw statement
Throw statements are used for throwing user-defined errors. User can define and throw their own custom errors. When throw statement is executed, the statements present after it will not execute. The control will directly pass to the catch block.
Syntax:
- expression – The expression to throw.
Ex:
Throwing a user-defined error:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function isNumeric(x) { return ["number", "bigint"].includes(typeof x); } function sum(...values) { if (!values.every(isNumeric)) { throw new TypeError("Can only add numbers"); } return values.reduce((a, b) => a + b); } console.log(sum(1, 2, 3)); // 6 try { sum("1", "2"); } catch (e) { console.error(e); // TypeError: Can only add numbers } |
Throwing an existing object:
1 2 3 4 5 6 | readFile("foo.txt", (err, data) => { if (err) { throw err; } console.log(data); }); |
try … catch statement
The try...catch
statement is comprised of a try
block and either a catch
block, a finally
block, or both. The code in the try
block is executed first, and if it throws an exception, the code in the catch
block will be executed. The code in the finally
block will always be executed before control flow exits the entire construct.
Syntax:
tryStatements
} catch ( exceptionVar ) {
catchStatements
} finally {
finallyStatements
}
- tryStatements – The statements to be executed.
- catchStatements – Statement that is executed if an exception is thrown in the
try
block. - exceptionVar – An optional identifier or pattern to hold the caught exception for the associated
catch
block. If thecatch
block does not use the exception’s value, you can omit theexceptionVar
and its surrounding parentheses. - finallyStatements – Statements that are executed before control flow exits the
try...catch...finally
construct. These statements execute regardless of whether an exception was thrown or caught.
Ex:
Unconditional catch block:
1 2 3 4 5 6 | try { throw "myException"; // generates an exception } catch (e) { // statements to handle any exceptions logMyErrors(e); // pass exception object to error handler } |
Conditional catch blocks:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | try { myroutine(); // may throw three types of exceptions } catch (e) { if (e instanceof TypeError) { // statements to handle TypeError exceptions } else if (e instanceof RangeError) { // statements to handle RangeError exceptions } else if (e instanceof EvalError) { // statements to handle EvalError exceptions } else { // statements to handle any unspecified exceptions logMyErrors(e); // pass exception object to error handler } } |
Nested try blocks:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | try { try { throw new Error("oops"); } catch (ex) { console.error("inner", ex.message); throw ex; } finally { console.log("finally"); } } catch (ex) { console.error("outer", ex.message); } // Logs: // "inner" "oops" // "finally" // "outer" "oops" |
Returning from a finally block:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | (() => { try { try { throw new Error("oops"); } catch (ex) { console.error("inner", ex.message); throw ex; } finally { console.log("finally"); return; } } catch (ex) { console.error("outer", ex.message); } })(); // Logs: // "inner" "oops" // "finally" |