Чи можу я зафіксувати декілька винятків Java в одній і тій же статті лову?


701

У Java я хочу зробити щось подібне:

try {
    ...     
} catch (/* code to catch IllegalArgumentException, SecurityException, 
            IllegalAccessException, and NoSuchFieldException at the same time */) {
   someCode();
}

...замість:

try {
    ...     
} catch (IllegalArgumentException e) {
    someCode();
} catch (SecurityException e) {
    someCode();
} catch (IllegalAccessException e) {
    someCode();
} catch (NoSuchFieldException e) {
    someCode();
}

Чи можна це зробити?

Відповіді:


1132

Це можливо з Java 7 . Синтаксис блоку з декількома ловами:

try { 
  ...
} catch (IOException | SQLException ex) { 
  ...
}

Однак пам’ятайте, що якщо всі винятки належать до однієї ієрархії класів, ви можете просто впізнати цей базовий тип виключення.

Також зауважте, що ви не можете зафіксувати і ExceptionA, і ExceptionB в одному блоці, якщо ExceptionB успадковується від ExceptionA, прямо чи опосередковано. Компілятор скаржиться:

Alternatives in a multi-catch statement cannot be related by subclassing
  Alternative ExceptionB is a subclass of alternative ExceptionA

81
TT - навіщо перевизначати оператор bitwise or( |)? Чому б не скористатися комою або оператором, який має більш подібне значення, logical or( ||)?
ArtOfWarfare

11
@ArtOfWarfare Можливо, вони думали, що це вже не матиме значення після того, як вони вже придумали синтаксис для декількох меж для дженериків.
JimmyB

12
Знак XOR (I) не те саме, що АБО (||), A | B означає або A, або B, але не обидва A || B означає або A, або B, або обидва, так як для винятків це винятокA або винятокB, але не обидва одночасно. тому вони використовували XOR sing замість АБО, і ви ясно бачите, коли виняток - це кидки, якщо ви помістите 2 винятки, один з них є
підтипом

41
@ user1512999 в Java, побітовий XOR є ^ (карета), а побітовий АБО | (труба) docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
Льюїс Баумстарк

6
Варто згадати, що тип винятку, що потрапляє в блок з кількома уловками, евакуюється до найпоширенішого загального батька
yanpas

104

Не зовсім перед Java 7, але я б зробив щось подібне:

Java 6 і раніше

try {
  //.....
} catch (Exception exc) {
  if (exc instanceof IllegalArgumentException || exc instanceof SecurityException || 
     exc instanceof IllegalAccessException || exc instanceof NoSuchFieldException ) {

     someCode();

  } else if (exc instanceof RuntimeException) {
     throw (RuntimeException) exc;     

  } else {
    throw new RuntimeException(exc);
  }

}



Java 7

try {
  //.....
} catch ( IllegalArgumentException | SecurityException |
         IllegalAccessException |NoSuchFieldException exc) {
  someCode();
}

11
Зауважте, що ваш приклад Java 6 порушує здатність компілятора розповідати, що буде викинуто звідки.
MichaelBlume

2
@MichaelBlume Правда, що не [так] погано. Ви завжди можете отримати оригінальний виняток за допомогою exc.getCause(). Як бічна примітка, Роберт К. Мартін (серед інших) рекомендує використовувати вивірені винятки (компілятор не має уявлення про те, який виняток буде викинутий звідти); див. Розділ 7: Поводження з помилками у книзі « Чистий код» .
користувач454322

4
Чи не у вашому прикладі Java 6 не слід перезавантажувати вихідний виняток, а не створювати новий екземпляр винятку, тобто throw excзамість throw new RuntimeException(exc)?
Девід Демар

5
Це досить погана практика з точки зору читабельності.
Rajesh J Advani

3
Екземпляр роботи трохи затратний, краще уникати якомога більше.
Парамеш Корракуті

23

В межах Java 7 ви можете визначити декілька застережень, як:

catch (IllegalArgumentException | SecurityException e)
{
    ...
}

16

Якщо є ієрархія винятків, ви можете використовувати базовий клас для лову всіх підкласів винятків. У виродженому випадку ви можете спіймати всі винятки Java за допомогою:

try {
   ...
} catch (Exception e) {
   someCode();
}

У більш поширеному випадку, якщо RepositoryException є базовим класом, а PathNotFoundException є похідним класом, то:

try {
   ...
} catch (RepositoryException re) {
   someCode();
} catch (Exception e) {
   someCode();
}

Вищевказаний код охоплює RepositoryException і PathNotFoundException для одного виду обробки винятків, а всі інші винятки об'єднуються разом. Оскільки Java 7, відповідно до відповіді @ OscarRyz вище:

try { 
  ...
} catch( IOException | SQLException ex ) { 
  ...
}

7
Клаузи BTW-лову обробляються для того, щоб, якщо ви поставили батьківський клас виключень перед дочірнім класом, він ніколи не викликається, наприклад: спробуйте {...} catch (Виняток e) {someCode (); } catch (RepositoryException re) {// ніколи не дійшов}
Майкл Шопсін

4
Насправді саме тому, що його ніколи не можна досягти, такий код навіть не компілюється.
полігенмастильні матеріали

15

Ні, по одному на клієнта.

Ви можете зловити суперклас, наприклад, java.lang.Exception, якщо ви будете вживати однакових дій у всіх випадках.

try {
    // some code
} catch(Exception e) { //All exceptions are caught here as all are inheriting java.lang.Exception
    e.printStackTrace();
}

Але це може бути не найкращою практикою. Виключення слід виловлювати лише тоді, коли у вас є стратегія фактичного поводження з нею - а реєстрація та повторне скидання - це не «обробка з нею». Якщо ви не маєте коригувальних дій, краще додайте їх до підпису методу та дозвольте комусь, хто може впоратися із ситуацією.


20
Чи можу я просити вас перефразувати частину про зловлення java.lang.Exception? Я усвідомлюю, що це приклад, але я відчуваю, що деякі люди можуть прочитати цю відповідь і сказати: «О, добре, тоді я просто спіймаю Виняток», коли це, мабуть, не те, що вони хочуть (або повинні) робити.
Роб Грушка

2
Я знав про це, але не хочу цього робити ... О, добре, здогадуюсь, я застряг із 4 уловами тоді, до наступної версії Java ...
froadie

@duffymo: Що не так із реєстрацією та повторним кроком? За винятком того, що він захаращує код, його еквівалент не ловити його, чи не так. З точки зору загальної стратегії поводження з помилками. Що погано - це ведення журналів, а не повторне викидання.
Френк Остерфельд

5
Я не вважаю ведення журналів і повторне викидання поводження ні з чим. Я вважаю за краще пускати це до того, хто може зробити щось значиме. Цей останній шар, де винятки ніколи не повинні виходити (наприклад, контролери у веб-програмі), повинен бути тим, хто записує помилку в цьому випадку.
duffymo

Чи я єдиний, хто вважає абсурдним, що журнал не генерується автоматично для мене? Здається, що всі ми повинні писати одне і те ж дурне повідомлення про реєстрацію кожного разу, коли якийсь фрагмент коду може призвести до виключення.
ArtOfWarfare

10

Більш чиста (але менш багатослівна і, можливо, не бажана) альтернатива відповіді user454322 на Java 6 (тобто Android) - це зловити всіх Exceptions і повторно кинути RuntimeExceptions. Це не спрацює, якщо ви плануєте витягувати інші типи винятків далі в стек (якщо ви також не перекинете їх повторно), але буде ефективно фіксувати всі перевірені винятки.

Наприклад:

try {
    // CODE THAT THROWS EXCEPTION
} catch (Exception e) {
    if (e instanceof RuntimeException) {
        // this exception was not expected, so re-throw it
        throw e;
    } else {
        // YOUR CODE FOR ALL CHECKED EXCEPTIONS
    } 
}

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


1
Такий підхід заважає компілятору визначати, чи буде "блок захоплення" доступним чи ні.
the_new_mr

3

Як і раніше: 7

  Boolean   caught = true;
  Exception e;
  try {
     ...
     caught = false;
  } catch (TransformerException te) {
     e = te;
  } catch (SocketException se) {
     e = se;
  } catch (IOException ie) {
     e = ie;
  }
  if (caught) {
     someCode(); // You can reference Exception e here.
  }

3
буде приємним рішенням. Як щодо того, щоб вставити остаточний елемент управління caughtв finallyблок?
Andrea_86

Для цього потрібно більше рядків, ніж оригінальне запитання.
Леандро Глоссман

1

Так. Ось спосіб використання трубного (|) сепаратора,

try
{
    .......
}    
catch
{
    catch(IllegalArgumentException | SecurityException | IllegalAccessException | NoSuchFieldException e)
}

Що це за стиль коду? Блок лову в пробний блок?
Сем

1

Для Kotlin наразі це неможливо, але вони розглядали, як додати його: Джерело
Але поки що лише невелика хитрість:

try {
    // code
} catch(ex:Exception) {
    when(ex) {
        is SomeException,
        is AnotherException -> {
            // handle
        }
        else -> throw ex
    }
}

0

Ловіть виняток, який трапляється з батьківським класом в ієрархії винятків. Це, звичайно, погана практика . У вашому випадку загальним батьківським винятком є ​​клас винятку, і вилов будь-якого винятку, який є екземпляром винятку, насправді є поганою практикою - винятки, такі як NullPointerException, як правило, є помилками програмування, і зазвичай їх слід усунути шляхом перевірки нульових значень.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.