2013-09-08 2 views
27

Я уже некоторое время программирую на Java. Но иногда я не понимаю, когда я должен выбросить исключение и когда я должен поймать исключение. Я работаю над проектом, в котором есть много методов. Иерархия что-то вроде this-Когда ловить Исключение против Когда бросать Исключения?

Method A will call Method B and Method B will call some Method C and Method C will call Method D and Method E. 

Так в настоящее время, что я делаю я IS-бросающая исключения во всех методах и ловить его в способе А, а затем войти в качестве ошибки.

Но я не уверен, будет ли это правильным путем? Или мне следует начинать перехватывать исключения во всех методах. Так вот почему эта путаница началась в моей-Когда я должен поймать Exception vs, когда я должен выбросить исключения. Я знаю, что это глупый вопрос, но почему-то я пытаюсь понять эту основную концепцию.

Может ли кто-нибудь дать мне подробный пример When to catch the Exception vs When to throw the Exceptions, чтобы мои понятия очистились от этого? И в моем случае я должен продолжать бросать исключение, а затем поймать его в основном вызове метода A?

+2

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

+0

Речь идет не о том или ином. Вы можете поймать исключения, сделать некоторую обработку, а затем восстановить их. Вы, вероятно, должны придумать конкретные примеры того, о чем вы думаете. Отправьте пример, рекомендованный здесь: http://www.sscce.org/ – dcaswell

ответ

4

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

Как вы хотите с этим справиться? Возможно, установив диалог «Извините, не могу подключиться к SERVER/DB» или что-то еще. Is - это метод A, B или C, который создал эту информацию SERVER/DB (например, прочитав файл настроек или запросив пользовательский ввод) и попробовал соединение? Это , вероятно, метод, который должен обрабатывать Исключение. Или, по крайней мере, 1 от метода, который должен его обработать.

Это действительно зависит от вашего приложения, поэтому это может быть только общий совет. Большая часть моего опыта связана с приложениями Swing/desktop, и вы обычно можете почувствовать, какие классы выполняют программную логику (например, «Контроллер»), и кто создает диалоговые окна (например, «Просмотр»). Обычно «контроллер» должен поймать исключение и попытаться что-то сделать.

В веб-приложении это может быть другим.

Некоторые очень скелетные коды, большинство классов не существует, и я не уверен, что URL-адрес для БД даже имеет смысл, но вы получаете идею. Смутно Swingish ...

/* gets called by an actionListener when user clicks a menu etc... */ 
public URL openTheDB() { 
    URL urlForTheDB = MyCoolDialogUtils.getMeAURL(URL somePreviousOneToFillInTheStart); 
    try { 
    verifyDBExists(urlForTheDB); 
    // this may call a bunch of deep nested calls that all can throw exceptions 
    // let them trickle up to here 

    // if it succeeded, return the URL 
    return urlForTheDB; 
    } 
    catch (NoDBExeption ndbe) { 
    String message = "Sorry, the DB does not exist at " + URL; 
    boolean tryAgain = MyCoolDialogUtils.error(message); 
    if (tryAgain) 
     return openTheDB(); 
    else 
     return null; // user said cancel... 
    } 
    catch (IOException joe) { 
    // maybe the network is down, aliens have landed 
    // create a reasonable message and show a dialog 
    } 

} 
37

Вы должны поймать исключение, когда находитесь в методе, который знает, что делать.

Например, забудьте о том, как это работает на данный момент, скажем, вы пишете библиотеку для открытия и чтения файлов.

Так у вас есть класс, скажем:

public class FileInputStream extends InputStream { 
    public FileInputStream(String filename) { } 
} 

Теперь, предположим, что файл не существует. Что вы должны сделать? Если вы пытаетесь придумать ответ, это потому, что его нет ... FileInputStream не знает, что делать с этой проблемой. Таким образом, он подбрасывает цепь, то есть:

public class FileInputStream extends InputStream { 
    public FileInputStream(String filename) throws FileNotFoundException { } 
} 

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

public class Main { 
    public static void main(String... args) { 
     String filename = "foo.txt"; 
     try { 
      FileInputStream fs = new FileInputStream(filename); 

      // The rest of the code 
     } catch (FileNotFoundException e) { 
      System.err.println("Unable to find input file: " + filename); 
      System.err.println("Terminating..."); 
      System.exit(3); 
     } 
    } 
} 

Здесь программист знает, что делать, чтобы они поймать исключение и обработать его.

+0

-1 Печать сообщения stderr, которое даже не ссылается на имя файла, за которым следует жесткий выход JVM, вряд ли «обрабатывает» исключение , Пожалуйста, улучшите свой код. (Я знаю, что это просто быстрый пример, но вы можете сделать лучше ...) – user949300

+11

@ user949300 Это [sscce] (http://sscce.org). Это должен быть простой пример, а не загромождать его другими вещи. Тем не менее, вы хорошо разбираетесь в 'filename', который я исправил. – durron597

+1

@ user949300 также замечает, что он находится в методе 'main', там не так уж и много сделать. Очевидно, что вы не будете сильно выходить из JVM глубоко в коде – durron597

1

Вы обычно генерируете исключение, если хотите уведомить вызывающего абонента о методе некоторых сбоев.

недопустимого ввод например пользователя, проблемы баз данных, сетевые сбои, отсутствующие файлы

3

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

  • поймать Если у вас есть метод, который подключается к ресурсу (например, открывает файл/сеть)
  • бросок, если класс выше в иерархии нуждается в информации об ошибке
0

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

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

3

Я расскажу о шаблоне, который спас мой бекон в производственных условиях или двух.

Мотивация

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

Метод

Для достижения этой цели, я ловлю все проверяемые исключения и повторно бросить их непроверенным исключения. Затем я использую глобальный захват на границе каждого из моих архитектурных слоев (обычно абстрагированных или инъецируемых, поэтому он только когда-либо записывается один раз). Именно в этих точках я могу добавить дополнительный контекст к стеку ошибок или решить, следует ли регистрировать и игнорировать, или создавать настраиваемое исключенное исключение с переменными для хранения любого дополнительного контекста. На в стороне, я только заносить ошибки в верхнем слое, чтобы остановить «двойной протоколирование» возникновения (например, задание хрон, контроллер пружинного для AJAX)

throw new RuntimeException(checked,"Could not retrieve contact " + id); 

При таком подходе нет захламления вашего GUI или подписи метода бизнес-уровня путем объявления «бросков» для исключений, связанных с базой данных.

Пример того, как это работает в реальной жизни:

Допустим, работа моего кода является автоматизированный процесс, чтобы возобновить многие страховые полисы.Архитектура поддерживает графический интерфейс для ручного запуска обновления для одной политики. Также скажем, что почтовый индекс для рейтинговой области поврежден в БД для одной из этих политик.

Примером такого типа журнала ошибок я бы хотел достичь.

Log message: Flagging policy 1234 for manual intervention due to error:

From Stack Trace: Error Renewing Policy 1234. Rolling back the transaction ... This catch would also cover errors such as save errors, or generation of a letter.

From Stack Trace: Caused by: Error Rating Policy 1234 ... This catch would pickup errors retrieving many other objects, and algorithm errors such as NPE etc...

From Stack Trace: Caused by: Error Retrieving Rating Area 73932 ...

From Stack Trace: Caused by: JPA: unexpected null in field 'postcode'

5

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

Функция представляет собой единицу работы, и ошибки следует рассматривать как ошибки или иным образом на основе их влияния на функции. Внутри функции ф, сбой является ошибкой, если и только если оно препятствует п от встречи любого из предпосылок своей вызываемой стороны в, достижения любого из е собственных постусловий «s, или восстановив любую инвариантного что f разделяет ответственность за ведение.

Существует три различные вида ошибок:

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

Любое другое условие не об ошибке и не следует сообщать об ошибке.

Сообщите об ошибке там, где функция обнаруживает ошибку, с которой она не может справиться сама по себе и которая препятствует ее продолжению в любой форме нормальной или предполагаемой операции.

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

Смежные вопросы