Exception handling is a crucial aspect of robust software development. In Object Pascal, exceptions provide a way to handle errors and other exceptional conditions in a controlled manner. This section will cover the basics of exception handling, how to use exceptions in object-oriented programming (OOP), and best practices for creating and managing exceptions in Delphi.

Key Concepts

  1. Exceptions: Special conditions that alter the normal flow of execution.
  2. Try...Except Block: A construct to handle exceptions.
  3. Try...Finally Block: Ensures that certain code runs regardless of whether an exception occurs.
  4. Raising Exceptions: Creating and throwing exceptions.
  5. Custom Exceptions: Defining your own exception classes.

Try...Except Block

The try...except block is used to handle exceptions. It allows you to catch and respond to exceptions that occur within the try block.

Syntax

try
  // Code that might raise an exception
except
  on E: ExceptionType do
    // Handle the exception
end;

Example

procedure DivideNumbers(A, B: Integer);
begin
  try
    WriteLn('Result: ', A div B);
  except
    on E: EDivByZero do
      WriteLn('Error: Division by zero is not allowed.');
  end;
end;

begin
  DivideNumbers(10, 0);
end.

In this example, if B is zero, an EDivByZero exception is raised, and the message "Error: Division by zero is not allowed." is displayed.

Try...Finally Block

The try...finally block ensures that the code in the finally section is executed regardless of whether an exception occurs.

Syntax

try
  // Code that might raise an exception
finally
  // Code that will always execute
end;

Example

procedure OpenFile;
var
  FileHandle: TextFile;
begin
  AssignFile(FileHandle, 'example.txt');
  try
    Reset(FileHandle);
    // Perform file operations
  finally
    CloseFile(FileHandle);
  end;
end;

In this example, the file is guaranteed to be closed whether an exception occurs during file operations or not.

Raising Exceptions

You can raise exceptions using the raise keyword. This is useful for signaling error conditions explicitly.

Syntax

raise ExceptionType.Create('Error message');

Example

procedure CheckAge(Age: Integer);
begin
  if Age < 18 then
    raise Exception.Create('Age must be 18 or older.');
end;

begin
  try
    CheckAge(16);
  except
    on E: Exception do
      WriteLn('Exception: ', E.Message);
  end;
end.

In this example, an exception is raised if the age is less than 18, and the message "Exception: Age must be 18 or older." is displayed.

Custom Exceptions

Creating custom exception classes allows you to handle specific error conditions more precisely.

Syntax

type
  ECustomException = class(Exception)
  end;

Example

type
  EInvalidInput = class(Exception)
  end;

procedure ValidateInput(Input: Integer);
begin
  if Input < 0 then
    raise EInvalidInput.Create('Input must be non-negative.');
end;

begin
  try
    ValidateInput(-1);
  except
    on E: EInvalidInput do
      WriteLn('Invalid input: ', E.Message);
  end;
end.

In this example, a custom exception EInvalidInput is defined and used to signal invalid input conditions.

Best Practices

  1. Use Specific Exceptions: Catch specific exceptions rather than the generic Exception class to handle different error conditions appropriately.
  2. Clean Up Resources: Always release resources (e.g., files, memory) in a finally block to avoid resource leaks.
  3. Provide Meaningful Messages: Include clear and informative messages when raising exceptions to aid in debugging.
  4. Avoid Overusing Exceptions: Use exceptions for exceptional conditions, not for regular control flow.

Practical Exercise

Exercise

Create a Delphi application that reads an integer from the user and checks if it is a prime number. If the input is not a valid integer, raise a custom exception. If the number is not prime, raise another custom exception.

Solution

type
  EInvalidNumber = class(Exception)
  end;

  ENotPrime = class(Exception)
  end;

function IsPrime(Number: Integer): Boolean;
var
  I: Integer;
begin
  if Number <= 1 then
    Exit(False);
  for I := 2 to Trunc(Sqrt(Number)) do
    if Number mod I = 0 then
      Exit(False);
  Result := True;
end;

procedure CheckPrime(Input: string);
var
  Number: Integer;
begin
  if not TryStrToInt(Input, Number) then
    raise EInvalidNumber.Create('Input is not a valid integer.');

  if not IsPrime(Number) then
    raise ENotPrime.Create('The number is not prime.');
end;

begin
  try
    CheckPrime('15');
  except
    on E: EInvalidNumber do
      WriteLn('Error: ', E.Message);
    on E: ENotPrime do
      WriteLn('Error: ', E.Message);
  end;
end.

In this solution, two custom exceptions EInvalidNumber and ENotPrime are defined. The CheckPrime procedure checks if the input is a valid integer and if it is a prime number, raising appropriate exceptions for invalid input and non-prime numbers.

Conclusion

Exception handling is a powerful feature in Delphi/Object Pascal that helps you manage errors and exceptional conditions gracefully. By using try...except and try...finally blocks, raising exceptions, and creating custom exceptions, you can write more robust and maintainable code. Remember to follow best practices to ensure your exception handling is effective and efficient.

Delphi/Object Pascal Programming Course

Module 1: Introduction to Delphi/Object Pascal

Module 2: Control Structures and Procedures

Module 3: Working with Data

Module 4: Object-Oriented Programming

Module 5: Advanced Delphi Features

Module 6: GUI Development with VCL and FMX

Module 7: Web and Mobile Development

Module 8: Best Practices and Design Patterns

Module 9: Final Project

© Copyright 2024. All rights reserved