以简洁的方式在 java8 谓词中记录条件结果

Logging the conditional outcome in java8 Predicate in a concise manner

我有这样的代码:

Predicate<String> notNull = input -> (input != null);
Predicate<String> notEmpty = input -> (input.trim().length() > 0);

我的验证器方法正在使用它,如下所示:

public boolean isInputValid(String input){
    return (notNull.and(notEmpty)).test(input);
}

每当我调用 isInputValid(<myInputString>) 方法时,它会 return 我是真还是假,但是,如果我想记录哪个条件完全失败,我怎么能在 Java8 中做到这一点无需将我的 Predicates notNull 和 notEmpty 转换为方法。

下面将 Predicate notNull 转换为方法的示例将实现我记录输入问题的目标,但它太冗长了。有 better/more-concise 的方法吗?

private Predicate<String> notNull(){
    return input -> {
        if(input == null){
            log.warn("NULL input");
            return false;
        }
        return true;
    };
}

对此没有内置解决方案,但您可以创建自定义可记录谓词来完成这项工作。

@FunctionalInterface
interface LPredicate<T> extends Predicate<T>{
    default boolean testAndLog(T t, String prefix){
        boolean result = this.test(t);
        if(!result){
            log.warn(prefix + " " + t);
        }
        return result;
    }
}

完整的可测试代码

import java.util.function.Predicate;

public class FunctionLog {
    static MLog log = new MLog();

    @FunctionalInterface
    interface LPredicate<T> extends Predicate<T>{
        default boolean testAndLog(T t, String prefix){
            boolean result = this.test(t);
            if(!result){
                log.warn(prefix + " " + t);
            }
            return result;
        }
    }

    static LPredicate<String> notNull = input -> (input != null);
    static LPredicate<String> notEmpty = input -> (input.trim().length() > 0);  

    public static void main(String[] args) {        
        System.out.println("Case1: " + isInputValid(""));
        System.out.println("Case2: " + isInputValid(null));
        System.out.println("Case3: " + isInputValid("hello"));
    }

    public static boolean isInputValid(String input){       
        return notNull.testAndLog(input, "NULL Check Failed") && notEmpty.testAndLog(input, "EMPTY Check Failed");
    }
}

/**
 * Just a mock log class
 *
 */
class MLog {
    void warn(String str) {
        System.out.println(str);
    }
}

一种方法是创建一个高阶函数,将一些日志记录代码包装在现有谓词周围,returns 一个可以用来代替原始谓词的谓词。这是此类函数的示例:

static <T> Predicate<T> loggingPredicate(String label, Predicate<? super T> pred) {
    return t -> {
        boolean r = pred.test(t);
        System.out.printf("%s: %s => %s%n", label, t, r);
        return r;
    };
}

这会打印出每次调用的输入和结果。它还带有一个标签,以便您可以从日志中判断正在评估哪个谓词。您可以调整它,以便它仅在谓词 returns 为假或类似情况时打印一条日志消息。当然,您可以调整它以使用您喜欢的任何日志记录框架,而不是打印到标准输出。

然后,您可以使用现有谓词并将它们包装在对此函数的调用中:

Predicate<String> notNull = loggingPredicate("notNull", input -> (input != null));
Predicate<String> notEmpty = loggingPredicate("notEmpty", input -> (input.trim().length() > 0));

然后像以前一样使用notNullnotEmpty。每次评估其中一个时,您都会收到一条日志消息。