Почему 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));

Ссылки:

Другие вопросы по тегам