2009-02-09 5 views
4

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

Я читал, что два основных способа обработки кода исключения являются:

1.) бросает исключение в примерки блоке с «бросить новый ...», и ловить его сразу в улове -block - так называемый механизм try-throw-catch.

2.) бросая исключение в методе с «throw new ...», а затем объявляя в заголовке метода, что этот метод может генерировать исключение с «throws ...» - так называемый pass- заместитель бакс.

Я недавно прочитал, что «не имеет смысла бросать исключение, а затем ловить его одним и тем же методом», что заставило меня подумать, понимаю ли я что-то не так, или человек, который это было что-то другое. Не делает ли это первый способ обработки исключений (механизм try-throw-catch)? Я имею в виду, что он выдает исключение и ловит его в том же методе. Я прочитал, что лучше всего использовать исключение в одном методе и перехватывать его другим способом, но это всего лишь один (возможно, лучший) способ. Другой способ также является законным и правильным, не так ли?

Не могли бы вы дать мне комментарий по этому вопросу? Большое спасибо.

+0

Да, я знаю. Читая ответы, иногда (почти каждый раз) я не могу сказать, какой из них лучший, люди говорят разные вещи, и я беру что-то полезное из многих ответов. Но если это важно (это?), Я сделаю это. – user42155

+0

Ну, неделю назад я дал вам ответ, который был правильным и проголосовал 11 раз. Если вы его примете, я получу хороший блестящий значок «Просветленный». Это моя мотивация. : D С другой стороны, вы должны вознаграждать тех, кто тратит время, чтобы ответить на ваши вопросы. Кроме того, вы получаете 2 очка и значок «Scholar». –

+0

Да, я всегда голосую ответы с одним, и я думал, что вознаграждаю реплик таким образом. Но с этого момента я попытаюсь подобрать лучший ответ. Но, как я сказал, это сложно - есть много лучших ответов .... хм ...;) – user42155

ответ

6

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

2

С первым способом вы имеете в виду что-то вроде этого:

try { 
    ok = doSomething(); 
    if (!ok) { 
    throw new Exception("Error"); 
    } 
ok = doSomethingElse(); 
}catch (Exception e) { 
} 

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

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

+0

В чем смысл переменной «ok» в этом коде? Вам нужно ИЛИ исключение ИЛИ флаг ok. – DJClayworth

+0

Я предполагаю, что это просто для ясности в этом простом примере. – Calum

+0

Извините, пожалуйста, проигнорируйте вышеуказанный комментарий. У меня ощущение утра в понедельник. – DJClayworth

1

Мое преимущество заключается в том, что с использованием первого метода ваш код быстро не читается - поскольку функциональность и обработка ошибок смешиваются. BUT имеет смысл в некоторых случаях, когда у вас есть попытка {} catch {} finaly {} - например, при обработке файлов или обработке базы данных, где вы ALLWAYS хотите, чтобы соединение было закрыто.

try{ //do something 
}catch(Exception ex){ 
//log 
}finally{ 
//connection.close 
} 

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

20

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

Например, FileNotFoundException выбрасывается из new FileInputStream(new File(filename)), потому что сам FileInputStream не может обрабатывать случай, когда файл отсутствует; это исключение должно быть брошено, поэтому приложение конечного пользователя может справиться с этой проблемой.

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

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

+0

tiny nitpick: «new File (filename)» не генерирует исключения, когда файл не существует. –

+0

О да ... спасибо! Исправлена. :) –

1

На мой взгляд, попробуйте блоки, которые вы пишете не должны включают любые «бросить новые», которые пойманы внутри одного и того же метода. Когда вы бросаете исключение, вы говорите: «Я столкнулся с ситуацией, с которой я не могу справиться, кому-то еще придется иметь дело с ней». Ваш метод с «throw new» должен либо создать исключение для исключения, либо бросить или объявить проверенное исключение в своей сигнатуре метода.

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

Я не создаю свое собственное исключение, а затем поймаю его в том же методе.

2

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

Вы бы бросить исключение, а не только непосредственно обработку ошибки, если:

  • Другой код, как и код, который называется ваш метод, должен обработать ошибку. Например, если ваш код не является кодом пользовательского интерфейса, то он, вероятно, не должен создавать окна. Это ваш метод №2.

  • Вы можете воспользоваться функцией try, catch, finally block. Возможно, вы могли бы написать более чистый код таким образом, но я думаю, что в 90% случаев ваш код будет более читаемым, используя простые операторы if.

4

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

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

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

+0

Спасибо. Теперь я понимаю лучше. Тем не менее, в книгах с intro Java есть такие простые программы, которые используют «throw new» в if-statement, окруженном блоком try-catch. И, вероятно, пока вы не получите больше опыта написания реальных программ, вы не сможете понять это, как вы это объясните. – user42155

+0

Если книги используют его таким образом, это объясняет, как исключения и обработка исключений работают в небольших примерах кода - или книги просто плохие. –

3

Лицо, которое написало «не имеет смысла бросать исключение, а затем ловить его одним и тем же методом», имеет право на их мнение, но оно не широко распространено. Есть много случаев, когда бросать и ловить исключение в том же методе - это то, что нужно. Самое простое - это то, где вы выполняете последовательность операций, и отказ любого из них делает остальные недействительными. Если вы обнаружите, что одна из этих операций терпит неудачу, вполне разумно выкинуть исключение и поймать его в конце метода. На самом деле это логичный способ делать вещи. Возможно, вы могли бы переписать код, чтобы не использовать исключение, может быть, с некоторыми флагами состояния и оператором break или двумя, но зачем вам? Использование исключения дает понять, что происходит и улучшает читаемость кода.

3

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


«Не первый способ обработки исключений делает именно это»?

Мой ответ: да, поскольку вы описываете его, первый метод работает, бросая и перехватывая исключение в том же методе. Тем не менее, я не знаю, что try-throw-catch должен работать, когда вы его описываете.


«Я читал, что это лучшая практика бросить исключение в одном методе, и поймать его в другом методе, но это только один (возможно лучше) способ. Другой способ также юридические и правильно, не так ли?

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

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

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


Мои комментарии:

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

В комбо один метод использует механизм try-throw-catch, чтобы поймать исключение, вызванное вызываемым методом. Мне кажется, что 1) и 2) должны работать вместе, чтобы сформировать вашу стратегию обработки исключений.

Теперь, возможно, кто-то придет и даст нам несколько замечательных причин, по которым мы можем захотеть исключить исключение в том же методе. Я ожидаю, что есть некоторые, но для меня они кажутся исключениями, а не правилом.

Приветствия, Ed

0

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

Смотри ниже:

1) бросание и ловить исключение в этом методе (неправильно)

public void method() { 
    try {  
     workA... 
     workA... 
     workA... 
     workA...  
     if(conditionIvalid() && notEnoughWhatever() && isWrongMoment()) { 
      throw new IllegalStateException("No the rigth time"); 
     } 
     workB... 
     workB... 
     workB... 
     workB... 
    } catch(IllegalStateException iee) { 
     System.out.println("Skiped workB..."); 
    } 
    workC.... 
    workC.... 
    workC.... 
    workC.... 
} 

В этом сценарии исключение метания используются, чтобы пропустить раздел "workB".

Это было бы лучше сделать так:

2) Используя условие для управления потоком (правый)

public void method() { 
    workA... 
    workA... 
    workA... 
    workA...  
    if(!(conditionIvalid() && notEnoughWhatever() && isWrongMoment())) { 
     //throw new IllegalStateException("No the rigth time"); 
     workB... 
     workB... 
     workB... 
     workB... 

    } 
    workC.... 
    workC.... 
    workC.... 
    workC.... 
} 

И тогда вы можете реорганизовать условие:

if(!(conditionIvalid() && notEnoughWhatever() && isWrongMoment())) { 

для

if(canProceedWithWorkB()) { 

реализован как:

boolean canProceedWithWorkB() { 
     return !(conditionIvalid() && notEnoughWhatever() && isWrongMoment()); 
    } 
1

Использование исключения для управления потоком специально рассматривается в Effective Java, 2-е издание Джошуа Блох, Пункт 57:

Пункт 57: Используйте исключения только для исключительные условия

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

Так что, хотя он, безусловно, «работает», чтобы использовать исключения для управления потоком, не рекомендуется.

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