Пользовательские исключения
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 60 из 87.
Встроенные исключения Java охватывают многие распространенные сценарии ошибок, но иногда вам нужны исключения, специфичные для предметной области вашего приложения. Пользовательские исключения позволяют создавать значимые типы ошибок, которые четко сообщают о том, что пошло не так.
Чтобы создать пользовательское исключение, просто расширьте существующий класс исключения. Для проверяемого исключения расширьте Exception:
public class InsufficientFundsException extends Exception {
public InsufficientFundsException(String message) {
super(message);
}
}Для непроверяемого исключения наследуйте RuntimeException:
public class InvalidAgeException extends RuntimeException {
public InvalidAgeException(String message) {
super(message);
}
}Вызов super(message) передает сообщение об ошибке родительскому классу, делая его доступным через getMessage(). Затем вы можете выбрасывать и перехватывать свое пользовательское исключение, как и любое другое:
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("Balance too low: " + balance);
}
balance -= amount;
}
// Использование
try {
account.withdraw(1000);
} catch (InsufficientFundsException e) {
System.out.println(e.getMessage());
}Пользовательские исключения делают ваш код более читаемым и позволяют вызывающим сторонам по-разному обрабатывать конкретные условия ошибок. Они особенно ценны при создании API или библиотек, где важна четкая передача информации об ошибках.
Задание
ЛегкоДавайте создадим систему бронирования билетов, которая использует пользовательские исключения для обработки различных сценариев ошибок! Вы создадите значимые типы исключений, которые четко сообщают о том, что пошло не так при бронировании билетов.
Вы организуете свой код в четырех файлах:
TicketSoldOutException.java: Создайте пользовательское проверяемое исключение (наследуется отException) для случаев, когда билеты больше не доступны. Ваше исключение должно принимать сообщение в конструкторе и передавать его родительскому классу с помощьюsuper(message).InvalidSeatException.java: Создайте пользовательское непроверяемое исключение (наследуется отRuntimeException) для случаев, когда кто-то пытается забронировать неверный номер места. Это исключение также должно принимать и передавать сообщение своему родителю.TicketBooth.java: Создайте класс, который управляет продажей билетов. Ваша касса должна отслеживать общее количество доступных мест и максимальный допустимый номер места. Включите:Конструктор, который принимает общее количество доступных мест.
Метод
bookTicket(int seatNumber), который проверяет бронирование. Если билетов не осталось (количество доступных мест 0 или меньше), выбросьтеTicketSoldOutExceptionс сообщением"No tickets remaining". Если номер места меньше 1 или больше общего количества мест, выбросьтеInvalidSeatExceptionс сообщением"Seat " + seatNumber + " does not exist". В противном случае уменьшите количество доступных мест на 1 и выведите"Booked seat " + seatNumber + " successfully".Метод
getAvailableSeats(), который возвращает текущее количество доступных мест.Main.java: Объедините вашу билетную систему! Вы получите два входных значения: общее количество мест и номер места для бронирования.Создайте
TicketBoothс заданным общим количеством мест. Затем попытайтесь забронировать указанный номер места внутри блока try-catch. ПосколькуTicketSoldOutExceptionявляется проверяемым, вы должны его обработать. Сначала поймайтеTicketSoldOutExceptionи выведите"Booking failed: " + e.getMessage(). Затем поймайтеInvalidSeatExceptionи выведите в том же формате:"Booking failed: " + e.getMessage().После блока try-catch выведите
"Remaining seats: " + booth.getAvailableSeats(), используя метод-геттер.
Вы получите два входных значения по порядку: общее количество мест (целое число) и номер места для бронирования (целое число).
Обратите внимание, как проверяемые исключения заставляют вызывающую сторону обрабатывать их (с помощью try-catch или throws), в то время как непроверяемые исключения не требуют явной обработки. Выбирайте тип исключения в зависимости от того, является ли ошибка чем-то, что вызывающая сторона должна предвидеть и от чего должна уметь восстановиться!
Шпаргалка
Чтобы создать пользовательское исключение, расширьте существующий класс исключений.
Для проверяемого исключения (checked exception) расширьте Exception:
public class InsufficientFundsException extends Exception {
public InsufficientFundsException(String message) {
super(message);
}
}Для непроверяемого исключения (unchecked exception) расширьте RuntimeException:
public class InvalidAgeException extends RuntimeException {
public InvalidAgeException(String message) {
super(message);
}
}Вызов super(message) передает сообщение об ошибке родительскому классу, делая его доступным через getMessage().
Выбрасывайте и перехватывайте пользовательские исключения так же, как и любые другие:
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("Balance too low: " + balance);
}
balance -= amount;
}
// Using it
try {
account.withdraw(1000);
} catch (InsufficientFundsException e) {
System.out.println(e.getMessage());
}Проверяемые исключения заставляют вызывающую сторону обрабатывать их с помощью try-catch или throws. Непроверяемые исключения не требуют явной обработки. Выбирайте тип исключения в зависимости от того, должна ли вызывающая сторона предвидеть ошибку и иметь возможность восстановиться после нее.
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int totalSeats = scanner.nextInt();
int seatNumber = scanner.nextInt();
// TODO: Создайте TicketBooth с заданным общим количеством мест
// TODO: Используйте блок try-catch, чтобы попытаться забронировать место
// - Сначала перехватите TicketSoldOutException и выведите "Booking failed: [сообщение об исключении]"
// - Перехватите InvalidSeatException и выведите "Booking failed: [сообщение об исключении]"
// TODO: После try-catch выведите "Remaining seats: [количество]"
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка10Обработка исключений в ООП
Иерархия классов исключенийПользовательские исключенияПроверяемые и непроверяемые ошибкиПаттерн Try With ResourcesПовторение — Validated User2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»