Почему checkArgument предусловий Google Guava не возвращает значение?
Мне очень нравится, как библиотека guava допускает простые однострочные символы для проверки на null:
public void methodWithNullCheck(String couldBeNull) {
String definitelyNotNull = checkNotNull(couldBeNull);
//...
}
к сожалению, для простой проверки аргументов вам нужно как минимум две строки кода:
public void methodWithArgCheck(String couldBeEmpty) {
checkArgument(!couldBeEmpty.isEmpty());
String definitelyNotEmpty = couldBeEmpty;
//...
}
однако можно добавить метод, который мог бы выполнять проверку аргумента и возвращать значение, если проверка прошла успешно. Ниже приведен пример проверки и как она может быть реализована:
public void methodWithEnhancedArgCheck(String couldBeEmpty) {
String definitelyNotEmpty = EnhancedPreconditions.checkArgument(couldBeEmpty, !couldBeEmpty.isEmpty());
//...
}
static class EnhancedPreconditions {
public static <T> T checkArgument(T reference, boolean expression) {
if (!expression) {
throw new IllegalArgumentException();
}
return reference;
}
}
Мне просто было интересно, что это за дизайн и стоит ли ставить функцию запроса на это.
РЕДАКТИРОВАТЬ: @Nizet, да, проверки в методах может быть неуклюжим. Однако проверка в конструкторах на наличие нулей выглядит действительно хорошо и экономит много времени, затрачиваемого на отладку NPE:
public class SomeClassWithDependency {
private final SomeDependency someDependency;
public SomeClassWithDependency(SomeDependency someDependency) {
this.someDependency = checkNotNull(someDependency);
}
//...
РЕДАКТИРОВАТЬ: Принимая ответ Низет, потому что я согласен с ним о побочных эффектах и обоснованности согласованности. Также, если вы посмотрите на комментарий Xaerxess, похоже, что это вызывает путаницу среди других разработчиков.
3 ответа
Я никогда не понимал, почему checkNotNull()
возвращает свой аргумент в первую очередь:
public void foo(String bar) {
Preconditions.checkNotNull(bar);
// here, you're sure that bar is not null.
// No need to use another variable or to reassign bar to the result
// of checkNotNull()
}
Я лично игнорирую результат checkNotNull()
, как указано выше. И это делает вещи совместимыми с другими проверками, которые возвращают пустоту.
Единственное преимущество, которое я вижу, заключается в том, что вы можете сделать что-то подобное, но я считаю, что это менее читабельно, чем в двух отдельных строках:
public String trim(String bar) {
return Preconditions.checkNotNull(bar).trim();
}
Короче говоря, я согласен с вами, что API несколько противоречив, но я бы предпочел, чтобы все методы возвращали void. Метод должен либо иметь побочный эффект, либо возвращать что-то, но, как правило, следует избегать использования того и другого. Здесь целью метода является побочный эффект: создание исключения.
РЕДАКТИРОВАТЬ:
Ваш пример действительно является более правильным объяснением того, почему возвращение аргумента полезно. Но я бы все же предпочел последовательность и чистоту вместо этой возможности проверки и назначения в одну строку.
Самая большая причина, по которой checkNotNull
возвращает аргумент, так что он может быть использован в конструкторах, например так:
public Foo(Bar bar) {
this.bar = checkNotNull(bar);
}
Но главная причина того, что checkArgument
не делает ничего подобного, это то, что вам все равно придется передавать аргумент отдельно, и это просто не стоит, особенно с более сложными проверками предварительных условий, которые иногда могут быть более читабельными в своей собственной строке. То, что что-то может быть однострочным, не означает, что так должно быть, если это не повышает читабельность.
Вместо этого вы можете использовать valid4j с hamcrest-matchers (в Maven Central он указан как org.valid4j:valid4j)
Для предварительных условий и постусловий:
import static org.valid4j.Assertive.*;
this.myField = require(argument, notNullValue());
this.myInteger = require(x, greaterThan(0));
...
return ensure(result, isValid());
Для проверки ввода:
import static org.valid4j.Validation.*;
validate(argument, isValid(), otherwiseThrowing(InvalidException.class));
Ссылки: