Почему мы не можем использовать утверждение для открытых методов? - PullRequest
22 голосов
/ 23 марта 2011

Почему мы не можем использовать утверждение для открытых методов?

Я где-то прочитал

"Утверждение неприемлемо в открытых методах, потому что метод гарантирует, что он всегда будет принудительно применятьсяпроверка аргумента. Открытый метод должен проверить свои аргументы, включены ли утверждения. Кроме того, конструкция assert не выдает исключение указанного типа. Он может выдавать только AssertionError ".

Так, разве это не применимо и к частному методу?
Я не совсем понял вышеприведенное утверждение

Ответы [ 11 ]

24 голосов
/ 23 марта 2011

Важным отличием является то, считаете ли вы, что неправильное значение является результатом

a) Программной ошибки, которая должна быть исправлена ​​в коде.

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

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


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

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

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

15 голосов
/ 23 марта 2011

Утверждения не должны использоваться для проверки аргументов в открытых методах по следующим причинам:

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

Пример:

    /**
     * @throws ArithmeticException if divisor is zero
     */ 
    public void int divide(int divisor) {
        if (divisor == 0) {
            throw new ArithmeticException("Cannot divide by zero");
        }
        ...
    }

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

3 голосов
/ 23 марта 2011

В таком виде, как вы говорите, это глупость, я верю.

Конечно, assert не для проверки параметров.

Но в каждой нетривиальной программе есть (или должно быть) несколько инвариантов, и именно здесь утверждения могут пригодиться. Если вы можете выразить инвариант в утверждении, сделайте это, независимо от того, является ли метод общедоступным или нет.

Затем произойдет одно из следующих действий:

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

1 голос
/ 30 июня 2014

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

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

Но то, что вы НИКОГДА не должны делать, это использовать утверждения для проверки АРГУМЕНТОВ открытых методов. Важное различие. Я думаю, что другие ответы здесь уже достаточно ясно объяснили причины, поэтому я не собираюсь ничего повторять.

1 голос
/ 18 мая 2011

Это, вероятно, оригинальный источник из руководства по Java SE "Программирование с утверждениями".

Не используйте утверждения для проверки параметров открытого метода.Утверждение неуместно, потому что метод гарантирует, что он всегда будет принудительно проверять аргументы.Он должен проверить свои аргументы, включены ли утверждения.Кроме того, конструкция assert не выдает исключение указанного типа.Он может выдавать только AssertionError.

Это не запрещает утверждения в открытых методах.Он запрещает их только для проверки аргументов публичного метода.

Утверждения тестовых инвариантов.Класс контролирует фактические аргументы, отправленные его закрытым методам, и может гарантировать инварианты.Класс не управляет фактическими аргументами, отправляемыми в открытые методы, и должен генерировать исключения, если предварительные условия нарушены, даже если утверждения отключены.

Подробнее о том, когда использовать утверждения, можно узнать здесь .

1 голос
/ 16 мая 2011

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

Суть в том, что вы должны делать или нет.Я сам прекрасно понимаю реакцию других людей о том, когда вы должны или не должны использовать утверждение.

Но я должен признать, что НИКОГДА не использую утверждения и что я редко, если когда-либо вижу утверждения в коде.Я работал всего несколько лет, но в 4 совершенно разных компаниях, в которых я работал, не было никаких утверждений в коде.Будь то веб-приложение с кодом более 10 миллионов строк для бронирования рейсов, центр управления космическим кораблем, программное обеспечение для управления гипермаркетом или система отслеживания ошибок.Никто из них не использовал утверждения.У всех компаний были разные потребности и методы.Никто не использовал утверждения.

Для меня причина проста.Люди здесь говорят, что утверждения для отладки.Все в порядке.И что вы можете отключить их для повышения скорости.Это тоже хорошо ... Сначала.Чем сложнее программа, тем больше времени проходит отладка.И некоторые ошибки, даже при 100% покрытии кода, даже при обширной интеграции и проверочном тестировании, вы найдете их только в производстве.Просто потому, что ваши пользователи используют ваше приложение чаще, чем вы.И они не будут использовать его так же, как вы.

Это забавно, потому что в производственных журналах мы постоянно видим следы стека из кода, подобного следующему:

catch (MyException e) {
  logger.war("This should never happen",e);
}

Это означает, что вы никогда не знаете, что может произойти в работе.

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

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

Важно то, что в тот или иной день какой-то пользователь будет делать то, что выдает предупреждение.Будь то из-за плохо написанного кода или чего-то еще, вы увидите это.А это значит, что вместо того, чтобы тратить 2 дня на выяснение, почему, черт возьми, программа ведет себя так странно, вы сможете использовать полную трассировку стека в начальной точке и исправить проблему за 2 часа.

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

1 голос
/ 23 марта 2011

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

1 голос
/ 23 марта 2011

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

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

public void update(Object o) {
   int nUpdatedObjects = dao.update(o);
   assert(nUpdatedObjects == 1)
}

В этом случае он обслуживает validate слой dao по принципу fail fast .

0 голосов
/ 14 марта 2017

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

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

Теперь у вас может возникнуть вопрос: зачем использовать утверждения для проверки значений аргументов приватного метода?

Ну, причина в том, что приватные методы могут быть вызваны из класса, который он определил (Либо изметод экземпляра или из статического метода main). Разработчик класса infact знает все о закрытом методе - что он делает, как его вызывать и какие значения параметров передавать. Значения аргументов закрытого метода можно безопасно проверять с помощью assertИоны.

0 голосов
/ 18 мая 2011

Этот запрет распространяется только на общедоступные интерфейсы.

С http://download.oracle.com/javase/6/docs/technotes/guides/language/assert.html#preconditions:

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

По сути, соглашение заключается в том, что публичные интерфейсы гарантируют проверку предварительных условий и генерируют конкретные исключения вместо AssertionError.

Для всех остальных случаев утверждения очень ценны и являются краеугольным камнем для «программирования по контракту». См. http://java.sun.com/developer/technicalArticles/JavaLP/assertions для хорошего введения.

  1. У Java есть неконтролируемые исключения по определенной причине - это множество катастрофических сбоев, которые обычно не должны обнаруживаться. Любое выделение памяти может выбрасывать OutOfMemoryError. Неудачное утверждение (ошибка в клиентском коде, который предоставил неверный аргумент нашему API) не менее катастрофично.

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

  3. Единственное, что следует учитывать в утверждениях, - это контракт производительности ваших интерфейсов. Обратите внимание, что это также может быть «неявный» контракт (т. Е. Когда очевидная реализация должна быть очень быстрой, выделение минуты не входит в подразумеваемый контракт на исполнение). Поэтому убедитесь, что проверка ваших утверждений приемлема по исполнению договора.

...