#java #exception
#java #исключение
Вопрос:
У меня есть повторяющиеся исключения, которые необходимо создавать из-за использования reflect API для целей рефакторинга:
throws ApiException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException
Эти исключения всегда присутствуют в методе, в котором я использую переработанные методы, возможно ли это сделать
что-то вроде этого вместо:
throws CustomException
для обработки всех исключений, упомянутых выше?
Спасибо
Комментарии:
1. конечно, это так. просто перехватите все вышеперечисленное и в блоке catch создайте свое CustomException
2. Взгляните на
Exception
конструкторы, которые уже предоставляют средства для переноса / вложения любого исключения в другое. Конечно, тот, кто перехватит ваше исключение, должен будет распаковать их, чтобы получить больше информации.
Ответ №1:
ДА. Есть два способа сделать это:
Иерархии классов
Это применимо только в том случае, если исключения разрабатываете вы. Если это не описывает этот случай, переходите к следующей главе.
Если у вас есть, скажем, API аутентификации пользователя, вы, вероятно, захотите создать целый набор исключений, таких как UserNotFoundException
, IncorrectPasswordException
, UserFrozenException
, IpBlockedException
и многое другое.
Если вы убедитесь, что все эти исключения расширяют один тип исключения ( AuthenticationException
), вот так:
public class AuthenticationException extends Exception {
public AuthenticationException(String msg, Throwable cause) {
super(msg, cause);
}
public AuthenticationException(String msg) {
super(msg);
}
}
public class UserNotFoundException extends AuthenticationException {
public UserNotFoundException(String username) {
super(username);
}
}
// and so on
тогда вызывающий может выбирать, вот почему это создает такой отличный дизайн API.
ЕСЛИ вызывающему абоненту необходимо иметь пользовательские реакции в зависимости от того, какая проблема с аутентификацией возникает, они могут перехватить, скажем, UserNotFoundException
. Но если им все равно, они могут перехватить AuthenticationException
.
Обратите внимание, что сама Java тоже это делает. GeneralSecurityException является общим суперклассом, и все же большинство методов, связанных с безопасностью, выдают значительный список подклассов этого, так что вызывающие пользователи точно знают, какие ошибки могут возникнуть, и могут писать обработчики для конкретных ошибок, не заставляя их писать тонну блоков catch, если они этого не хотят.
повторное перемещение
Альтернативное решение заключается в том, что вы объединяете исключения в свой собственный пользовательский тип.
Для этого сначала напишите исключение (или используйте существующее, но это редко бывает правильным со стилистической точки зрения). Затем напишите блок catch и перенесите все эти странные, не связанные исключения в это вновь созданное, убедившись, что используется система ’cause’:
public class CustomException { // find a better name
public CustomException(String msg, Throwable cause) {
super(msg, cause);
}
public CustomException(String msg) {
super(msg);
}
public CustomException(Throwable cause) {
super(cause);
}
}
public void myMethod() throws CustomException {
try {
// code here
} catch (ApiException | ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
throw new CustomException(e);
} catch (InvocationTargetException e) {
throw new CustomException(e.getCause();
}
}
но обратите внимание, как ваше предложение о том, что вы просто хотите запустить и забыть, вызывает проблемы с дизайном вашего API. Например, обертывание InvocationTargetException подобным образом довольно враждебно по отношению к вашим потребителям API; InvocationTargetException само по себе является оболочкой, так что теперь у вас есть wrappers-in-wrappers-in-wrappers, и это просто уродливо, и вызывающему коду очень сложно даже пытаться решать проблемы точечным способом. На самом деле нет простого способа прочитать используемые вами API и понять, почему он выдает различные исключения, которые он выдает.
ПРИМЕЧАНИЕ: Если вы можете, решение с иерархией классов — гораздо лучший способ сделать это; но для этого требуется, чтобы вы контролировали код, который их генерирует.
Ответ №2:
Предположим, у вас есть:
void myMethod() throws ApiException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
/// Your code here;
}
Вы можете изменить его с помощью:
void myMethod() throws CustomException {
try {
/// Your code here;
} catch (ApiException | ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new CustomException(e); // Make sure to have constructor initialized with cause.
}
}
Например, класс CustomException:
public class CustomException {
CustomException(Throwable cause) {
super(cause);
}
}
Ответ №3:
ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException
являются ли все подклассы ReflectiveOperationException
, поэтому вы можете просто уменьшить список исключений:
throws ApiException, ReflectiveOperationException
Если вы хотите объединить эти 2 в CustomException
, просто создайте одно и используйте его:
public class CustomException extends Exception {
private static final long serialVersionUID = -1006015659738896046L;
public CustomException(Exception e) {
super(e);
}
public CustomException(String msg, Exception e) {
super(msg, e);
}
}
void foo() throws CustomException {
try {
// your code here
} catch (ApiException | ReflectiveOperationException e) {
throw new CustomException(e);
}
}
Если вам даже не нужно throws CustomException
, потому что вы знаете, что вызывающий объект никогда специально не поймает его, измените класс исключения на CustomException extends RuntimeException
.