Как бы вы перехватили все исключения? - PullRequest
5 голосов
/ 02 октября 2009

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

EDIT:

Спасибо за хороший совет, но разве текущий совет не относится только к проверенным исключениям? Как насчет непроверенных исключений, таких как NullPointerExceptions, разве не было бы полезно, если бы они могли быть перехвачены, и чтобы приложение, перехватывая их, сбрасывало кучу / стек, чтобы предоставить вам текущий контекст приложения в момент сбоя?

Ответы [ 7 ]

11 голосов
/ 02 октября 2009

С какой целью вы хотите перехватывать каждое исключение - для ведения журнала и отчетов об ошибках?

Перехват каждого исключения в каждой отдельной строке Java-программы возможен, но, вероятно, приведет к значительному снижению производительности. Если это неизбежно, то, вероятно, было бы лучше использовать что-то вроде AspectJ , которое может работать во время компиляции (то есть «вплетается» в файлы вашего класса) и, следовательно, намного быстрее, чем динамические прокси.

Но я бы постарался избежать любой ценой! В целом, я бы сказал, что лучше ограничить объем исключений, которые вы хотите перехватить. Также вы можете захотеть взглянуть на Thread.setDefaultUncaughtExceptionHandler , который я считаю полезным для отображения диалогов об ошибках в приложениях с графическим интерфейсом.

9 голосов
/ 02 октября 2009

Как и в ответе Фила, здесь приведен пример кода, показывающий, как использовать обработчик необработанных исключений. Это работает как для проверенных, так и для непроверенных исключений.

Редактировать: Обновлено для печати трассировки стека на основе обновленных комментариев в вопросе.

import java.lang.Thread.UncaughtExceptionHandler;

public class Test {

    public static void main(String[] args) throws Exception {
        Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {

            @Override
            public void uncaughtException(Thread t, Throwable e) {
                e.printStackTrace();
            }}

        );

        // throw new RuntimeException(); /* this works too */
        throw new Exception();
    }

}
5 голосов
/ 02 октября 2009

У Нейта и Конамимана ... То, что вы предлагаете, совсем не работает и не отвечает на вопрос ОП.

Что если OP запускает новый поток изнутри вашего try / catch?

Например:

public static void main(String[] args) {
    try {
        final Thread t = new Thread( new Runnable() {
            public void run() {
                System.out.println( 3 / Math.min(0,4) );
            }
        } );
        t.start();
    catch(Throwable t) {
        ...
    }
}

Тогда вы не поймаете исключение.

Правильный способ сделать это - использовать Thread.setDefaultUncaughtExceptionHandler.

3 голосов
/ 02 октября 2009
public static void main(String[] args) {
    try {
        ...
    catch(Throwable t) {
        ...
    }
}
0 голосов
/ 02 октября 2009

Всем тем, кто ставит под сомнение необходимость поймать все исключения ...

Существует лот уважительных причин для перехвата всех исключений:

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

Обратите внимание, что сама Java перехватывает все исключения в EDT (Thread Dispatch Thread) и порождает новый EDT после смерти EDT. Вы можете считать это формой "самовосстановления" программного обеспечения. Умирание EDT не является чем-то неслыханным и точно не препятствует правильной работе приложений (наоборот). (и да, у Swing и AWT довольно много ошибок, просто взгляните на парад ошибок Sun;)

Можно утверждать, что любое уважающее себя программное обеспечение должно фактически учитывать случай непредвиденного исключения (все ли программное обеспечение, которое вы поставляете, на 100% без ошибок и никогда не получает новые выпуски, выпуски с исправлением ошибок?) И что-то делает умный, когда такое непредвиденное исключение случается.

«Что-то умное» может препятствовать сбою программного обеспечения (как в случае EDT), предупреждать пользователя, отправлять отчет и т. Д.

Ответы на вопрос о необходимости сделать что-то или предположить, что это плохая практика, если ИМХО будет изменено.

0 голосов
/ 02 октября 2009

Если вы просто хотите поймать исключение, блока try / catch будет достаточно. Если вы хотите, чтобы они не были выброшены, или заносили в журнал исключения или исключения, вам, вероятно, понадобится AOP для этого. AspectJ справится с этим довольно хорошо, но остерегайтесь потенциальных узких мест производительности.

Динамические прокси будут работать только тогда, когда метод проксируется, поэтому, если какое-либо Исключение выбрасывается и перехватывается при выполнении объекта прокси, у прокси нет никаких средств для перехвата Исключения.

Следует учитывать, что вы перехватываете все исключения или только проверенные исключения. Чтобы отловить все исключения, совет AspectJ around throwing или after throwing будет включать в себя обработку по каждому методу, включая создание объектов JoinPoint и синтетических методов при каждом вызове метода. Обычно это не проблема, если процесс не находится в узком цикле, где сборка мусора может пройти через крышу.

0 голосов
/ 02 октября 2009

Важнее, чем просто перехват всех исключений, - это ГДЕ, где вы перехватываете исключение:

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

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

...