在 Java 中链接谓词的首选方法是什么?
What is the preferred way to chain predicates in Java?
我有一堆谓词,我想用逻辑 "and" 将它们链接在一起,这样只有当所有单个谓词的计算结果都为真时,最终结果才为真。
据我所知,有两种写法。我可以像这样将它们链接在一起:
Predicate composedPredicate =
predicate1
.and(predicate2)
.and(predicate3)
.and(predicate4)
或者我可以使用像这样的更嵌套的方法:
Predicate composedPredicate =
predicate1
.and(predicate2
.and(predicate3
.and(predicate4)))
显然,选项 1 的可读性更高,但似乎效率稍低。我想选项 1 大致相当于:
(((p1 && p2) && p3) && p4)
虽然选项 2 是:
(p1 && (p2 && (p3 && p4)))
在第二种情况下,第一个参数 p1
将被评估,如果它为假,整个事情立即短路,你就完成了。在第一个选项中,第一个参数实际上是整个表达式 ((p1 && p2) && p3)
,它本身具有 (p1 && p2)
的第一个参数,而 p1
作为其第一个参数。基本上,在 p1 实际可以被评估之前,你还要再 "steps" 堆栈。我实际上并不知道 Java 如何实现默认谓词方法,所以如果我在这里错了请纠正我。
有什么方法可以两全其美吗?如果不是,我是否应该更喜欢可读性更强的方法,而不是可能带来非常小的性能提升,或者反之亦然?
一般来说,支持可读性任何感知的边际性能考虑。对于大多数谓词,我们希望它们执行得非常快,并且很难注意到这样的组合谓词,即提前短路和经常短路与那些延迟短路或根本不短路的谓词。
因此,从您的第一个选项开始,可读性更高的选项不会嵌套谓词以扰乱操作顺序。
如果您确实发现存在性能问题,由于某种探查器统计数据或基准性能 运行,那么您可以重新排序操作以获得性能优势。
- 您可以选择首先放置最有可能短路的谓词,以避免执行不会对结果产生影响的谓词的不必要开销。因为您在它们之间使用
and
,所以这些更有可能 return false
.
- 如果您多次调用这些链式谓词,请查看是否可以找到任何不变的谓词,例如不依赖于循环迭代索引,并保存这些结果,这样它们就不需要一遍又一遍地重复。
- 如果你发现其中一个谓词是计算密集型的并且它在循环中不是不变的,所以它需要一遍又一遍地执行,然后将它放在链的最后,看看以前的谓词是否可以短路,根本不需要执行。
但这也不应该影响可读性。您不需要像您所做的那样嵌套谓词;最多你需要重新排序它们,例如
Predicate composedPredicate =
predicate4
.and(predicate2)
.and(predicate1)
.and(predicate3)
如果您注意到 predicate4
很少 return 和 true
并且 predicate3
是计算密集型的。
我有一堆谓词,我想用逻辑 "and" 将它们链接在一起,这样只有当所有单个谓词的计算结果都为真时,最终结果才为真。
据我所知,有两种写法。我可以像这样将它们链接在一起:
Predicate composedPredicate =
predicate1
.and(predicate2)
.and(predicate3)
.and(predicate4)
或者我可以使用像这样的更嵌套的方法:
Predicate composedPredicate =
predicate1
.and(predicate2
.and(predicate3
.and(predicate4)))
显然,选项 1 的可读性更高,但似乎效率稍低。我想选项 1 大致相当于:
(((p1 && p2) && p3) && p4)
虽然选项 2 是:
(p1 && (p2 && (p3 && p4)))
在第二种情况下,第一个参数 p1
将被评估,如果它为假,整个事情立即短路,你就完成了。在第一个选项中,第一个参数实际上是整个表达式 ((p1 && p2) && p3)
,它本身具有 (p1 && p2)
的第一个参数,而 p1
作为其第一个参数。基本上,在 p1 实际可以被评估之前,你还要再 "steps" 堆栈。我实际上并不知道 Java 如何实现默认谓词方法,所以如果我在这里错了请纠正我。
有什么方法可以两全其美吗?如果不是,我是否应该更喜欢可读性更强的方法,而不是可能带来非常小的性能提升,或者反之亦然?
一般来说,支持可读性任何感知的边际性能考虑。对于大多数谓词,我们希望它们执行得非常快,并且很难注意到这样的组合谓词,即提前短路和经常短路与那些延迟短路或根本不短路的谓词。
因此,从您的第一个选项开始,可读性更高的选项不会嵌套谓词以扰乱操作顺序。
如果您确实发现存在性能问题,由于某种探查器统计数据或基准性能 运行,那么您可以重新排序操作以获得性能优势。
- 您可以选择首先放置最有可能短路的谓词,以避免执行不会对结果产生影响的谓词的不必要开销。因为您在它们之间使用
and
,所以这些更有可能 returnfalse
. - 如果您多次调用这些链式谓词,请查看是否可以找到任何不变的谓词,例如不依赖于循环迭代索引,并保存这些结果,这样它们就不需要一遍又一遍地重复。
- 如果你发现其中一个谓词是计算密集型的并且它在循环中不是不变的,所以它需要一遍又一遍地执行,然后将它放在链的最后,看看以前的谓词是否可以短路,根本不需要执行。
但这也不应该影响可读性。您不需要像您所做的那样嵌套谓词;最多你需要重新排序它们,例如
Predicate composedPredicate =
predicate4
.and(predicate2)
.and(predicate1)
.and(predicate3)
如果您注意到 predicate4
很少 return 和 true
并且 predicate3
是计算密集型的。