我可以这样使用lambda函数统计树节点数量吗?附AtomicInteger疑问
代码问题修正
你当前实现的size方法存在逻辑错误:当前仅累加了所有子树的节点数,没有计入当前节点本身,非叶子节点的返回值需要额外加1,修正后代码如下:
/** = the number of nodes in this H1N1Tree. * Note: If this is a leaf, the size is 1 (just the root) */ public int size() { // TODO 2. This method must be recursive. if (children.size() == 0) return 1; AtomicInteger sizeOfChildren = new AtomicInteger(); children.forEach(p -> {sizeOfChildren.addAndGet(p.size());}); // 加上当前节点本身的计数 return 1 + sizeOfChildren.get(); }
如果追求更简洁的写法,也可以直接用Stream流完成累加,不需要手动声明计数器:
public int size() { return 1 + children.stream().mapToInt(H1N1Tree::size).sum(); }
关于AtomicInteger用法的疑问解答
你的理解是对的,这里AtomicInteger的用法和C++中传入int指针的作用高度类似:
- Java lambda对外部局部变量的捕获有严格限制:只能捕获*不可变(final或effectively final)*的变量。如果直接声明普通
int sizeOfChildren,lambda捕获的是int的值,且不允许在lambda内部修改该值,编译会直接报错。 - 你用
AtomicInteger的本质是捕获了这个对象的不可变引用,虽然引用本身不能改,但可以调用对象的方法修改其内部存储的整数值,这和C++里lambda捕获int指针、指针本身不变但可以通过指针修改指向的int值的逻辑是完全一致的。
补充说明:如果只是单线程场景下用lambda做累加,不需要并发安全的话,用长度为1的int数组int[] sizeOfChildren = new int[1];也能实现同样效果,原理也是捕获不可变的数组引用、修改数组内部的元素值,只是AtomicInteger的API更友好。
内容的提问来源于stack exchange,提问作者James E
相关产品推荐
相关产品推荐

