如何使用Java 7计算嵌套列表元素的大小?

3

我有一个对象,其中包含另一个对象的列表,该列表包含另一个对象的列表,依此类推...假设我想获取嵌套列表元素的计数(假设是最后一个元素),除了在java中使用传统的for循环(如下面的示例所示)之外,还应该采取什么最佳方法-

public static void main(String[] args) {

    Statement statement = new Statement();
    statement.getInvAccount().add(new InvestmentAccount());
    statement.getInvAccount().get(0).getSecAccountStmt().add(new SecurityStatement());
    statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
    statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
    statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());

    // method to count the number of TransactionStatement
    System.out.println("Size of TransactionStatement is : " + count(statement));

}

private static int count(Statement stmt) {
    int countOfTransStmt = 0;
    for (InvestmentAccount invAcc : stmt.getInvAccount()) {
        if (invAcc != null) {
            for (SecurityStatement secStmt : invAcc.getSecAccountStmt()) {
                if (secStmt != null) {
                    countOfTransStmt = countOfTransStmt + secStmt.getTransactionStatement().size();
                }
            }
        }
    }
    return countOfTransStmt;
}

1
@JohnKugelman 嵌套层数未知。 - Andrew Tobilko
@JohnKugelman 如果嵌套的层数更多,例如6-7层呢? - Hars
1
@JohnKugelman提到:“我有一个包含另一个对象列表的对象,该列表又包含另一个对象列表,以此类推...” - Andrew Tobilko
@JohnKugelman 抱歉,实际上嵌套层级为6,我只是在这里快速添加了3个层级的示例。 - Hars
拥有6-7个嵌套列表会引发很多问题,比如“你是否正确地建模了事物?”和“为什么需要从这么高的位置循环遍历一些深度嵌套的列表?”我强烈怀疑这是一个XY问题。与其跳到像访问者这样复杂的东西,我首先会检查问题的框架。也许你正在尝试做一些不自然、不必要或可以通过重组数据更好地完成的事情。 - John Kugelman
显示剩余2条评论
2个回答

2

在Java 7中,你最好只用两个for循环。我不会尝试使用其他方法。

在Java 8中,你可以使用流来简化代码:

private static int count(Statement stmt) {
    return stmt.getInvAccount().stream()
        .filter(Objects::nonNull)
        .flatMap(InvestmentAccount::getSecAccountStmt)
        .filter(Objects::nonNull)
        .flatMap(SecurityStatement::getTransactionStatement)
        .count();
}

我建议您摒弃对空值的检查。如果您要忽略空值,在第一次插入时最好就期望它们不会被插入,这样可以消除代码中大量的额外if检查。
我还鼓励您不要缩写变量和方法。拼出"statement"和"investment"等词汇。缩写难以阅读,简洁也并非必然胜利。
同样地,尽可能使用更具描述性的方法名。主方法应命名为countTransactions。对于返回列表的方法,其命名应该是复数形式的:"getAccounts"而不是"getAccount"。请注意,现在getter的名称与类名匹配;如果您知道类名,则知道getter名称。您无需猜测其中一个是否被缩写:
private static int countTransactions(Statement statement) {
    return statement.getInvestmentAccounts().stream()
        .flatMap(InvestmentAccount::getSecurityStatements)
        .flatMap(SecurityStatement::getTransactionStatements)
        .count();
}

谢谢John,我仍在使用Java 7,您有任何关于如何在Java 7中完成此操作的建议吗?另外,由于我从某个不受控制的地方获取此信息,因此可能会出现空值。 - Hars
4
个人认为,如果没有Java 8或更高版本,你无法避免使用循环。此外,如果你的代码可以运行,那么你应该考虑将问题发布到 代码审查 网站上。 - zlakad
4
@Hars,请在问题中注明Java 7的限制,因为Java 8是标准,更不用说明天将正式发布Java 11了。 - Pshemo
@John:感谢您提供的方法命名建议,这只是本篇文章的一个快速示例,因此名称并不准确。另外,在实际数据中,我有6个嵌套列表,所以将使用大约5个循环,这样可以吗? - Hars

-1
递归可以在这种情况下使用: 以下是一般思路:
 private int countTransactions(object t)
{
int sum = 0;
if (t == null) return 0;
for (int i = 0; i < t.getAllSub().count; i++)
{
    sum += countTransactions(t.subAt(i));
}

 return sum;
}

3
不行,这些类有不同的方法用于访问内部列表。 - John Kugelman
用户有可能会更改方法或添加包装器方法... - Peter Chikov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接