Вы когда-нибудь задумывались, как начинают формироваться исключения и как они влияют на ваш проект? Полезны ли они? Влияют ли они в любом случае на производительность?
Во время недавнего занятия в моем университете состоялась конкретная дискуссия, связанная с исключениями и тем, как они могут повлиять на ваш проект. Большая часть беседы включала споры о том, как работают исключения, когда они полезны и как они влияют на ваш проект, с нескольких точек зрения; удобочитаемость кода, связь, производительность и общая полезность исключений. Я хотел немного изучить эту идею и посмотреть, какие последствия будут иметь исключения, когда вы начнете их использовать.
По моему опыту, обработка исключений – очень обширная и обсуждаемая тема, с несколькими различными мнениями по ней, которые обычно формируются благодаря личному опыту каждого человека. Я видел, как программисты выполняли обширный и защитный код, выполняя попытку/перехват для каждой отдельной операции или выполнения метода, чтобы окружить все большой попыткой/перехватом с одной обработкой исключений, ни к чему вообще.
Да, это очень удобно в сценариях, когда вы обращаетесь к определенным ресурсам, которые могут привести к критическому сбою, например, при доступе к базе данных, вызове API, открытии файла и т.д. Эти ситуации в конечном итоге приведут к сбою из-за тайм-аута, невозможности найти ресурс, несоблюдения определенного правила в базе данных, такого как внешний ключ или обязательное поле, или непредвиденной ошибки. И исключения позволяют вам восстанавливаться после этих сценариев и показывать что-то пользователю, страницу с ошибкой, страницу, которая не найдена, “Извините, повторите попытку позже”. Что-то значимое, что позволит пользователю узнать, что что-то пошло не так, а не просто закрыть или заморозить окно или браузер.
Исключения также очень полезны, когда вы разрабатываете библиотеки, предназначенные для использования другими командами, или если вы хотите внести свой вклад в открытый исходный код. Обычно люди не тратят время на чтение того, как работает конкретная библиотека, и просто используют ее. Если они что-то пропустили, создание исключения было бы отличным способом обучить их и контролировать, как они взаимодействуют с вашей библиотекой.
С другой стороны, у нас есть другие сценарии, в которых использование исключения было бы немного излишним, поскольку вы, возможно, могли бы решить этот сценарий с помощью других простых структур управления.
Возьмем следующий пример: У вас есть класс с именем Employee, у которого есть конструктор, принимающий 1 параметр, имя. Представьте, что требуется имя, и вы не можете создать сотрудника без имени. Таким образом, вы решаете реализовать пользовательское исключение, чтобы при имени вы отправляли это исключение всем, кто хочет его использовать, которое мы будем называть EmployeeException. Это означало бы, что:
- Каждая часть вашего приложения, которая хочет создать сотрудника, должна будет окружить код в ловушке try, чтобы поймать эту конкретную ошибку
- Каждая часть вашего приложения будет зависеть как от сотрудника, так и от исключения сотрудника, что увеличит связь, что может привести к проблемам с обслуживанием в будущем.
- Попытка/перехват будет немного запутанной, так как вы создадите исключение для сотрудника. Было ли это потому, что имя было пустым? или мне нужно было установить и другие переменные? Или имя должно иметь определенный формат? Очевидно, что вы можете изменить имя исключения на что-то более понятное, но если вы работаете в команде или используете внешнюю библиотеку, а кто-то другой закодировал это исключение, это может привести к путанице. И представьте, если есть несколько ошибок, которые могут вызвать это исключение? Не могли бы вы создать собственное исключение для каждого из них? Это может привести к еще большему усилению связи между вашим проектом и сотрудником.
- Это может повлиять на производительность (я объясню это позже)
Потенциально мы могли бы решить эту проблему, добавив статический метод в класс Employee, который из определенного набора параметров возвращает логическое значение, показывающее, может ли сотрудник быть создан или нет, и это помогло бы с указанными выше пунктами. Это было бы одной из альтернатив обработке исключений, проверке входных данных и созданию методов проверки.
Для этого обсуждения я подумал, что мог бы применить более практичный подход. Поэтому я создал простой проект Java, который соответствует сценарию сотрудника, о котором я упоминал ранее. В основном мы создаем сотрудника с конструктором (строковое имя) и создаем исключение, если имя равно null. И мы делаем то же самое, но добавляем метод isValid для проверки перед созданием сотрудника. Я протестировал это с помощью цикла for и несколько раз запускал конструктор, потому что для того, чтобы увидеть разницу во времени выполнения, мне нужно создать более 1 сотрудника. Поэтому я протестировал следующие сценарии:
1 – Создайте сотрудника и окружите его попыткой/уловом.
2 – Создайте сотрудника, где половина из них выдаст ошибку, а половина из них пройдет и окружит ее попыткой/уловом.
3 – Создайте сотрудника, в котором половина из них выдаст ошибку, а половина из них пройдет и окружит ее попыткой/уловом, а также на улове я выполняю ex.getStackTrace(), просто чтобы имитировать обработку исключений.
4 – Создайте сотрудника, где пятая часть из них выдаст ошибку и окружит ее попыткой/уловом.
5 – Создайте сотрудника и окружите его попыткой/уловом, но так как это допустимое имя, никаких исключений не возникает
6 – Создайте сотрудника с, но до того, как я выполнил недопустимое
Я выполнил эти сценарии с полным набором 100, 1000, 10000, 100000, 1000000. И вот результаты (измеренные в миллисекундах):
- Поскольку особой разницы нет, выполнение занимает от 0 до 1 мс
- Для сценариев 1, 2, 3 требуется в 3 раза больше, чем для сценариев 4, 5, 6. Это наводит на мысль, что обработка исключения занимает больше времени. Кроме того, из числа 5 мы можем заметить, что добавление блока try/catch не снижает производительность, если не возникает исключений.
- Для сценариев 1, 2, 3 требуется в 16-23 раза больше, чем для других сценариев
- Для, он взлетает до 136 мс и 154 мс для сценариев 1 и 3, и 5 мс и 4 мс для сценариев 5 и 6.
- Например, сценарии, в которых создаются и управляются исключения, могут занимать до 1 секунды.
В целом, мы можем сказать, что исключения, очевидно, являются одним из столпов языков программирования. Они позволяют нам восстанавливаться после нескольких критических сценариев и позволяют нам передавать эту информацию пользователю. Более того, это позволяет нам отслеживать эти ошибки при закрытии catch, чтобы мы могли извлечь уроки из этих ошибок и повторить наш проект, чтобы предотвратить их.
С другой стороны, мы должны учитывать, что исключения затрагивают не только конечного пользователя, но и разработчика. Пользовательские исключения могут привести к проблемам с обслуживанием кода, удобочитаемостью и производительностью. ИМХО сказал бы, что это скорее индивидуальный анализ, иногда они могут быть весьма полезны, но в других сценариях это может привести к некоторым головным болям! Просто убедитесь, что вы немного подумали, прежде чем вводить исключения в смесь.
Оригинал: “https://dev.to/juanigalan91/is-there-a-price-to-pay-for-using-exceptions-58gl”