Возвращение проверенных исключений - PullRequest
2 голосов
/ 29 декабря 2010
public void foo() {
 begin();
 try {
  ...
  commit();
 } catch (Exception e) {
  rollback();
  throw e;
 }
}

В приведенном выше примере есть ошибка, потому что foo не имеет throws Exception. Добавление этого также не принесет пользы юзабилити метода.

Какой лучший способ сделать это? Как вы что-то делаете, если ошибка происходит без «обработки» ошибки?

Ответы [ 9 ]

6 голосов
/ 29 декабря 2010

На ум приходит как минимум два подхода, которые обычно будут объединены в зависимости от того, что вы хотите foo сделать:

1.Поймать и отбросить только соответствующие исключения

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

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

2.Совсем не поймайте исключение

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

// Signature changes to include any exceptions that really can be thrown
public void foo() throws XYZException, ABCException {
 // A flag indicating that the commit succeeded
 boolean done = false;

 begin();
 try {
  // Don't have any `return` statements in here (or if you do,
  // set `done` to `true` first)

  ...
  commit();
  done = true; // Commit didn't throw an exception, we're done
 } finally {
  // finally clause always happens regardless
  if (!done) {
    // We must be processing an exception; rollback
    try {
      rollback();
    } catch (Exception e) {
      // quash it (e.g., leave this block empty), we don't want
      // to mask the real exception by throwing a different one
    }
  }
 }
}

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

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

5 голосов
/ 29 декабря 2010

Начиная с Java 8 мы используем

/**
 * Cast a CheckedException as an unchecked one.
 *
 * @param throwable to cast
 * @param <T> the type of the Throwable
 * @return this method will never return a Throwable instance, it will just throw it.
 * @throws T the throwable as an unchecked throwable
 */
@SuppressWarnings("unchecked")
public static <T extends Throwable> RuntimeException rethrow(Throwable throwable) throws T {
    throw (T) throwable; // rely on vacuous cast
}

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

public void foo() throws MyCheckedException {
 begin();
 try {
  ...
  commit();
 } catch (Exception e) {
  rollback();
  // same as throwing an exception without the compiler knowing.
  Thread.currentThread().stop(e); 
 }
}

Перед использованием stop () вы должны прочитать http://download.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

Thread.currentThread (). Stop (e) .. поведенчески идентичен операции броска Java, но обходит попытки компилятора гарантировать, что вызывающий метод объявил все проверенные исключения, которые он может выбросить:

3 голосов
/ 29 декабря 2010

Оберните это с некоторой RuntimeException, которая не проверена.

1 голос
/ 29 декабря 2010

Добавление, которое не принесло бы пользы для метода, также очень хорошо.

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

Также см.

0 голосов
/ 24 ноября 2015

Стоит упомянуть некоторые достижения в этой области.

Во-первых, в Java 7 возможно перехватывать и генерировать универсальные исключения, если то, что объявлено внутри блока try, перехвачено или объявлено во внешнем блоке.,Таким образом, это скомпилирует:

void test() throws SQLException {
  try { 
    conn.commit();
  } catch (Throwable t) {
    // do something
    throw t;
  }
}

Это хорошо объяснено здесь: http://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html


Другой способ описан здесь: http://blog.jooq.org/2012/09/14/throw-checked-exceptions-like-runtime-exceptions-in-java/

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

try {
  do_operation
  flag_success
} catch (Throwable e) {
  flag_error
  throw e;
}

с использованием метода:

public static void wrapExec(RunnableT s) {
    try {
        s.run();
        flag_success
    } catch (Throwable t) {
        flag_error
        doThrow(t);
    }
}

и, следовательно, заменить весь блок try / catch на

wrapExec(()->{do_operation})
0 голосов
/ 29 декабря 2010

Здесь вы случайно столкнулись с одним из самых больших религиозных расколов на Яве (если не шире) - миром. Это сводится к тем, кто считает, что, как кажется TJ, и я тоже, что проверенные исключения являются ценными по многим причинам, школа VS Rod Johnson / Spring, которая при разработке Java проверяла исключения, использовалась во многих случаях, когда не следует, скажем, закрывать результирующий набор или сокет, поэтому, поскольку он использовался во многих случаях неправильно, он делает их бесполезными, поэтому все исключения следует проверять. В среде Spring есть много классов, которые являются очень тонкими обертками вокруг стандартных объектов Java, но преобразуют проверенные исключения в непроверенные. Это сводит меня с ума!

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

0 голосов
/ 29 декабря 2010

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

0 голосов
/ 29 декабря 2010

вы можете выбросить подкласс RuntimeException - они не требуют catch ()

0 голосов
/ 29 декабря 2010

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

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

...