Скажем, у меня есть следующий интерфейс Java, который я не могу изменить:
public interface MyInterface {
public void doSomething();
}
И теперь класс, реализовывая его похож на это:
class MyImplementation implements MyInterface {
public void doSomething() {
try {
// read file
} catch (IOException e) {
// what to do?
}
}
}
Я не могу восстановиться с не чтения файла.
Подкласс RuntimeException
может ясно помочь мне, но я не уверен, является ли это правильный поступок: проблема состоит в том, что то исключение не было бы затем зарегистрировано в класс, и пользователь класса возможно получит то исключение знание ничего о решении этого.
Что я могу сделать?
Все мы соглашаемся: интерфейс является дефектным.
Решение я выбрал
Я наконец решил записать a MyVeryOwnInterface
это расширяется MyInterface
и добавляет как часть подписи дефектных методов MyRuntimeException
:
public interface MyVeryOwnInterface extends MyInterface {
public void doSomething() throws MyRuntimeException;
}
class MyImplementation implements MyVeryOwnInterface {
public void doSomething() throws MyRuntimeException {
try {
// read file
} catch (IOException e) {
throw new MyRuntimeException("Could not read the file", e);
}
}
}
Вы столкнулись с проблемой дырявых абстракций . На самом деле хорошего решения не существует, и использование исключения RuntimeException
практически единственное, что вы можете сделать.
Возможно, это также пример того, почему проверенные исключения являются ошибочной концепцией.
Если вы не можете восстановить, чем вы нужно выбросить и, таким образом, обернуть его в RuntimeException или Error и выбросить.
public class Unchecked extends Error {
private final Exception source;
public Unchecked( Exception source) {
this.source = source;
}
public String toString() {
return "Unchecked Exception, Caused by: " + source;
}
public Exception getSource() {
return source;
}
public static Unchecked wrap( Exception cause ) {
return new Unchecked(cause);
}
}
Я бы бросил new IOError (e);
и сообщил о проблеме разработчику интерфейса.
Очевидно, что разработчик интерфейса виноват в том, что не учел возможность отказа doSomething (). В идеале он должен был либо разрешить выброс IOException (если он подозревал, что будет задействован ввод-вывод), либо SomethingException (проверено), которое вы могли бы использовать для обертывания исключения IOException.
Если вам доступен дизайнер интерфейса, поговорите с ним и спросите, что они ожидают от вас в случае сбоя. Может быть, они могут изменить интерфейс: или, может быть, допустимо молча потерпеть неудачу в соответствии с контрактом интерфейса.
Если все это не удается, вы ограничиваетесь выбором: молчание (возможно, запись, но не реагирование на проблему) или выброс RuntimeException, который может завершить процесс.
Я бы посоветовал
throw new RuntimeException("while reading file " + fileName + "...", e);
Разве проблема не в том, что интерфейс вообще не ожидает каких-либо проблем?
(и вы можете создать свое собственное OurCompanyDomainException extends RuntimeException, чтобы его было легко различать в коде на другой стороне интерфейса) .
Я не думаю, что есть что-то делать, кроме как объявить бросает IOException
в интерфейсе.
Это это просто природа интерфейсов Java и проверенных исключений.
В вашем классе может быть другой метод ( doSomethingDangerous
), который генерирует исключение IOException
. В реализации doSomething
вы просто вызываете doSomethingDangerous (заключенный в try / catch), а затем, где бы вы ни пожелали, будьте осторожны с doSomething
, вы вызываете doSomethingDangerous
напрямую.