目录
- Java函数编程的一些基础知识
- BiFunction
- BinaryOperator
- stream reduce
- And, Or操作符
- and 逻辑 的 Combiner 如下:
- or 逻辑 的 Combiner 如下:
- 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)