Почему люди Java часто потребляют исключения молча?

Я никогда раньше не делал серьезных Java-кодировок, но я изучил синтаксис, библиотеки и концепции на основе моих существующих навыков (Delphi и С#). Одна вещь, которую я почти не понимаю, это то, что я видел столько кода, который молча потребляет исключения после 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);
        }
    }

Ответ 1

Я всегда думал, что похоже на следующий сценарий:

"Человек получает выстрел.

Он задерживает дыхание и имеет достаточно сил, чтобы сесть на автобус.

Через 10 миль человек выходит из автобуса, идет по парам блоков и умирает".

Когда полиция добирается до тела, у них нет подсказки о том, что только что произошло. В конце концов, возможно, это намного сложнее.

Лучше:

"Человек получает выстрел, и он умирает мгновенно, и тело лежит именно там, где только что произошло убийство".

Когда полиция прибывает, все доказательства имеются.

Если система терпит неудачу, лучше выполнить быстро выполнить

Решение вопроса:

  • Невежество.
    • +
  • Лень

EDIT:

Конечно, секция catch полезна.

Если что-то может быть сделано с исключением, то, где это должно быть сделано.

Вероятно, это НЕ исключение для данного кода, возможно, это то, что ожидается (и по моей аналогии похоже пуленепробиваемая куртка, и мужчина ждал выстрела на первом месте).

И да, улов можно использовать для Выбросить исключения, соответствующие абстракции

Ответ 2

Обычно это связано с тем, что IDE предлагает полезное "быстрое исправление", которое обертывает код нарушения в блоке try-catch с этой обработкой исключений. Идея в том, что вы на самом деле что-то делаете, но ленивые разработчики этого не делают.

Это плохая форма, без сомнения.

Ответ 3

  • Java заставляет вас обрабатывать все Исключения явно. Если метод, вызываемый вашими кодами, объявляет об исключении FooException и BarException, ваш код ДОЛЖЕН обрабатывать (или удалять) эти исключения. Единственным исключением из этого является RuntimeException, которое тикает, как ниндзя.
  • Многие программисты ленивы (включая меня), и очень просто просто распечатать трассировку стека.

Ответ 4

Это классический аргумент соломы. printStackTrace() - это отладочная помощь. Если вы видели его в блоге или в журнале, это объяснялось тем, что писатель больше интересовался иллюстрацией точки, отличной от обработки исключений. Если вы видели это в производственном коде, разработчик этого кода был невежественным или ленивым, не более того. Это не следует воспринимать как пример обычной практики в "мире Java".

Ответ 5

Я нахожу, что это часто бывает 2 причины.

  • Программист был ленив
  • Программист хотел охранять точку входа в компонент (правильно или неправильно)

Я не считаю, что это явление ограничено Java. Я часто видел такое кодирование в С# и VB.Net.

На первый взгляд это довольно шокирует и выглядит ужасно. Но на самом деле это ничего нового. Это происходит все время в приложениях на С++, которые используют значения возврата кода ошибки по сравнению с исключениями. Разница заключается в том, что игнорирование потенциально фатального возвращаемого значения действительно не выглядит иначе, чем вызов функции, которая возвращает void.

Foo* pFoo = ...;
pFoo->SomeMethod(); // Void or swallowing errors, who knows?

Этот код выглядит лучше, но если SomeMethod() должен был возвращать HResult, он был бы семантически ничем не отличающимся от проглатывания исключения.

Ответ 6

поскольку Проверенные исключения - неудавшийся эксперимент

(возможно, printStackTrace() является реальной проблемой?:)

Ответ 7

Я должен сказать, что я слегка возмущаюсь тоном, который подразумевает, что подобное поведение при обработке ошибок является чем-то принципиальным для Java-программистов. Конечно, Java-программисты могут лениться, как и любой другой программист, а Java - популярный язык, поэтому вы, вероятно, увидите много ошибок при проглатывании кода.

Кроме того, как было указано в другом месте, есть понятные фрустрации с принудительным объявлением Java проверенных исключений, хотя лично у меня нет проблем с этим.

У меня есть проблема с, я думаю, в том, что вы ветерок через кучу статей и фрагментов кода в Интернете, не утруждая себя рассмотрением контекста. По правде говоря, когда вы пишете техническую статью, пытающуюся объяснить, как работает какой-то конкретный API, или как начать с чего-то, тогда вы, скорее всего, пропустите некоторые аспекты кода - обработку ошибок, которая не напрямую связанный с тем, что вы демонстрируете, является вероятным кандидатом на удаление, особенно если исключение вряд ли произойдет в сценарии примера.

Люди, которые пишут статьи такого характера, должны поддерживать разумное соотношение сигнал/шум, и довольно справедливо, я думаю, это означает, что они должны предположить, что вы знаете некоторые основы языка, в котором вы разрабатываете; как правильно справляться с ошибками и кучей других вещей. Если вы сталкиваетесь с какой-либо статьей и замечаете отсутствие надлежащей проверки ошибок, то это прекрасно; просто убедитесь, что, когда вы включаете эти идеи (но, конечно, никогда не являетесь точным кодом, не так ли?) в свой производственный код, вы будете иметь дело со всеми этими битами и бобами, которые автор разумно упустил, таким образом, что большинство подходит для того, что вы разрабатываете.

У меня возникла проблема с очень высокоуровневыми вводными статьями, которые проделывают такие проблемы, даже не возвращаясь к ним, но, пожалуйста, имейте в виду, что не существует определенного "мышления" Java-программистов относительно обработки ошибок; Я знаю много ваших любимых программистов на С#, которые также не беспокоятся о всех своих проблемах.

Ответ 8

Отпечаток System.out или e.printStackTrace() - что подразумевает использование System.out, как правило, красного флага, означающего, что кто-то не потрудился выполнять усердную работу. За исключением настольных приложений Java, большинство приложений Java лучше используют протоколирование.

Если режим отказа для метода является нерабочим, он отлично подходит, чтобы есть исключение, независимо от того, записываете ли вы причину (и существование) или нет. Более типично, однако, предложение catch должно принимать какое-то исключительное действие.

Повторное создание исключения - это то, что лучше всего делать, когда вы либо используете catch для очистки части работы на уровне, где необходимая информация по-прежнему доступна, либо когда вам нужно преобразовать исключение в тип исключения, более подходящий для вызывающий абонент.

Ответ 9

Он потребляется только тихо, если блок catch действительно пуст.

Что касается статей, то они, вероятно, более интересны в доказательстве некоторых других моментов, кроме того, как справляться с исключениями. Они просто хотят получить прямо к делу и иметь самый короткий код.

Очевидно, что вы правы, но исключения должны быть зарегистрированы, если они будут "проигнорированы".

Ответ 10

Как указывали другие, причина, по которой вы видите это, связана с одной из трех причин:

  • В IDE создан блок try-catch
    • Код был скопирован и вставлен
    • Разработчик поставил stacktrace для отладки, но никогда не вернулся, чтобы нормально обрабатывать исключение.

Последняя точка - наименее вероятная. Я говорю это, потому что я не думаю, что кто-то действительно отлаживает этот путь. Выполнение кода с помощью отладчика - гораздо более простой способ отладки.

Лучшее описание того, что должно быть сделано в блоке catch, можно найти в главе 9 Эффективная Java от Джошуа Блоха.

Ответ 11

В С# все исключения - это исключения во время выполнения, но на Java у вас есть исключения времени выполнения и проверенные исключения, которые вы должны либо уловить, либо объявить в своих методах. Если вы вызываете любой метод, который имеет "броски" в конце, вы должны либо уловить исключения, упомянутые там, либо ваш метод должен также объявить эти исключения.

Статьи Java обычно просто печатают трассировку стека или имеют комментарий, поскольку обработка исключений не имеет отношения к предмету статьи. В проектах, однако, что-то нужно делать по этому поводу, в зависимости от типа исключения.

Ответ 12

Вы должны видеть это очень часто, если программист выполняет свою работу правильно. Игнорирование Исключения - плохая, плохая практика! Но есть некоторые причины, почему некоторые могут это сделать и более удобные решения:

  • "Это не произойдет!" Несомненно, когда-нибудь вы "знаете", что это исключение не произойдет, но его еще более целесообразно реконструировать исключение во время выполнения, в то время как исключение Exception как "причина" вместо того, чтобы просто игнорировать его. Бьюсь об заклад, что это произойдет в будущем.; -)

  • Код прототипирования Если вы просто печатаете свои материалы, чтобы узнать, работает ли это, вы можете игнорировать все Исключения, которые могут возникнуть. Это единственный случай, когда я делаю ленивый улов (Throwable). Но если код превратится во что-то полезное, я включу правильную обработку исключений.

  • "Я не знаю, что делать!" Я видел много кода, особенно код библиотеки, который проглатывает исключения, потому что на этом уровне приложения не может быть выполнена надлежащая обработка. Не делайте этого! Просто переверните исключение (либо добавив предложение throws в подпись метода, либо обернув исключение в конкретную библиотеку).

Ответ 13

Вы всегда должны пересылать его или обращаться с ним соответствующим образом в реальном мире. Многие статьи и учебные пособия упростят их код, чтобы получить более важные точки, хотя одна из самых простых вещей для упрощения - обработка ошибок (если только вы не пишете статью об обработке ошибок::)). Так как java-код будет проверять обработку исключений, то простой прокси файл (или журнал регистрации) - это самый простой способ предоставить рабочий пример.

Если вы обнаружите это в чем-либо, кроме кода примера, не стесняйтесь пересылать код на TDWTF, хотя у них может быть слишком много его примеров:)

Ответ 14

Сочетание проверенных исключений и интерфейсов приводит к тому, что код должен обрабатывать выходы, которые никогда не будут выбрасываться. (То же самое относится и к нормальному наследованию, но это более распространено и проще объяснить с помощью интерфейсов)

Причина: реализация интерфейса не может исключать (проверять) исключения, отличные от тех, которые определены в спецификации интерфейса. По этой причине создатели интерфейса, не зная, какие методы класса, реализующего интерфейс, действительно должны были бы генерировать исключение, могут указать, что все методы могут вызывать по крайней мере один тип исключения. Пример: JDBC, где объявлено, что все и его бабушка бросают SQLException.

Но на самом деле многие методы реальных реализаций просто не могут потерпеть неудачу, поэтому ни при каких обстоятельствах они никогда не бросают исключение. Код, вызывающий эти методы, все равно должен "обрабатывать" исключение, и самый простой способ - это усвоить исключение. Никто не хочет загромождать свой код с кажущейся бесполезной обработкой ошибок, которая никогда не будет выполнена.

Ответ 15

Как указано, вызов printStackTrace() не является действительно тихой обработкой.

Причиной такого рода "глотания" исключения является то, что, если вы продолжаете передавать исключение по цепочке, вам все равно придется обрабатывать исключение где-то или разрешить приложение сбой. Таким образом, обращение с ним на уровне, которое происходит с помощью информационного дампа, не хуже, чем обработка его на верхнем уровне с помощью информационного дампа.

Ответ 16

Его ленивая практика - ничего не поделаешь.

Обычно это делается, когда вы действительно не заботитесь об исключении - вместо того, чтобы увеличивать ваши пальцы.

Ответ 17

Я не согласен с тем, что переосмысление проверенного исключения - лучшая идея. Уловка означает обработку; если вам нужно реконструировать, вы не должны ловить. В этом случае я добавлю предложение throw к сигнатуре метода.

Я бы сказал, что перенос проверенного исключения в неконтролируемый (например, способ Spring обертывает проверенное SQLException в экземпляр его неконтролируемой иерархии) является приемлемым.

Ведение журнала можно рассматривать как обработку. Если этот пример был изменен для записи трассировки стека с использованием log4j вместо записи на консоль, это сделает его приемлемым? Не так много изменений, ИМО.

Реальная проблема - это то, что считается исключительной и приемлемой процедурой восстановления. Если вы не можете восстановиться из исключения, лучше всего это сообщить об ошибке.

Ответ 18

Реальная точка исключений - упростить обработку ошибок и отделить ее от обнаружения ошибок. Это противоречит представлению ошибок по кодам ошибок, где ошибка код обработки разбросаны повсюду, и каждый вызов, который может потерпеть неудачу, должен быть проверен для кода возврата.

Если исключение представляет собой ошибку (в большинстве случаев), то наиболее разумным способом ее устранения является спасение и уход обработки на некоторый верхний уровень. Повторяя различное исключение, следует учитывать, если к нему добавлена ​​значимая семантика, то есть эта ошибка представляет собой необычную системную ошибку/временную (сетевую) проблему/это ошибка на стороне клиента или сервера и т.д.

Из всех стратегий обработки ошибок наиболее невежественные скрываются или просто печатают сообщение об ошибке и идут вперед, поскольку ничего не произошло.


Люди Sun хотели, чтобы код был более явным и принудительным программистом, чтобы писать, какие исключения могут быть выбраны с помощью какого метода. Казалось, это правильный ход - любой известно, чего ожидать взамен от любого вызова метода с его прототипом (он может вернуться значение этого типа или бросить экземпляр одного из указанных классов (или его подкласса)).

Но, как выяснилось, с множеством неосведомленных программистов на Java они теперь рассматривают обработку исключений, как если бы это была ошибка языка/ "функция", которая нуждалась в обходном пути и написании кода наихудшим или почти наименее возможным способом:

  • Ошибка обрабатывается сразу в контексте, не подходящем для решения, что с ним делать.
  • Он отображается или игнорируется молча, и вычисления продолжаются, даже если дополнительный код нет возможности нормально работать.
  • Вызывающий метод не может отличить, успешно ли он завершен или нет.

Как написать "правильный путь", чем?

  • Укажите каждый базовый класс исключений, которые могут быть выбраны в заголовке метода. AFAICR Eclipse может делать это автоматически.
  • Сделать список бросков в прототипе метода значимым. Длинные списки бессмысленны, а "throw Exception" - ленивый (но полезный, когда вы не беспокоитесь многое об исключениях).
  • При написании "неправильного пути" простое "бросить исключение" намного лучше и занимает меньше байтов, чем "try {...} catch (Исключение e) {e.printStackTrace();}".
  • Retrow прикованное исключение, если необходимо.

Ответ 19

Я боюсь, что большинство программистов Java не знают, что делать с Исключениями, и довольно часто считают это раздражением, которое замедляет их кодирование "номинального" случая. Конечно, они совершенно неправы, но трудно убедить их, что важно правильно разбираться с исключениями. Каждый раз, когда я встречаюсь с таким программистом (это часто случается), я даю ему две записи:

  • знаменитый Thinking In java
  • Краткая и интересная статья Барри Рузека доступна здесь: www.oracle.com/technology/pub/articles/dev2arch/2006/11/effective-exceptions.html

Кстати, я категорически согласен с тем, что глупо поймать типизированное исключение, чтобы переустановить его в RuntimeException:

  • если вы его поймаете, нажмите HANDLE.
  • в противном случае измените свою сигнатуру метода, чтобы добавить возможные исключения, которые вы/не могли бы обрабатывать, поэтому ваш абонент имел бы возможность сделать это самостоятельно.

Ответ 20

Пожалуйста, никогда не завершайте проверенное исключение в исключенном исключении.

Если вы обнаружите, что имеете дело с исключениями, которые вы не думаете, что вам следует, мой совет заключается в том, что вы, вероятно, работаете на неправильном уровне абстракции.

Я уточню: проверенные и непроверенные исключения - это два совершенно разных зверя. Проверенные исключения похожи на старый метод возврата кодов ошибок... да, они несколько более болезненны для обработки, чем коды ошибок, но у них также есть преимущества. Непроверенные исключения - это ошибки программирования и критические сбои системы... исключительные исключения, другими словами. При попытке объяснить, что такое исключение, многие люди попадают в полный беспорядок, потому что они не признают разницу в этих двух, очень разных случаях.

Ответ 21

Потому что они еще не научились этому трюку:

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);
        }
    }
}

Ответ 22

Если вы хотите, чтобы ваше исключение было обработано за пределами текущего метода, вам не нужно его поймать, вместо этого вы добавляете оператор "throws" к сигнатуре метода.

Операторы try/catch, которые вы видели, только в коде, где программист явно решил обработать исключение на месте и, следовательно, не бросать его дальше.

Ответ 23

Я думаю, что разработчики также стараются учитывать важность "правильной работы" в конкретном контексте. Часто для выброса кода или при распространении исключения вверх ничего не будет покупать, потому что исключение является фатальным, вы можете сэкономить время и усилия, "сделав неправильную вещь".

Ответ 24

Обычно вы проглатываете исключение, если вы не можете его восстановить, но это не критично. Одним хорошим примером является IOExcetion, который может быть запущен при закрытии соединения с базой данных. Вы действительно хотите сбой, если это произойдет? Вот почему Jakarta DBUtils имеют близкие методы.

Теперь для проверенных исключений, которые невозможно восстановить, но которые являются критическими (обычно из-за ошибок программирования), не проглатывайте их. Я думаю, что исключения должны быть зарегистрированы как можно ближе к источнику проблемы, поэтому я бы не рекомендовал удалить вызов printStackTrace(). Вы захотите превратить их в RuntimeException с единственной целью не объявлять эти исключения в своем бизнес-методе. На самом деле не имеет смысла иметь бизнес-методы высокого уровня, такие как createClientAccount() throws ProgrammingErrorException (читать SQLException), вы ничего не можете сделать, если у вас есть опечатки в вашем sql или доступ к плохим индексам.

Ответ 25

Из опыта, проглатывание исключения вредно, главным образом, когда оно не печатается. Это помогает привлечь внимание, если вы потерпите крах, и я буду делать это намеренно порой, но просто распечатывая исключение и продолжая, вы можете найти проблему и исправить ее, но, как правило, не оказывает отрицательного воздействия на других, работающих на одной и той же кодовой базе.

Я нахожусь в Fail-Fast/Fail-HARD, но, по крайней мере, распечатаю его. Если вы на самом деле "Ешьте" исключение (которое по сути ничего не делает: {}) Это будет стоить кому-то DAYS, чтобы его найти.

Проблема в том, что Java заставляет вас поймать множество вещей, которые разработчик знает, не будет брошен или им все равно, если они есть. Наиболее распространенным является Thread.sleep(). Я понимаю, что есть дыры, которые могут разрешить проблемы с потоками, но, как правило, вы знаете, что вы не прерываете его. Период.

Ответ 26

Могут быть много причин, по которым можно было бы использовать исключение catch. Во многих случаях это плохая идея, потому что вы также улавливаете RuntimeExceptions - и хорошо, что вы не знаете, в каком состоянии будут выполняться базовые объекты после этого? Это всегда сложно с непредвиденными условиями: можете ли вы доверять тому, что остальная часть кода не сработает после этого.

В этом примере печатается стек, так что, по крайней мере, вы узнаете, в чем была причина. В более крупных проектах программного обеспечения лучше всего регистрировать эти вещи. И давайте надеяться, что компонент журнала не выдаст исключений ни из нашего, что вы можете оказаться в бесконечном цикле (который, вероятно, убьет вашу JVM).

Ответ 27

Если у вас есть проверенное исключение, и вы не хотите обрабатывать его в методе, вы должны просто исключить этот метод. Только поймайте и обработайте исключения, если вы собираетесь что-то сделать с этим. Просто вносить в журнал это не очень полезно в моей книге, поскольку пользователи редко имеют время для чтения журналов, ищущих исключения, или знают, что делать, если вызывается исключение.

В то время как обертка исключения является опцией, я бы не предложил вам сделать это, если; вы бросаете другое исключение, чтобы соответствовать существующему интерфейсу, или действительно нет такого исключения, которое должно быть выбрано.

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 для метода верное, поскольку компилятор не может сделать это для вас в этой ситуации.

Ответ 28

потому что это лучшая практика. Я думал, все знают.
но холодная правда заключается в том, что никто не понимает, как работать с исключениями. Стиль передачи ошибок C сделал гораздо больше смысла.