我需要取一个给定的记录,并填充其所有子记录和infinitem的标识符列表(即原始项目的所有子记录,孩子的所有子记录,孙子的所有子记录等)我目前有一个方法产生我想要的,但它不是最容易阅读和使用迭代而不是递归。我想知道是否有一种更干净的方法来实现我想要的,可能使用递归调用,但主要目的是使代码更容易阅读。当前的实现如下
public List<String> getAllChildRecords(targetRecord) {
final List<String> allChildRecordIds = new ArrayList<>();
final List<String> recordIdsForQuery = new ArrayList<>();
final List<String> queryResults = new ArrayList<>();
recordIdsForQuery.add(targetRecord);
while (!recordIdsForQuery .isEmpty()) {
for (final String queryParentId : recordIdsForQuery ) {
queryResults.addAll(
[DBAccessLayerClass].[getChildRecordIds](queryParentId));
}
allChildRecordIds .addAll(queryResults);
recordIdsForQuery .clear();
recordIdsForQuery .addAll(queryResults);
queryResults.clear();
}
return allChildRecordIds
}
递归通常不是正确的答案,特别是在java中—例如,递归往往很慢,并且会产生复杂的堆栈跟踪。因此,"只是重写为递归"并不是一个可靠的答案,因此,如果你关心可读性,这不是一个可靠的改进。
通常的技巧是使用队列。另外,不要再"为了可读性"而声明final了——这样会给代码增加很多噪音。如果你坚持要将"改变局部变量"减少到最低限度以提高可读性,那么配置你的IDE以一种高度可见的方式呈现对局部变量的写入,不要因为到处添加一堆嘈杂的关键字而弄乱你的代码。
var out = new ArrayList<String>();
var queue = new ArrayDeque<String>();
queue.add(targetRecord);
while (!queue.isEmpty()) {
String id = queue.pop();
var childIds = DbAccessLayerClass.getChildRecordIds(id));
out.addAll(childIds);
queue.addAll(childIds);
}
return out;
如果你害怕循环或重复(例如,一个项目可以是多个单独条目的子条目),将out
改为(Linked)HashSet
,并在DbAccessLayerClass.getChildRecordIds
之后添加childIds.removeAll(out);
。