Исключения. Практические Задания
Строка catch (WrongLoginException | WrongPasswordException e) выглядит безобидно, но если вы унаследуете одно исключение от другого, код перестанет компилироваться. На этой странице такие детали всплывают не в теории, а прямо в ваших решениях.
Задания по исключениям в Java закрепляют модуль «Исключения»: вы создадите собственные классы исключений, будете выбрасывать их оператором throw, перехватывать одним блоком multi-catch и встроите проверку логина и пароля в сквозной проект «Интернет-магазин» (часть 7).
Что повторить перед решением
Для обеих задач нужны три навыка: объявить свой класс исключения, выбросить его через throw и перехватить в try-catch. Если что-то из этого вызывает сомнения, сначала откройте соответствующий урок модуля.
| Урок | Что понадобится в задачах |
|---|---|
| Создание подклассов исключений | Классы WrongLoginException и WrongPasswordException с двумя конструкторами |
| Ключевое слово throw | Выброс исключения при неверном логине или пароле |
| Оператор try-catch-finally | Перехват нескольких исключений одним блоком multi-catch |
| Иерархия исключений | Выбор родителя: Exception (проверяемое) или RuntimeException |
Проверка логина и пароля
- Создайте статический метод, который принимает на вход три параметра:
login,passwordиconfirmPassword. loginдолжен содержать только латинские буквы, цифры и знак подчёркивания.- Длина
loginдолжна быть меньше 20 символов (от 1 до 19; пустая строка недопустима). Еслиloginне соответствует этим требованиям, выброситеWrongLoginException. passwordдолжен содержать только латинские буквы, цифры и знак подчёркивания, его длина должна быть меньше 20 символов. ТакжеpasswordиconfirmPasswordдолжны быть равны. Еслиpasswordне соответствует этим требованиям, выброситеWrongPasswordException.WrongPasswordExceptionиWrongLoginException— пользовательские классы исключений с двумя конструкторами: один по умолчанию, второй принимает сообщение исключения и передаёт его в конструктор классаException.- Обработка исключений проводится внутри метода.
- Используйте multi-catch block.
- Метод возвращает
true, если значения верны, илиfalseв другом случае.
С чего начать
Поместите все проверки в блок try и при нарушении правила выбрасывайте исключение через throw с понятным сообщением. Оба исключения перехватите одним catch (WrongLoginException | WrongPasswordException e), выведите e.getMessage() и верните false. Для проверки символов подойдёт login.matches("[A-Za-z0-9_]+").
Регистрация и обработка ошибок входа
Интернет-магазин · часть 7 из 13 · ← часть 6 · часть 8 →
Реализуйте аутентификацию и регистрацию пользователя интернет-магазина:
- Храните зарегистрированных пользователей в отображении (
Map), содержащем пары логин–пароль. - Если пользователь ввёл логин и пароль, которые есть в отображении, он аутентифицирован.
- Если логин есть в отображении, но пароль не совпадает, сообщите об ошибке входа. Существующую запись не изменяйте.
- Если такого логина в отображении нет, запросите пароль повторно (
confirmPassword) и проверьте корректность данных методом из задачи «Проверка логина и пароля». - Если проверка пройдена, добавьте логин и пароль в отображение — пользователь зарегистрирован.
На чём чаще всего ошибаются
Чаще всего решения ломаются не на исключениях, а на проверке строк: метод find() вместо matches() пропускает недопустимые символы, а \w не совпадает с кириллицей. Ниже — короткий пример с реальным выводом и ещё два неочевидных момента.
Pattern p = Pattern.compile("[A-Za-z0-9_]+");
System.out.println(p.matcher("admin!").find()); // true - нашлась подстрока "admin"
System.out.println(p.matcher("admin!").matches()); // false - проверяется вся строка
System.out.println("admin_1".matches("\\w+")); // true
System.out.println("логин".matches("\\w+")); // false - \w по умолчанию только латиница, цифры и _
System.out.println("".matches("[A-Za-z0-9_]+")); // false - квантификатор + требует хотя бы один символ | Ошибка | Что произойдёт | Как исправить |
|---|---|---|
matcher(login).find() | Логин admin! проходит проверку | Используйте matches() или String.matches() |
WrongPasswordException extends WrongLoginException и оба типа в multi-catch | Ошибка компиляции: Alternatives in a multi-catch statement cannot be related by subclassing | Наследуйте оба класса от Exception напрямую |
login.length() <= 20 | Принимается логин из 20 символов, хотя по условию нужно меньше 20 | login.length() < 20 |
users.put(login, password) без проверки containsKey() | Пароль существующего пользователя молча перезаписывается | Сначала проверьте, есть ли логин в Map |
Проверь свой код
Перед отправкой решения сверьтесь с рекомендациями по оформлению кода: имена классов исключений заканчиваются на Exception, пустых блоков catch быть не должно.
Часто задаваемые вопросы
От чего наследовать собственное исключение: от Exception или от RuntimeException?
От Exception, если вызывающий код обязан обработать ситуацию (неверный пароль — ожидаемая ошибка ввода): компилятор заставит её перехватить или объявить в throws. От RuntimeException — для ошибок программиста, которые обычно не перехватывают. В задачах этой страницы по условию используется Exception. Подробнее — в уроке Иерархия исключений.
Зачем пользовательскому исключению конструктор с сообщением?
Он передаёт текст в super(message), и тогда e.getMessage() объясняет причину: «Логин длиннее 19 символов» вместо null. Конструктор по умолчанию оставляют для случаев, когда достаточно самого типа исключения.
Можно ли присвоить новое значение переменной e в блоке multi-catch?
Нет. Параметр multi-catch неявно final, поэтому e = new WrongLoginException() внутри catch (WrongLoginException | WrongPasswordException e) не скомпилируется. В обычном catch с одним типом такое присваивание разрешено.
Можно ли хранить пароли в Map в настоящем приложении?
Только в учебной задаче. В реальных системах пароль в открытом виде не хранят: сохраняют хеш с солью (bcrypt, PBKDF2, Argon2) и при входе сравнивают хеши, а пользователей держат в базе данных, а не в памяти.
Комментарии