我有两个lambda函数(谓词):
final Predicate<Node> isElement = node -> node.getNodeType() == Node.ELEMENT_NODE;
final BiPredicate<Node, String> hasName = (node, name) -> node.getNodeName().equals(name);
我希望以一种简洁的方式结合使用,如下所示:
// Pseudocode
isElement.and(hasName("tag")) // type of Predicate
然后传递给另一个lambda函数:
final BiFunction<Node, Predicate<Node>, List<Node>> getChilds = (node, cond) -> {
List<Node> resultList = new ArrayList<>();
NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); ++i) {
Node tmp = nodeList.item(i);
if (cond.test(tmp)) {
resultList.add(tmp);
}
}
return resultList;
};
结果我期待它看起来如下:
List<Node> listNode = getChilds.apply(document, isElement.and(hasName("tag")));
但and
的{{1}}方法不接受Predicate
参数。
我怎么能这样做?
答案 0 :(得分:5)
停止将每个方法重写为lambda表达式。没有真正的好处。如果您使用普通方法,则可以通过简单名称调用它,而无需附加apply
,test
或类似内容。如果您确实需要一个函数,那么仍然可以使用::
运算符创建静态方法引用。
因此,如果您想改进代码,请考虑使用新的 API 而不是过度使用Java语言功能。例如:
static List<Node> getChilds(Node node, Predicate<Node> cond) {
NodeList nodeList = node.getChildNodes();
return IntStream.range(0, nodeList.getLength()).mapToObj(nodeList::item)
.filter(cond).collect(Collectors.toList());
}
关于您尝试合并Predicate
的问题。当然,你可以表达所有功能而不妥协。例如:
Predicate<Node> isElement = node -> node.getNodeType() == Node.ELEMENT_NODE;
Function<Node, String> nodeName = Node::getNodeName;
Predicate<Node> both = isElement.and(nodeName.andThen("tag"::equals)::apply);
但这真的是一种改进吗?
您可以简单地写
Predicate<Node> both = isElement.and(n -> n.getNodeName().equals("tag"));
或更简单,因为Node
不代表ELEMENT
个节点,永远不会报告"tag"
的节点名称,根本不需要第一个谓词和整个谓词操作变为:
getChilds(document, n -> "tag".equals(n.getNodeName()));
这可能不像复杂的功能组合那样花哨,但它是实用的解决方案。
答案 1 :(得分:4)
你需要编写一个静态辅助函数,将你的BiPredicate curries下移到一个谓词,然后你可以.and()
使用另一个谓词。
isElement.and(curryRight(hasName, "tag"))
或者,您可以这样做:
isElement.and(node -> hasName.test(node, "tag"))
它不会那么长
答案 2 :(得分:3)
将lambada函数hasName
更改为函数hasName(String name)
返回lambda函数。
final Predicate<Node> hasName(String name) { return node -> node.getNodeName().equals(name); }
然后你的代码就可以了。
List<Node> listNode = getChilds.apply(document, isElement.and(hasName("tag")));