Я никогда раньше не занимался серьезным кодированием на Java, но я изучил синтаксис, библиотеки и концепции, основываясь на моих существующих навыках (Delphi и C #). Одна вещь, которую я с трудом понимаю, - это то, что я видел так много кода, который молча потребляет исключения после printStackTrace
следующего:
public void process() {
try {
System.out.println("test");
} catch(Exception e) {
e.printStackTrace();
}
}
Подобный код есть почти в каждой статье и проекте Java, с которыми я сталкивался. Насколько мне известно, это очень плохо. Исключение почти всегда следует перенаправлять во внешний контекст следующим образом:
public void process() {
try {
System.out.println("test");
} catch(Exception e) {
e.printStackTrace();
throw new AssertionError(e);
}
}
В большинстве случаев исключение должно обрабатываться в самом внешнем цикле, который принадлежит базовой структуре (например, Java Swing). Почему такой код в мире Java кажется нормой? Я озадачен.
Исходя из моего опыта, я бы предпочел полностью удалить printStackTrace . Я бы просто перебросил как необработанный aka RuntimeException
(или, что еще лучше, AssertionError
), затем поймал бы и зарегистрировал его в наиболее подходящем месте: во внешнем цикле фреймворка.
public void process() {
try {
System.out.println("test");
} catch(Exception e) {
throw new AssertionError(e);
}
}
Ответы:
Я всегда думал, что это похоже на следующий сценарий:
Когда полиция добирается до тела, они понятия не имеют, что только что произошло. Возможно, в конце концов, но это намного сложнее.
Лучше это:
Когда приезжает полиция, все улики на месте.
Если система выйдет из строя, лучше быстро выйти из строя
Решение вопроса:
+
РЕДАКТИРОВАТЬ:
Конечно, полезен раздел улова.
Если что-то можно сделать с исключением, то это и нужно делать.
Возможно, это НЕ исключение для данного кода, вероятно, это то, что ожидается (и в моей аналогии это похоже на бронежилет, и человек ждал выстрела в первую очередь).
И да, улов можно использовать для создания исключений, соответствующих абстракции.
источник
Обычно это происходит из-за того, что IDE предлагает полезное «быстрое исправление», которое помещает проблемный код в блок try-catch с этой обработкой исключений. Идея в том, что вы действительно что-то делаете, а ленивые разработчики - нет.
Это, без сомнения, дурной тон.
источник
Это классический аргумент соломенного человека .
printStackTrace()
это средство отладки. Если вы видели это в блоге или в журнале, это было потому, что писатель больше интересовался иллюстрацией другого момента, чем обработка исключений. Если вы видели это в производственном коде, разработчик этого кода был невежественным или ленивым, не более того. Его не следует рассматривать как пример обычной практики в «мире Java».источник
источник
Я нахожу, что это часто делается по двум причинам
Я не верю, что это явление ограничивается Java. Я часто видел такое кодирование на C # и VB.Net.
На первый взгляд это довольно шокирующе и ужасно выглядит. Но на самом деле ничего нового. Это происходит постоянно в приложениях C ++, которые используют возвращаемые значения кода ошибки вместо исключений. Однако разница в том, что игнорирование потенциально фатального возвращаемого значения на самом деле ничем не отличается от вызова функции, возвращающей void.
Foo* pFoo = ...; pFoo->SomeMethod(); // Void or swallowing errors, who knows?
Этот код выглядит лучше, но если бы SomeMethod () сказал вернуть HResult, это было бы семантически не иначе, как проглатывание исключения.
источник
потому что проверенные исключения - неудачный эксперимент
(может быть, printStackTrace () - настоящая проблема ? :)
источник
Я должен сказать, что меня немного возмущает тон, который подразумевает, что такая небрежная обработка ошибок является чем-то фундаментальным для программистов Java. Конечно, Java-программисты могут быть ленивыми, как и любой другой программист, а Java - популярный язык, поэтому вы, вероятно, увидите, что много кода проглатывает исключения.
Кроме того, как уже отмечалось в другом месте, есть понятные разочарования в связи с принудительным объявлением проверенных исключений в Java, хотя лично у меня с этим проблем нет.
У меня проблема, я полагаю, заключается в том, что вы быстро просматриваете кучу статей и фрагментов кода в сети, не беспокоясь о контексте. По правде говоря, когда вы пишете техническую статью, пытаясь объяснить, как работает какой-то конкретный API или как начать с чего-либо, вы, скорее всего, пропустите некоторые аспекты кода - обработку ошибок, которая не связана напрямую. связанных с тем, что вы демонстрируете, является вероятным кандидатом на удаление, особенно если исключение маловероятно в примере сценария.
Люди, которые пишут статьи такого рода, должны поддерживать разумное соотношение сигнал / шум, и я думаю, довольно справедливо, это означает, что они должны предполагать, что вы знаете некоторые основы языка, на котором разрабатываете; как правильно работать с ошибками и многое другое. Если вы наткнулись на статью и заметили отсутствие надлежащей проверки ошибок, тогда ничего страшного; просто убедитесь, что, когда вы включаете эти идеи (но, конечно, никогда не сам точный код, верно?) в свой производственный код, вы будете иметь дело со всеми теми частями и кусками, которые автор разумно упустил, наиболее подходит для того, что вы разрабатываете.
У меня действительно есть проблема с вводными статьями очень высокого уровня, в которых обсуждаются такие проблемы, но я не возвращаюсь к ним, но имейте в виду, что у Java-программистов нет определенного «мышления» относительно обработки ошибок; Я знаю многих ваших любимых программистов на C #, которые тоже не заботятся о решении всех своих проблем.
источник
try {...} catch (IOException e) {}
просто глупо (и TODO НЕ помогает). Это наверняка заставит многих новичков сделать то же самое. Кроме того, это гораздо больше писать , чемthrows IOException
, что является правильным большую часть времени. Может быть, один раз на статью это невозможно, и тогда писатьthrow wrap(e)
(без скучных определенийwrap
) - хорошее решение. Одна из первых вещей, на которые я опирался в Java, это то, что тихое глотание - ужасная вещь, и я очень осторожен, поэтому я не делаю этого даже временно (даже сбой в долгосрочной перспективе лучше).Печать System.out или e.printStackTrace (), подразумевающая использование System.out, обычно является красным флажком, означающим, что кто-то не потрудился выполнить усердную работу. За исключением настольных Java-приложений, для большинства Java-приложений лучше использовать ведение журнала.
Если режимом отказа для метода является отсутствие операции, вполне нормально съесть исключение, независимо от того, записываете ли вы причину (и существование) или нет. Однако более часто предложение catch должно предпринимать какие-то исключительные действия.
Повторное отображение исключения - это то, что лучше всего делать, когда вы либо используете catch для очистки части работы на уровне, где необходимая информация все еще доступна, либо когда вам нужно преобразовать исключение в тип исключения, более доступный для вызывающего.
источник
Он потребляется беззвучно, только если блок catch действительно пуст.
Что касается статей, они, вероятно, более интересны в доказательстве чего-то другого, помимо того, как работать с исключениями. Они просто хотят перейти прямо к делу и получить как можно более короткий код.
Очевидно, что вы правы, исключения должны, по крайней мере, регистрироваться, если они собираются «игнорироваться».
источник
Как указывали другие, вы видите это по одной из трех причин:
Последний пункт является наименее вероятным. Я говорю это, потому что не думаю, что кто-то действительно отлаживает таким образом. Пошаговое выполнение кода с помощью отладчика - гораздо более простой способ отладки.
Лучшее описание того, что следует делать в блоке catch, можно найти в главе 9 « Эффективной Java » Джошуа Блоха .
источник
В C # все исключения являются исключениями времени выполнения, но в Java у вас есть исключения времени выполнения и проверенные исключения, которые вы должны либо перехватывать, либо объявлять в своих методах. Если вы вызываете какой-либо метод, в конце которого есть «throws», вы должны либо перехватить упомянутые исключения, либо ваш метод также должен объявить эти исключения.
Статьи Java обычно просто печатают трассировку стека или содержат комментарий, поскольку обработка исключений не имеет отношения к предмету статьи. Однако в проектах с этим нужно что-то делать, в зависимости от типа исключения.
источник
Вы должны увидеть это очень часто, если программист правильно выполняет свою работу. Игнорирование исключений - плохая практика! Но есть несколько причин, по которым некоторые могут это сделать, и более подходящие решения:
"Этого не случится!" Конечно, когда-нибудь вы «знаете», что этого Исключения не произойдет, но еще более целесообразно повторно вызвать исключение времени выполнения с возникшим Исключением в качестве «причины», а не просто игнорировать его. Бьюсь об заклад, это произойдет когда-нибудь в будущем. ;-)
Создание прототипа кода Если вы просто набираете свой материал, чтобы посмотреть, работает ли он, вы можете проигнорировать все исключения, которые могут возникнуть. Это единственный случай, когда я делаю ленивый улов (Throwable). Но если из кода получится что-то полезное, я включаю правильную обработку исключений.
"Я не знаю, что делать!" Я видел много кода, особенно библиотечного, который поглощает возникающие исключения, потому что на этом уровне приложения невозможно выполнить надлежащую обработку. НЕ ДЕЛАЙТЕ ЭТОГО! Просто повторно вызовите исключение (либо добавив предложение throws в сигнатуру метода, либо заключив исключение в конкретную библиотеку).
источник
Вы всегда должны пересылать его или обрабатывать соответствующим образом в реальном контексте. Многие статьи и учебные пособия упростят свой код, чтобы прояснить наиболее важные моменты, и одна из самых простых вещей, которые можно упростить, - это обработка ошибок (если только вы не пишете статью об обработке ошибок, то есть :)). Поскольку java-код проверяет обработку исключений, то простейшим методом предоставления рабочего примера является включение простого блока перехвата без вывода сообщений (или оператора регистрации).
Если вы найдете это в чем-то другом, кроме примера кода, не стесняйтесь пересылать код в TDWTF, хотя у них сейчас может быть слишком много примеров этого :)
источник
Боюсь, что большинство java-программистов не знают, что делать с Исключениями, и всегда считают это раздражением, которое замедляет их кодирование в «номинальном» случае. Конечно, они совершенно неправы, но их трудно убедить в том, что ЭТО ВАЖНО правильно обрабатывать исключения. Каждый раз, когда я встречаю такого программиста (а это бывает часто), я даю ему две записи для чтения:
Кстати, я полностью согласен с тем, что глупо перехватывать типизированное исключение, чтобы повторно выбросить его, встроенное в исключение RuntimeException:
источник
Комбинация проверенных исключений и интерфейсов приводит к тому, что код должен обрабатывать исключения, которые никогда не запускаются. (То же самое относится и к нормальному наследованию, но это более распространено и проще объяснить с помощью интерфейсов)
Причина: реализация интерфейса не может генерировать (проверенные) исключения, отличные от тех, которые определены в спецификации интерфейса. По этой причине создатели интерфейса, не зная, каким методам класса, реализующим интерфейс, может действительно потребоваться сгенерировать исключение, могут указать, что все методы могут вызывать по крайней мере один тип исключения. Пример: JDBC, где объявлено, что все и его «бабушка» выбрасывают SQLException.
Но на самом деле многие методы реальных реализаций просто не могут дать сбой, поэтому ни при каких обстоятельствах они не вызывают исключения. Код, вызывающий эти методы, должен каким-то образом «обрабатывать» исключение, и самый простой способ - это проглотить исключение. Никто не хочет загромождать свой код бесполезной обработкой ошибок, которая никогда не выполняется.
источник
Как уже отмечалось, вызов printStackTrace () на самом деле не является тихой обработкой.
Причина такого рода «проглатывания» исключения заключается в том, что если вы продолжите передавать исключение вверх по цепочке, вам все равно придется обрабатывать исключение. где-то или позволить приложению аварийно . Таким образом, обработка его на уровне информационного дампа не хуже, чем обработка его на верхнем уровне при помощи информационного дампа.
источник
Его ленивая практика - не что иное, как на самом деле.
Обычно это делается, когда вы действительно не заботитесь об исключении, а не увеличиваете свою работу пальцами.
источник
Я не согласен с тем, что повторное создание проверенного исключения - лучшая идея. Обработка средств отлова; если вам нужно перебросить, вы не должны ловить. В этом случае я бы добавил предложение throws к сигнатуре метода.
Я бы сказал, что обертывание проверенного исключения в непроверенное (например, способ, которым Spring переносит проверенное исключение SQLException в экземпляр своей непроверенной иерархии) приемлемо.
Ведение журнала можно считать обработкой. Если бы пример был изменен на запись трассировки стека с использованием log4j вместо записи в консоль, сделало бы это приемлемым? Не так много изменений, ИМО.
Настоящая проблема заключается в том, что считается исключительной и приемлемой процедурой восстановления. Если вы не можете восстановиться после исключения, лучшее, что вы можете сделать, - это сообщить об ошибке.
источник
Пожалуйста, никогда, никогда не заключайте проверенное исключение в непроверенное исключение.
Если вы обнаружите, что имеете дело с исключениями, которые, по вашему мнению, вам не следует делать, тогда мой совет - вы, вероятно, работаете на неправильном уровне абстракции.
Я уточню: отмеченные и непроверенные исключения - два очень разных существа. Проверенные исключения похожи на старый метод возврата кодов ошибок ... да, обрабатывать их несколько сложнее, чем коды ошибок, но у них тоже есть преимущества. Непроверенные исключения - это ошибки программирования и критические системные сбои ... другими словами, исключительные исключения. Пытаясь объяснить, что такое исключение, многие люди попадают в полную неразбериху, потому что не осознают разницу в этих двух, очень разных случаях.
источник
FooException
, текущая ситуация не будет соответствовать тому, что вызывающий восходящий поток ожидает, когдаFooException
будет брошено a .Потому что они еще не научились этому трюку:
class ExceptionUtils { public static RuntimeException cloak(Throwable t) { return ExceptionUtils.<RuntimeException>castAndRethrow(t); } @SuppressWarnings("unchecked") private static <X extends Throwable> X castAndRethrow(Throwable t) throws X { throw (X) t; } } class Main { public static void main(String[] args) { // Note no "throws" declaration try { // Do stuff that can throw IOException } catch (IOException ex) { // Pretend to throw RuntimeException, but really rethrowing the IOException throw ExceptionUtils.cloak(ex); } } }
источник
Настоящее исключение состоит в том, чтобы упростить обработку ошибок и отделить ее от обнаружения ошибок. Это противоречит представлению ошибок кодами ошибок, когда код обработки ошибок разбросан повсюду, и каждый вызов, который может потерпеть неудачу, должен проверяться на код возврата.
Если исключение представляет собой ошибку (что бывает в большинстве случаев), обычно наиболее разумным способом ее устранения является спасение и передача обработки некоторому верхнему уровню. Следует учитывать повторное отображение другого исключения, если к нему добавлена значимая семантика, то есть эта ошибка является необычным системным сбоем / временной (сетевой) проблемой / это ошибка на стороне клиента или сервера и т. Д.
Из всех стратегий обработки ошибок самая невежественная - это скрытие или просто печать сообщения об ошибке и дальнейшее продвижение, поскольку ничего не произошло.
Люди из Sun хотели, чтобы код был более явным, и заставляли программистов писать, какие исключения могут быть вызваны каким методом. Это казалось правильным ходом - любой будет знать, чего ожидать в ответ от любого вызова метода с учетом его прототипа (он может возвращать значение этого типа или выдавать экземпляр одного из указанных классов (или его подкласса)).
Но, как выяснилось со многими невежественными Java-программистами, они теперь относятся к обработке исключений, как если бы это была языковая ошибка / «функция», которая требует обходного пути, и пишут код худшим или почти худшим из возможных способов:
Как написать "правильный путь" чем?
источник
Если вы хотите, чтобы ваше исключение обрабатывалось за пределами области действия текущего метода, вам не нужно на самом деле его перехватывать, вместо этого вы добавляете оператор throws в подпись метода.
Операторы try / catch, которые вы видели, есть только в коде, где программист явно решил обработать исключение на месте и, следовательно, не выдавать его дальше.
источник
Я думаю, что разработчики также стараются учитывать важность «правильного поведения» в конкретном контексте. Часто, если выбросить код или распространить исключение вверх, ничего не даст, потому что исключение является фатальным, вы также можете сэкономить время и усилия, «сделав неправильные вещи».
источник
Обычно вы проглатываете исключение, если не можете от него избавиться, но это не критично. Хорошим примером является IOExcetion, которое может быть выбрано при закрытии соединения с базой данных. Вы действительно хотите вылететь, если это произойдет? Вот почему в Jakarta DBUtils есть методы closeSilently.
Теперь для проверенных исключений, которые вы не можете восстановить, но которые являются критическими (обычно из-за ошибок программирования), не проглатывайте их. Я думаю, что исключения должны регистрироваться как можно ближе к источнику проблемы, поэтому я бы не рекомендовал удалять вызов printStackTrace (). Вы захотите превратить их в RuntimeException с единственной целью - не объявлять эти исключения в своем бизнес-методе. На самом деле нет смысла иметь высокоуровневые бизнес-методы, такие как createClientAccount (), генерирующие ProgrammingErrorException (читайте SQLException), вы ничего не можете сделать, если у вас есть опечатки в вашем sql или доступ к плохим индексам.
источник
По опыту, проглатывание исключения вредно в основном, когда оно не распечатано. Это помогает привлечь внимание в случае сбоя, и я иногда делаю это намеренно, но простая печать исключения и продолжение позволяет найти проблему и исправить ее, и все же обычно не оказывает негативного влияния на других, работающих с той же кодовой базой. .
Я вообще-то увлекаюсь Fail-Fast / Fail-HARD, но хотя бы распечатайте это. Если вы на самом деле "съедите" исключение (то есть по-настоящему ничего не делать: {}), поиск его будет стоить кому-то ДНЕЙ.
Проблема в том, что Java заставляет вас ловить много вещей, которые разработчик знает, что они не будут выброшены, или не заботится о них. Самый распространенный - Thread.sleep (). Я понимаю, что здесь есть дыры, которые могут привести к проблемам с потоками, но обычно вы знаете, что не прерываете это. Период.
источник
Может быть много причин, по которым можно использовать catch Exception. Во многих случаях это плохая идея, потому что вы также ловите RuntimeExceptions - и вы не знаете, в каком состоянии будут находиться базовые объекты после того, как это произойдет? Это всегда трудная вещь с неожиданными условиями: можете ли вы верить, что остальной код впоследствии не откажет.
В вашем примере печатается трассировка стека, чтобы, по крайней мере, вы знали, в чем могла быть основная причина. В более крупных проектах по разработке программного обеспечения лучше регистрировать эти вещи. И давайте надеяться, что компонент журнала не генерирует исключения, и вы можете оказаться в бесконечном цикле (что, вероятно, убьет вашу JVM).
источник
Если у вас есть проверенное исключение, и вы не хотите обрабатывать его в методе, вам просто нужно, чтобы метод генерировал исключение. Ловите и обрабатывайте исключения только в том случае, если вы собираетесь делать с этим что-то полезное. Простое ведение журнала в моей книге не очень полезно, поскольку у пользователей редко бывает время читать журналы в поисках исключений или знать, что делать в случае возникновения исключения.
Хотя можно обернуть исключение, я бы не советовал вам это делать, если: вы генерируете другое исключение, соответствующее существующему интерфейсу, или на самом деле не существует способа создания такого исключения.
BTW: если вы хотите повторно выбросить проверенное исключение, вы можете сделать это с помощью
try { // do something } catch (Throwable e) { // do something with the exception Thread.currentThread().stop(e); // doesn't actually stop the current thread, but throws the exception/error/throwable }
Примечание: если вы это сделаете, вы должны убедиться, что объявление throws для метода верное, поскольку компилятор не может сделать это за вас в этой ситуации.
источник
Thread#stop()
устарел и пока что отключен (выкидываетUnsupportedOperationException
).потому что это лучшая практика. Я думал, что все знают.
но холодная правда в том, что никто толком не понимает, как работать с исключениями. Стиль обработки ошибок C имеет гораздо больше смысла.
источник