Есть ли способ применить логический предикат к набору свойств объекта в Java - PullRequest
0 голосов
/ 14 декабря 2018

Мне интересно, есть ли более элегантный способ кодирования следующего, который использует некоторую комбинацию потоков, лямбда-выражений и ссылок на методы:

final boolean valid = StringUtils.hasText(obj.getFirstName())
                && StringUtils.hasText(obj.getLastName())
                && StringUtils.hasText(obj.getGender())
                && StringUtils.hasText(obj.getDob());

В идеале это будет выглядеть примерно так:

final boolean valid =
       something(StringUtil::hasText, 
                 obj.getFirstName(),
                 obj.getLastName(),
                 obj.getGender(),
                 obj.getDob());

Или, возможно:

final boolean valid =
       something(StringUtil::hasText, obj,
                 Type::getFirstName(),
                 Type::getLastName(),
                 Type::getGender(),
                 Type::getDob());

Очевидно, что вы можете поместить все геттеры в список и затем использовать поток, но это выглядит очень многословно.Мне кажется, что может быть библиотечная функция, которая делает что-то подобное, либо в JRE, либо, возможно, в Spring или Apache.

Ответы [ 2 ]

0 голосов
/ 14 декабря 2018

Использование чего-либо еще, кроме вашего нынешнего подхода, только ухудшает ситуацию.Даже если вы создадите метод для выполнения логики «и» с учетом некоторых аргументов ввода, вы в конечном итоге получите тот же объем кода, если не больше, и определенно будете менее дружелюбны к памяти.

Вы можете использовать allMatch, как предложено в комментариях:

Stream.of(obj.getFirstName(), obj.getLastName(), obj.getGender(), obj.getDob())
      .allMatch(StringUtils::hasText)

, но, как вы можете видеть, это гораздо сложнее и менее читабельно.

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

0 голосов
/ 14 декабря 2018

Я бы написал метод, который принимает функции предиката и геттера:

static <T> boolean validate(Predicate<String> condition, T object, 
        Function<T, String>... functions) {

    boolean res = true;

    for(Function<T, String> f: functions) {
        res &= condition.test(f.apply(object));

        if(!res) return false;
    }

    return res;
}

И использовал бы его следующим образом:

boolean allValid = validate(StringUtils::hasText, myObject, 
        MyClass::getFirstName, MyClass::getLastName, MyClass::getGender);

Конечно, Function<T, String> может потребоватьсяизменить на Function<T, Object>, если hasText принимает Object.

...