Об утверждениях и исключениях;Джава - PullRequest
2 голосов
/ 01 февраля 2011

В этих конкретных сценариях утверждения более уместны, чем исключения?

Насколько я понимаю, assert следует использовать, когда программа FUBAR до такой степени, что она не может восстановиться и завершится.

Мне также сказали всегда выдавать исключения для ясности и обработки сообщений об ошибках.

Есть ли тонкая грань между тем, когда использовать каждый? Есть ли пример, где assert должен использоваться вместо исключения безоговорочно?

   public void subscribe(DataConsumer c) throws IllegalArgumentException {
        if (c == null) {
            // Almost certainly FUBAR
            throw new IllegalArgumentException("Can't subscribe null as a DataConsumer. Object not initialized");
        }

        if (dataConsumerList == null) {
            // Definetely FUBAR
            throw new IllegalArgumentException("Nothing to subscribe to. DataConsumerList is null");
        }

        dataConsumerList.add(c);
    }

Ответы [ 4 ]

4 голосов
/ 01 февраля 2011

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

Конечно, утверждение все равно будет выдавать исключение.Если вы абсолютно хотите отключить JVM прямо сейчас , вам нужно использовать что-то вроде Runtime.halt.

Так что я фанат исключенийздесь, хотя я бы обычно использовал NullPointerException, когда ему дан нулевой аргумент, и если dataConsumerList является частью вашего состояния , то я бы лично использовал IllegalStateException для дифференциации этой ситуации.(Жаль, что у Java нет того же ArgmentNullException, что и у .NET, учитывая, что это обычная проверка.)

Гуава имеет полезное Preconditions класс, который позволяет написать это более кратко:

public void subscribe(DataConsumer c) throws IllegalArgumentException {
    Preconditions.checkNotNull(c,
        "Can't subscribe null as a DataConsumer. Object not initialized");
    Preconditions.checkState(dataConsumerList != null,
        "Nothing to subscribe to. DataConsumerList is null");
    dataConsumerList.add(c);
}
1 голос
/ 01 февраля 2011

Общее правило (скопировано с здесь )

утверждения должны защищать от (не всегда очевидных) ошибок разработчик, например используя указатель, несмотря на то, что он равен NULL.

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

И есть лучший способ написания вышеуказанного кода с использованием google-guava Preconditions.checkNotNull () class.

public void subscribe(DataConsumer c) throws IllegalArgumentException 
{
checkNotNull(c, "Can't subscribe null as a DataConsumer. Object not initialized");
checkNotNull(dataConsumerList , "Nothing to subscribe to. DataConsumerList is null");

dataConsumerList.add(c);
}
0 голосов
/ 01 августа 2014

Java technote Программирование с утверждениями содержит эту явную строку в отношении использования :

Не используйте утверждения для проверки аргументов в открытых методах.

Это должен быть довольно четкий ответ на ваш вопрос.

0 голосов
/ 01 февраля 2011

Если вы можете поместить это в английские термины, используйте assert для "gotta" (Got to, Must) и исключения для "otta" (Ought to, must).

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

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

В вашем примере я предполагаю, что нулевой потребитель или пустой список никогда не должны возникать при нормальных обстоятельствах. Если мои предположения верны, то вы можете использовать здесь assert, заявив, что subscribe () с этим справится.

Если мое предположение неверно и произойдет нулевой потребитель, скажем, 1 из 50 раз, бросок будет лучше, и вы заявите, что subscribe () формирует контракт с вызывающим методом, в результате чего вызывающий метод обрабатывает ошибка.

...