Pull to refresh

Comments 24

Конструкции, что в конце статьи приведены где-то применяются на практике? Я имею в виду это считается нормальным стилем?
>> Конструкции, что в конце статьи приведены где-то применяются на практике? Я имею в виду это считается нормальным стилем?
именно в таком виде — нет.
но
1. Это учебные примеры, задача которых состоит в том, что бы слушатель досконально разобрался с механизмами обработки исключений. Тройные циклы и тройные if — это тоже ненормально.
2. Косвенным образом вложенные конструкции присутствуют постоянно. Вы под try-catch-ем вызываете метод в котором тоже есть try-catch.
Спасибо.

В целом хотел вам лично выразить признательность за ваши лекции на ютьюбе, не скоро их просмотрю, но смотрю постоянно, весьма полезны. Весьма.

И еще вопрос, хотя я наверное забегаю вперед, сам способ применения исключений, как я понимаю, это некоторая материя, которая не описывается правилами? Что-то из серии с опытом придет и т.д.?
Исключения — это инструмент, и конечно чем больше опыта, тем лучше. Но общие правила есть
1. Любая программа — это последовательность действий, которая может разветвляться. Для веток, которые являются ненормальными(в случае невозможности достижения цели) используются исключения. При корректной работе программы их использовать не стоит.
2. Исключения выбрасываются(throw) там, где выполнение зашло в тупик и нет корректных альтернатив. А ловятся там, где могут быть обработаны. Т.е. это как бы резкий перескок из одного слоя логики в другой
3. Обрабатываемые или нет? Как выбирать: если в правильно написанной программе такой ситуации произойти не может, то кидаете необрабатываемое исключение. В остальных случаях — обрабатываемые.
Ну и не злоупотребляйте ими, исключения хороши в меру.
Кстати, интересный вопрос для обсуждения, связанный с исключениями.
В С++ для создания объектов исключений можно использовать любые классы и типы.
В подавляющем большинстве последующих языков (включая C# и Java) для этой цели можно использовать исключительно специальный класс типа throwable и его потомков.

С чем это связано? И как лучше?
Облегчает ли это (введение специального класса для исключений) каким-то образом жизнь компилятору и программе?
Улучшает ли это читаемость программы?
Какие еще преимущества/недостатки у такого подхода?
да, в C++ можно кинуть даже int (кажется).
но не понимаю — какой в этом смысл.
Один из смыслов состоит в том, чтобы не навязывать разработчику Стандартную библиотеку. В Плюсах никто не заставляет инклюдить хедер, содержащий std::exception, да и вообще, в части Стандарта, которая не касается Стандартной библиотеки, никакие «особенные» типы не упомянаются. Так во всяком случае было до C11, в котором языковая контрукция initializer list судя по всему требует обязательного включения соотв хедера.

В Плюсах можно просто придерживаться правила: никогда не бросать ничего, кроме std::exception. Этому правилу придерживается Стандартная библиотека, и если ему следовать, то всё будет норм.
При дизайне нового языка программирования какой способ предпочтительнее?
С одной стороны — универсальность, можно любой тип использовать для исключений.
С другой стороны — зачем? (особенно если достаточно просто реализуется наследование). В языке D, насколько я помню, тоже специальный тип исключения, и там это не просто так, в типе есть какие-то поля, используемые при обработке исключений.
А что касается подключения или неподключения библиотек — ну так специальный тип можно сделать и встроенным в язык.
К каждому экземпляру Throwable и его потомков может быть привязано детальное сообщение о его причине и трассировка стека. Если бы это был произвольный класс, гарантировать этого было бы нельзя.
А вторая часть о чем будет? Что хотите вложить в нее? Я бы хотел видеть «Философия исключений в Java». В последнее время перестаю использовать Checked исключения и ухожу в сторону Unchecked. Очень надоело видеть списки исключений в декларациях методов. Мне хочется понять это я что-то недопонимаю или это так и надо и все к этому приходят?
Это от лени писать «лишние» throws и catch :)
ЕСЛИ будет, то план такой:
1. try+catch+finally
2. checked/unchecked
3. «внутренности исключения» и 4 наиболее популярных стратегии обработки
4. Изменения в Java 7 (try-with-resources, multicatch, more precise rethrow)
5. 25 наиболее популярных исключения в Java (от ArithmeticException до UnsupportedOperationException)
>>ЕСЛИ
Очень надеюсь, чтобы у Вас нашлось время, возможность и желание написать подобное. Надеюсь мой комментарий заплюсуют те кто хочет почитать от Вас Вашу вторую часть.
>> Мне хочется понять это я что-то недопонимаю или это так и надо и все к этому приходят?
В моем представлении, при использовании проверяемых исключений
1. Мы подключаем компилятор, переходим к статически типизированному стилю Java. Требуем, что бы компилятор следил за наличием обработчиков.
2. Можем обезопасить себя, как разработчики сервисных модулей. При вызове на ковер к начальству с вопросом «почему ваша программа не нашла USB порт, но не уведомила пользователя об этом», вы говорите
— Товарищи, мой код
class USBUtils {
    USBConnection connectTo(USBAddress address) throws USBNotFounException, USBNotInitedException, USBBadVersionException {...}   
}

И обнаруживает, что USB нет И кидает USBNotFounException И это исключение проверяемое, значит тот, кто вызывает этот метод получил USBNotFounException (где-то обязательно есть catch), но неправильно отреагировал.
Если бы это был unchecked исключение, то клиент может все списать на недостатки коммуникации в команде, типа, «ну я недопонял, что такое может быть», «а ты меня явно предупредил о такой ситуации»,… А так, за вас говорит компилятор.
Смотря на Ваш пример:
class USBUtils {
    USBConnection connectTo(USBAddress address) throws USBNotFounException, USBNotInitedException, USBBadVersionException {...}   
}

Мне пришла в голову мысль о том, что если возникает ситуация с «портянкой», то возможно:
1) Код решает более чем 1 задачу. А хороший код должен работать согласно SPR;
2) Недостаточно хорошо продумана система слоев и использования типов исключений с каждого слоя.

Так ли это?
1. SRP говорит, что одна сущность (метод, поле, класс, ...) отвечает за что-то одно.
У меня же одно конкретное действие (захват USB-порта) может не сработать по разным причинам.
Эти причины — и есть исключительные ситуации.
На вскидку не чувствую, что надо перепроектировать этот метод.
Хотя можно, конечно, ввести много фаз подключения (поиск порта, проверка на подходящую версию, проверка на инициированность), но если вам дали такое нижестоящее API (которое делает соединение одним махом на уровне ОС), то вы искусственно породите множество классов-состояний проверки порта. И за вами придет Бритва Оккама.
И тогда решайте, что вам дороже — SRP или Оккам:)
2. Возможно это Facade к сложному многостадийному API с исключение на каждую фазу. Тогда Facade уменьшает кол-во вызовов и классов, но собирает в пучек все исключения.
Checeked исключения в java используются в таких случаях, когда вы в принципе не можете предотвратить их возникновение.
Те есть, причину RuntimeException можно проверить и устранить заранее. Например, проверить ссылку на null перед вызовом метода, что бы не получать NullPointerException. Поэтому их разрешается не обрабатывать — предполагается, что программист позаботился о том, что бы такое исключение не возникало.
А вот с Checeked Exception такой номер не пройдет. Например, ошибка при чтении файла может возникнуть непосредственно в момент чтения, потому что другая программа его просто удалила. Соответственно, при чтении файла требуется обрабатывать IOException, так как гарантировать его отсутствие программист не может в принципе.

Если же вы уверенны, что при нормальной работе вашей программы такое исключение не возможно, а при его возникновении невозможна дальнейшая работа, оберните его в RuntimeException и выбросите дальше. В случае чего программа быстро упадёт с трассировкой стека и записью в консоль.
>>Те есть, причину RuntimeException можно проверить и устранить заранее.
Из Ваших слов понял что это «Программерское» исключение, говорящее о том что программист что-то забыл. Все так?
В большинстве случаев (но не во всех) можно устранить
NullPointerException — можно проверить на null
IllegalStateException — вызвал метод у объекта в ненадлежащем состоянии, значит давай объект в корректном состоянии
ConcurrentModificationException — случайно изменил коллекцию с используемым итератором
Исключения должны быть или не быть в зависимости от бизнес логики, опыт конечно играет не маловажную роль в понимании когда нужно ловить, а когда надо чтобы приложение полностью упало с откатом, иногда ручным, транзакции, если она была разумеется.
Т.к. статья учебная я бы добавил хотя бы небольшое предостережение про производительность исключений и о том, что не нужно строить логику на исключениях, исключения — для исключительный ситуаций. Иначе, прочитав статью, кто-нибудь будет писать такой код:

try {
    return a/b;
catch(Exception e) {
    return 0;
}
Sign up to leave a comment.