规则引擎--函数式编程和and/or操作符的设计

接上一篇博文:规则引擎–规则逻辑形如“1 & (2 | 3)“的抽象, 重点分析一下And, Or操作符的设计

Java函数编程的一些基础知识

BiFunction

@FunctionalInterface
public interface BiFunction<T, U, R> {
    
    

    /**
     * 将apply函数应用到给定的参数上面
     *
     * @param t 函数的第一个参数
     * @param u 函数的第二个参数
     * @return R 函数的结果
     */
    R apply(T t, U u);

    /**
     * 返回一个组合的函数,第一次是将该函数应用到它的输入,接着是将该函数的after应用到
     * 之前的结果上。如果在任一函数评测期间抛出异常,它都会被传递给组合函数的调用者。
     * @param <V> 组合函数和after函数的输出类型
     * @param after 该函数应用将被在当前函数apply后被apply
     * @return 返回一个组合函数,第一次应用该函数,接着应用after函数
     * @throws 当after为null的时候,会抛出NullPointerException异常。
     */
    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
    
    
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}

例子代码

public static void main(String[] args) {
    
    
   // BiFunction
    BiFunction<Integer, Integer, Integer> biFunc = (x1, x2) -> x1 + x2;
    Integer result = biFunc.apply(2, 3);
    System.out.println(result); // 5

    Function<Integer,String> function = a->"result:"+a;
    String s = biFunc.andThen(function).apply(1,2);
    System.out.println(s); // result:3
}

BinaryOperator

@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
    
    
    /**
     * 通过比较器Comparator来比较两个元素中较小的一个作为返回值返回。
     * @param <T> 比较器的输入参数的类型
     * @param comparator 用来比较两个值的Comparator
     * @return 通过比较器Comparator来比较两个元素中较小的一个作为返回值返回。
     * @throws 如果参数为NULL,就会抛出NullPointerException异常
     */
    public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
    
    
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
    }

    /**
     * 通过比较器Comparator来比较两个元素中较大的一个作为返回值返回。
     * @param <T> 比较器的输入参数的类型
     * @param comparator 用来比较两个值的Comparator
     * @return 通过比较器Comparator来比较两个元素中较小的一个作为返回值返回。
     * @throws 如果参数为NULL,就会抛出NullPointerException异常
     */
    public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
    
    
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
    }
}

例子代码

public static void main(String[] args) {
    
    
    BinaryOperator<Integer> integerBinaryOperator = (x1, x2) -> x1 - x2;
    Integer result = integerBinaryOperator.apply(3, 2);
    System.out.println(result); // 1

    Integer a = BinaryOperator.minBy(Integer::compare).apply(1,2);
    System.out.println(a); // 1

    Integer b = BinaryOperator.maxBy(Integer::compare).apply(1,2);
    System.out.println(b); // 2
}

stream reduce

常见释义
英[rɪˈdjuːs][rɪˈduːs]
v.	使还原; 减少; 缩小(尺寸、数量、价格等); (使)蒸发; 减轻体重; 节食;
[例句]Better insulation of your home will help to reduce heating bills.
增加房子的隔热性能会有助于减少供暖费用。
[其他]	第三人称单数:reduces 现在分词:reducing 过去式:reduced 过去分词:reduced

reduce重载的三个方法

// 一个参数: 主要作用 累加、累减,求取最大值、最小值。
Optional<T> reduce(BinaryOperator<T> accumulator);
 
// 两个参数: 多了一个初始值, 同一个参数的方法
T reduce(T identity, BinaryOperator<T> accumulator);
 
// 三个参数:并行流使用
<U> U reduce(U identity,
             BiFunction<U, ? super T, U> accumulator,
             BinaryOperator<U> combiner);

例子1

public static void main(String[] args) {
    
    
   final List<Integer> list = Arrays.asList(1, 2, 5, 3, 4);

   // reduce累加
   BinaryOperator<Integer> binaryOperatorAdd = (x1, x2) -> x1 + x2;
   Optional<Integer> result = list.stream().reduce(binaryOperatorAdd);
   System.out.println(result); // Optional[15]

   // reduce求最大值
   Optional<Integer> resultMax = list.stream().reduce(BinaryOperator.maxBy(Integer::compare));
   System.out.println(resultMax); // Optional[5]

   // reduce带初始化值的累加
   Integer result2 = list.stream().reduce(10, binaryOperatorAdd);
   System.out.println(result2); // 25

}

例子2:

public static void main(String[] args) {
    
    
    List<Long> list = new ArrayList<>();
    for(long i = 1L;i<20_000_000L;i++){
    
    
        list.add(i);
    }
    BinaryOperator<Long> binaryOperatorAdd = (x1, x2) -> x1 + x2;
    long sta = System.currentTimeMillis();
    Long result = list.stream().reduce(0L, binaryOperatorAdd, binaryOperatorAdd);
    long cost = System.currentTimeMillis() - sta;
    System.out.println(result + " cost:" + cost);


    long sta2 = System.currentTimeMillis();
    Long result2 = list.parallelStream().reduce(0L, binaryOperatorAdd, binaryOperatorAdd);
    long cost2 = System.currentTimeMillis() - sta2;
    System.out.println(result2 + " cost:" + cost2);

}

某些时候运行的耗时差距如下
在这里插入图片描述

And, Or操作符

在这里插入图片描述

  • AbstractAndOr
public abstract class AbstractAndOr extends AbstractShortcutableEvaluable<Evaluable<EvalResult>, EvalResult> implements
        Operator<Evaluable<EvalResult>, EvalResult> {
    
    

    @Override
    protected BinaryOperator<EvalResult> getCombiner(EvalResult s) {
    
    
        return (r1, r2) -> {
    
    
            if (r1 == s || r2 == s) {
    
    
                return s;
            } else if (r1 == EvalResult.Unknown || r2 == EvalResult.Unknown) {
    
    
                return EvalResult.Unknown;
            } else if (r1 == EvalResult.Exception || r2 == EvalResult.Exception) {
    
    
                return EvalResult.Exception;
            } else {
    
    
                return initial();
            }
        };
    }
}
  • AbstractShortcutableEvaluable
public abstract class AbstractShortcutableEvaluable<E extends Evaluable<T>, T> extends
        AbstractOperandsBasedEvaluable<E, T> {
    
    

    /**
     * 定义两操作数求值结果的结合逻辑
     *
     * @param shortcut
     * @return
     */
    protected abstract BinaryOperator<T> getCombiner(T shortcut);

    /**
     * 定义短路值
     *
     * @return
     */
    public abstract T shortcut();

    /**
     * 定义初始值
     *
     * @return
     */
    public abstract T initial();


    @Override
    public T eval(EngineExecutionContext context) {
    
    
        return getOperands().stream().reduce(initial(), getAccumulator(context, shortcut()),
                getCombiner(shortcut()));
    }

    private BiFunction<T, Evaluable<T>, T> getAccumulator(EngineExecutionContext context, T shortcut) {
    
    
        return (r, op) -> r.equals(shortcut) ? r : getCombiner(shortcut).apply(r,
                op.eval(context));
    }
}

and 逻辑 的 Combiner 如下:

  • and操作符
public class And extends AbstractAndOr {
    
    

    @Override
    public EvalResult initial() {
    
    
        return EvalResult.True;
    }

    @Override
    public EvalResult shortcut() {
    
    
        return EvalResult.False;
    }

    @Override
    public String getOperator() {
    
    
        return Operator.AND;
    }

    @Override
    public void accept(EvaluableVisitor visitor) {
    
    
        visitor.visit(this);
    }
}

and的shortcut是false,初始值是true, 则combiner 逻辑

BinaryOperator<EvalResult> getCombiner(EvalResult s) {
    
    
	// s 为 EvalResult.False
  return (r1, r2) -> {
    
    
        if (r1 == s || r2 == s) {
    
    
            return s;
        } else if (r1 == EvalResult.Unknown || r2 == EvalResult.Unknown) {
    
    
            return EvalResult.Unknown;
        } else if (r1 == EvalResult.Exception || r2 == EvalResult.Exception) {
    
    
            return EvalResult.Exception;
        } else {
    
    
            return EvalResult.True;
        }
    };
}

即只要有一个False就是false, 为执行未知和异常情况单独处理,否则返回true

or 逻辑 的 Combiner 如下:

  • or操作符
public class Or  extends AbstractAndOr {
    
    

    @Override
    public EvalResult initial() {
    
    
        return EvalResult.False;
    }

    @Override
    public EvalResult shortcut() {
    
    
        return EvalResult.True;
    }

    @Override
    public String getOperator() {
    
    
        return Operator.OR;
    }

    @Override
    public void accept(EvaluableVisitor visitor) {
    
    
        visitor.visit(this);
    }
}

or的shortcut是true,初始值是false, 则combiner 逻辑

BinaryOperator<EvalResult> getCombiner(EvalResult s) {
    
    
	// s 为 EvalResult.True
  return (r1, r2) -> {
    
    
        if (r1 == s || r2 == s) {
    
    
            return s;
        } else if (r1 == EvalResult.Unknown || r2 == EvalResult.Unknown) {
    
    
            return EvalResult.Unknown;
        } else if (r1 == EvalResult.Exception || r2 == EvalResult.Exception) {
    
    
            return EvalResult.Exception;
        } else {
    
    
            return EvalResult.False;
        }
    };
}

即只要有一个True就是true, 为执行未知和异常情况单独处理,否则返回false

and, or的执行

上面解释了and ,or的Combiner都是正确的,再来看其执行

 @Override
public T eval(EngineExecutionContext context) {
    
    
   return getOperands().stream().reduce(initial(), getAccumulator(context, shortcut()),
           getCombiner(shortcut()));
}

private BiFunction<T, Evaluable<T>, T> getAccumulator(EngineExecutionContext context, T shortcut) {
    
    
   return (r, op) -> r.equals(shortcut) ? r : getCombiner(shortcut).apply(r, op.eval(context));
}

对于and来说,三目运算符号return (r, op) -> r.equals(shortcut) ? r : getCombiner(shortcut).apply(r, op.eval(context));如果第一个结果是false,那么直接返回该结果(因为 r.equals(shortcut) 这句会满足), 即左右边量有一个为false了,不用and了,直接false

对于or来说,三目运算符号return (r, op) -> r.equals(shortcut) ? r : getCombiner(shortcut).apply(r, op.eval(context));如果第一个结果是true,那么直接返回该结果(因为 r.equals(shortcut) 这句会满足), 即左右边量有一个为true了,不用or了,直接true

否则需要执行combiner的逻辑了

所以and, or操作符号执行如下,

getOperands().stream().reduce(
参数1:	EvalResult.True,
参数2: getAccumulator 同	BinaryOperator<EvalResult> getCombiner, 有短路逻辑
参数3:	BinaryOperator<EvalResult> getCombiner
```

如下截图,反映了其中一次and操作符的执行
![在这里插入图片描述](https://img-blog.csdnimg.cn/70f8b3aaa0174366888b11f9585cf597.png)

猜你喜欢

转载自blog.csdn.net/qq_26437925/article/details/131348032