Java: Как правильно объявить метод интерфейса, который может вызвать исключение? - PullRequest
5 голосов
/ 15 июня 2011

Допустим, у меня есть этот интерфейс A, который реализован несколькими поставщиками:

interface A
{
    void x();
    void y();
}

Однако я хочу, чтобы поставщики могли выдавать исключения, сигнализирующие о том, что что-то не удалось, и потенциально метод может вызвать RuntimeException.В каждом случае код, который вызывает эти методы, должен обработать ошибку и продолжить.Просто потому, что 1 продавец бросает NPE, я не хочу, чтобы система рухнула.Вместо того, чтобы оставлять это на усмотрение человека, вызывающего метод (или, на самом деле, на линии поддержки), я хотел бы убедиться, что каждый вызов будет перехватывать все исключения, объявив каждый метод как:

void x() throws Exception;

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

Позвольте мне прояснить, яЯ ищу решение, в котором вызывающий интерфейс вынужден обрабатывать все исключения (включая RuntimeException s).

Для дальнейшей детализации моей среды все это выполняется в рамках OSGi.Таким образом, каждый поставщик упаковывает свой код в пакет, и OSGi будет обрабатывать все исключения, чтобы предотвратить сбой всей системы.На самом деле я смотрю на интерфейсы сервисов OSGi, которые будут вызываться каким-то ядром.Я хочу убедиться, что, когда я перебираю все сервисы, один сервис не выбрасывает NPE и не останавливает выполняющийся процесс.Я хочу обработать это более изящно, перехватывая все исключения, генерируемые службой, чтобы другие предоставляемые службы все еще управлялись.

Ответы [ 7 ]

7 голосов
/ 15 июня 2011

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

class MySeviceException extends Exception{
    public MySeviceException() {}  
    public MySeviceException(String msg) { super(msg); }  
    public MySeviceException(Throwable cause) { super(cause); }  
    public MySeviceException(String msg, Throwable cause) { super(msg, cause); } 
}

interface A
{
    void x() throws MySeviceExceptionException;
    void y() throws MySeviceExceptionException;
}

Как правило, никогда не перехватывает Errors, всегда лови Exceptions и разбирайся с этим!

2 голосов
/ 15 июня 2011

Продавцы, безусловно, могут добавить RuntimeException к своему сердцу, потому что они непроверены. Это означает, что вам не нужно добавлять предложение throws в интерфейс.

Это также означает, что клиенты не будут получать никаких предупреждений из определения интерфейса, и компилятор не будет принудительно применять требуемый try / catch. Единственный способ, которым они узнают, это прочитать ваш Javadocss.

Вы можете создать пользовательское исключение, расширяющее java.lang.Exception; это проверенное исключение. Вы должны будете добавить это к предложению throws; компилятор будет принудительно использовать методы try / catch; Ваши клиенты должны будут решить проблему.

1 голос
/ 22 июня 2011

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

class MySeviceException extends Exception{
    public MySeviceException() {}  
    public MySeviceException(String msg) { super(msg); }  
    public MySeviceException(Throwable cause) { super(cause); }  
    public MySeviceException(String msg, Throwable cause) { super(msg, cause); } 
}

interface A
{
    void x() throws MySeviceExceptionException;
    void y() throws MySeviceExceptionException;
}

class ABase implements A
{
    public final void x() throws MySeviceExceptionException {
        try {
            doX();
        } catch(RuntimeException ex) {
            throw new MySeviceExceptionException(ex);
        }
    }
    public final void y() throws MySeviceExceptionException {
        try {
            doY();
        } catch(RuntimeException ex) {
            throw new MySeviceExceptionException(ex);
        }
    }

    public abstract void doX() throws MySeviceExceptionException;
    public abstract void doY() throws MySeviceExceptionException;
}
1 голос
/ 15 июня 2011

В зависимости от настроек JVM любой метод может генерировать исключение RuntimeException независимо от того, объявляете ли вы его как генерирующее исключение или нет. Отлов / обработка исключений RuntimeException - это, как правило, плохая практика. Несмотря на то, что в некоторых случаях такое поведение может потребоваться, RuntimeExceptions - это прежде всего показатель того, что с кодом что-то не так, а не использование продукта. Конечно, основным недостатком в обнаружении исключений RuntimeException (особенно, если вы их игнорируете) является то, что в вашей системе могут возникать проблемы, и вы даже не подозреваете, что это происходит ... и вдруг ваша система полностью выплевывает. неверные данные или в противном случае происходит сбой по какой-либо другой причине, что затрудняет поиск основной причины.

См. Руководство Sun / Oracle по поводу исключений

http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

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

1 голос
/ 15 июня 2011

Я согласен с PMD - объявлять, что вы выбрасываете общие Exception s, ужасно. Я думаю, что лучше

  • Определите новые, специфичные для домена классы исключений, не относящиеся к среде выполнения (если встроенные не подойдут; всегда придерживайтесь предварительно определенных классов, если вы соответствуете их семантике), и объявите их в методах, которые могут их выбрасывать
  • Держите исключения времени выполнения к минимуму. Они имеют смысл только тогда, когда у вас нет контроля над тем, как вас зовут, и больше ничего не поделаешь. Если у вас есть основания ожидать, что они будут добавлены в код, который вы вызываете, то поймайте их как можно раньше и перезапустите как стандартные исключения (см. Пункт выше).

Последние версии Java позволяют связывать исключения. Например, если вы получаете NullPointerException ex при синтаксическом анализе File f с внешней библиотекой, вы захотите перехватить его и перебросить как, скажем, new FileParsingException("error parsing " + f + ": " + ex.getMessage(), ex);

1 голос
/ 15 июня 2011

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

Добавление «throws Exception» - плохая идея во многих случаях, но в некоторых случаях это работает.В таких фреймворках, как Struts и JUnit, вы можете без проблем добавить «throws Exception», потому что фреймворк это позволяет.(JUnit не был бы очень полезен, если бы из-за первого возникшего исключения остановился набор тестов.)

Вы могли бы спроектировать систему так, чтобы вызовы кода поставщика происходили в определенных модулях, которые подключаются к системе и имеютобработка исключений, выполняемая системой, аналогично тому, как действия работают в Struts.Каждое действие может выдать что угодно, есть обработчик исключений, который регистрирует, что пошло не так.Таким образом, бизнес-логику, которая вызывает API-интерфейсы вендоров, не нужно будет беспокоить бесполезным образцом для поиска исключений, но если что-то пойдет не так, программа не завершится.

1 голос
/ 15 июня 2011

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...