В чем смысл Guava checkNotNull
Я довольно новичок в Guava (давайте будем честными, я не "довольно новый", я полный новичок на эту тему), и поэтому я решил пройти через некоторую документацию и был очень удивлен, читая это:
com.google.common.base.Preconditions.checkNotNull(...)
Я не понимаю смысла этого метода. Это означает, что вместо того, чтобы делать :
myObject.getAnything();
(что может привести к NullPointerException
Если myObject равен null)
Я должен используйте
checkNotNull(myObject).getAnything();
, который будет бросить NullPointerException
Если myObject
имеет значение null и возвращает myObject
если это не null.
я озадачен, и это может быть глупый вопрос, но ...
какой в этом смысл? Эти две линии делают то же самое, что и для результатов, учитывая любые ситуации, которые я могу придумать.
Я даже не думаю, что последнее является более читаемым.
значит, я что-то упустил. Что это?
3 ответа:
идея в том, чтобы потерпеть неудачу быстро. Например, рассмотрим этот глупый класс:
public class Foo { private final String s; public Foo(String s) { this.s = s; } public int getStringLength() { return s.length(); } }
допустим, вы не хотите разрешать нулевые значения для
s
. (или жеgetStringLength
будет бросать NPE). С классом как есть, к тому времени, когда вы поймаете этоnull
, уже слишком поздно -- очень трудно выяснить, кто его туда положил. Преступник вполне может быть в совершенно другом классе, и этоFoo
экземпляр мог быть построен уже давно. Теперь вам нужно прочесать свою базу кода, чтобы узнайте, кто мог бы поставитьnull
есть значение.вместо этого представьте себе этот конструктор:
public Foo(String s) { this.s = checkNotNull(s); }
теперь, если кто-то ставит
null
там, вы узнаете сразу -- и у вас будет трассировка стека, указывающая вам точно на вызов, который пошел не так.
в другой раз это может быть полезно, если вы хотите проверить аргументы, прежде чем предпринимать действия, которые могут изменить состояние. Например, рассмотрим этот класс это вычисляет среднее значение всех длин строк, которые он получает:
public class StringLengthAverager { private int stringsSeen; private int totalLengthSeen; public void accept(String s) { stringsSeen++; totalLengthSeen += s.length(); } public double getAverageLength() { return ((double)totalLengthSeen) / stringsSeen; } }
вызов
accept(null)
приведет к тому, что NPE будет брошен - но не раньшеstringsSeen
был увеличен. Это может быть не то, что вы хотите; как пользователь класса, я могу ожидать, что если он не принимает null, то его состояние должно быть неизменным, если вы передаете null (другими словами: вызов должен завершиться неудачей, но он не должен аннулировать объект). Очевидно, что в этом примере вы также можете исправить это, получивs.length()
перед приращениеstringsSeen
, но вы можете увидеть, как для более длинного и более сложного метода может быть полезно сначала проверить, что все ваши аргументы действительны, и только затем изменить состояние:public void accept(String s) { checkNotNull(s); // that is, s != null is a precondition of the method stringsSeen++; totalLengthSeen += s.length(); }
myObject.getAnything();
(что может вызвать исключение NullPointerException, если myObject равен null)нет... это будет бросьте NPE всякий раз, когда
myObject == null
. В Java нет возможности вызвать метод с помощьюnull
приемник (теоретическим исключением являются статические методы, но они могут и должны быть всегда вызывается без объекта).
Я должен использовать
checkNotNull(myObject).getAnything();
нет, вы не должны. Это было бы скорее избыточный (обновление).
вы должны использовать
checkNotNull
для того чтобы не быстро. Без него вы можете пройти нелегальныйnull
другой метод, который передает его дальше, и так далее и так далее, где он окончательно терпит неудачу. Тогда вам может понадобиться некоторая удача, чтобы узнать, что на самом деле самый первый метод должен был отказатьсяnull
.
в ответе yshavit упоминается важный момент: передача незаконного значения плоха, но хранение его и передав его позже еще хуже.
обновление
на самом деле
checkNotNull(myObject).getAnything()
также имеет смысл, поскольку вы четко выражаете свое намерение не принимать никаких нулей. Без него, кто-то может подумать, что вы забыли чек и преобразовать его в нечто вроде
myObject != null ? myObject.getAnything() : somethingElse
OTOH, я не думаю, что чек стоит многословия. В лучше язык, система типов будет рассматривать возможность обнуления и даст нам некоторый семантический сахар как
myObject!!.getAnything() // checkNotNull myObject?.getAnything() // safe call else null myObject?.getAnything() ?: somethingElse // safe call else somethingElse
для nullable
myObject
, в то время как стандартный синтаксис точки будет разрешен только тогда, когдаmyObject
как известно, быть не-null.
Я прочитал всю эту тему несколько минут назад. Тем не менее, я был смущен, почему мы должны использовать
checkNotNull
. Затем просмотрите предварительный класс doc of Guava, и я получил то, что ожидал. Чрезмерное использованиеcheckNotNull
определенно ухудшит производительность.моя мысль
checkNotNull
метод стоит требуется для проверка данных, которая поступает от пользователя напрямую или очень конец API для взаимодействия с пользователем. Он не должен использоваться в каждом методе внутреннего API, потому что использование это вы не можете остановить исключение, а исправить свой внутренний API, чтобы избежать исключения.согласно DOC:ссылке
С помощью checkNotNull:
public static double sqrt(double value) { Preconditions.checkArgument(value >= 0.0, "negative value: %s", value); // calculate the square root }
предупреждение о производительности
цель этого класса-улучшить читаемость кода, но в некоторых обстоятельства это может привести к значительным затратам на производительность. Помните, что значения параметров для сообщения строительство должно быть все вычисляется с нетерпением, и автобоксинг и создание массива varargs может произойти также, даже когда проверка предварительного условия затем завершается успешно (как и должно почти всегда делаю в производстве). В некоторых обстоятельствах эти впустую Циклы процессора и распределения могут добавить до реальной проблемы. Проверки предварительных условий с учетом производительности всегда можно преобразовать в обычная форма:
if (value < 0.0) { throw new IllegalArgumentException("negative value: " + value); }