Создание исключений, throw

// 1. Создание собственного исключения
class InsufficientFundsException extends Exception {
    private double amount;

    public InsufficientFundsException(String message, double amount) {
        super(message);
        this.amount = amount;
    }

    public double getAmount() {
        return amount;
    }
}

// 2. Создание исключения времени выполнения
class InvalidAccountNumberException extends RuntimeException {
    public InvalidAccountNumberException(String message) {
        super(message);
    }
}

// 3. Пример использования исключений
class BankAccount {
    private String accountNumber;
    private double balance;

    public BankAccount(String accountNumber, double initialBalance) {
        if (accountNumber == null || accountNumber.length() != 10) {
            throw new InvalidAccountNumberException("Номер счета должен содержать 10 цифр");
        }
        this.accountNumber = accountNumber;
        this.balance = initialBalance;
    }

    public void withdraw(double amount) throws InsufficientFundsException {
        if (amount <= 0) {
            throw new IllegalArgumentException("Сумма снятия должна быть положительной");
        }

        if (amount > balance) {
            throw new InsufficientFundsException(
                "Недостаточно средств на счете. Требуется: " + amount + ", доступно: " + balance,
                amount - balance
            );
        }

        balance -= amount;
    }

    public void deposit(double amount) {
        if (amount <= 0) {
            throw new IllegalArgumentException("Сумма депозита должна быть положительной");
        }
        balance += amount;
    }

    public double getBalance() {
        return balance;
    }
}

// 4. Демонстрация работы с исключениями
public class ExceptionDemo {
    public static void main(String[] args) {
        try {
            // Создание счета с неверным номером
            System.out.println("=== Тест неверного номера счета ===");
            BankAccount invalidAccount = new BankAccount("123", 1000);
        } catch (InvalidAccountNumberException e) {
            System.out.println("Ошибка: " + e.getMessage());
        }

        // Работа с корректным счетом
        System.out.println("\n=== Тест операций со счетом ===");
        try {
            BankAccount account = new BankAccount("1234567890", 1000);

            // Тест успешного снятия
            System.out.println("Баланс до: " + account.getBalance());
            account.withdraw(500);
            System.out.println("Баланс после снятия 500: " + account.getBalance());

            // Тест снятия большей суммы
            try {
                account.withdraw(1000);
            } catch (InsufficientFundsException e) {
                System.out.println("Ошибка: " + e.getMessage());
                System.out.println("Не хватает: " + e.getAmount());
            }

            // Тест отрицательной суммы
            try {
                account.withdraw(-100);
            } catch (IllegalArgumentException e) {
                System.out.println("Ошибка: " + e.getMessage());
            }

        } catch (Exception e) {
            System.out.println("Непредвиденная ошибка: " + e.getMessage());
        }

        // 5. Пример цепочки исключений
        System.out.println("\n=== Тест цепочки исключений ===");
        try {
            methodA();
        } catch (Exception e) {
            System.out.println("Основное исключение: " + e.getMessage());
            Throwable cause = e.getCause();
            if (cause != null) {
                System.out.println("Причина: " + cause.getMessage());
            }
        }
    }

    public static void methodA() throws Exception {
        try {
            methodB();
        } catch (IllegalArgumentException e) {
            throw new Exception("Ошибка в methodA", e);
        }
    }

    public static void methodB() {
        throw new IllegalArgumentException("Ошибка в methodB");
    }
}

Давайте разберем ключевые моменты создания и использования исключений:

  1. Типы исключений:
  2. Checked (проверяемые) - наследуются от Exception
  3. Unchecked (непроверяемые) - наследуются от RuntimeException
  4. Error - системные ошибки, не предназначенные для обработки

  5. Создание собственных исключений:

  6. Наследование от Exception или RuntimeException
  7. Добавление конструкторов
  8. Добавление дополнительных полей и методов при необходимости

  9. Использование ключевого слова throw:

  10. Используется для явного выброса исключения
  11. Может использоваться с любым объектом Throwable
  12. Прерывает выполнение текущего метода

  13. Особенности работы с исключениями:

  14. Checked исключения должны быть объявлены в сигнатуре метода или обработаны
  15. Unchecked исключения не требуют объявления
  16. Можно создавать цепочки исключений с помощью причин (cause)

  17. Лучшие практики:

  18. Создавайте специфичные исключения для конкретных ошибок
  19. Включайте полезную информацию в сообщение об ошибке
  20. Используйте checked исключения для обрабатываемых ошибок
  21. Используйте unchecked исключения для программных ошибок

  22. Обработка исключений:

  23. try-catch блоки для обработки исключений
  24. finally блок для гарантированного выполнения кода
  25. multi-catch для обработки нескольких типов исключений
  26. try-with-resources для автоматического закрытия ресурсов