You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java中验证列表对象的父子关系及顺序合法性

问题说明

需要对外部服务返回的Category列表执行两项校验:

  • 父子关系合法性:根节点的parentId为null;非根节点的parentId必须指向列表中存在的分类,且不存在循环引用。
  • 顺序合法性:列表必须严格遵循层级递进顺序,即每个非根节点必须紧跟在其父节点之后(如示例中的HW → Phones → IPhone → 13 Pro),若顺序不符合要求则抛出异常。
待优化代码
List<Category> categoryList = getCategoryList();
categoryList.stream().forEach(category -> {
    if (category.getParentId().isEmpty()) {
        String rootCategory = category.getId();
        if (category.getParentId().equals(rootCategory)) {
            String category2 = category.getId();
            if (category.getParentId().equals(category2)) {
                String category3 = category.getId();
                if (category.getParentId().equals(category3)) {
                    String category4 = category.getId();
                }
            }
        }
    }
});
优化后的实现方案

核心思路

  1. 构建分类ID到对象的映射表,快速校验父节点是否存在;
  2. 用栈维护当前的层级路径,确保每个节点的父节点是路径的最后一个节点(保证顺序合规);
  3. 分步校验父子关系合法性与顺序合法性,不符合时抛出自定义异常。

完整代码实现

import java.util.*;

// 自定义异常类,用于抛出校验错误
class CategoryValidationException extends RuntimeException {
    public CategoryValidationException(String message) {
        super(message);
    }
}

// Category类示例(根据实际结构调整)
class Category {
    private String categoryId;
    private String parentId;

    public Category(String categoryId, String parentId) {
        this.categoryId = categoryId;
        this.parentId = parentId;
    }

    public String getCategoryId() {
        return categoryId;
    }

    public String getParentId() {
        return parentId;
    }
}

public class CategoryValidator {
    public static void validateCategoryList(List<Category> categoryList) {
        if (categoryList == null || categoryList.isEmpty()) {
            throw new CategoryValidationException("分类列表不能为空");
        }

        // 构建ID到Category的映射,用于快速查找父节点
        Map<String, Category> categoryMap = new HashMap<>();
        for (Category category : categoryList) {
            categoryMap.put(category.getCategoryId(), category);
        }

        // 用栈维护当前层级路径,栈顶为当前层级的父节点
        Deque<Category> hierarchyStack = new ArrayDeque<>();

        for (Category current : categoryList) {
            String currentId = current.getCategoryId();
            String parentId = current.getParentId();

            // 校验父子关系合法性
            if (parentId == null) {
                // 根节点:栈必须为空(只能有一个根节点,且是第一个节点)
                if (!hierarchyStack.isEmpty()) {
                    throw new CategoryValidationException("根节点必须是列表第一个节点,且只能有一个根节点");
                }
                hierarchyStack.push(current);
            } else {
                // 非根节点:父节点必须存在于映射中
                Category parent = categoryMap.get(parentId);
                if (parent == null) {
                    throw new CategoryValidationException("分类[" + currentId + "]的父节点[" + parentId + "]不存在");
                }
                // 校验循环引用(父节点的父节点不能指向当前节点,或更上层循环)
                if (isCircularReference(current, parent, categoryMap)) {
                    throw new CategoryValidationException("分类[" + currentId + "]存在循环引用");
                }

                // 校验顺序合法性:当前节点的父节点必须是栈顶节点(紧跟父节点之后)
                if (!hierarchyStack.isEmpty() && !hierarchyStack.peek().getCategoryId().equals(parentId)) {
                    throw new CategoryValidationException("分类[" + currentId + "]顺序错误,必须紧跟在父节点[" + parentId + "]之后");
                }

                // 入栈,进入下一层级
                hierarchyStack.push(current);
            }
        }
    }

    // 辅助方法:检查是否存在循环引用
    private static boolean isCircularReference(Category current, Category parent, Map<String, Category> categoryMap) {
        Set<String> visited = new HashSet<>();
        visited.add(current.getCategoryId());
        Category temp = parent;
        while (temp != null) {
            String tempId = temp.getCategoryId();
            if (visited.contains(tempId)) {
                return true;
            }
            visited.add(tempId);
            temp = categoryMap.get(temp.getParentId());
        }
        return false;
    }

    // 测试示例
    public static void main(String[] args) {
        // 合法顺序的列表
        List<Category> validList = Arrays.asList(
                new Category("HW", null),
                new Category("Phones", "HW"),
                new Category("IPhone", "Phones"),
                new Category("13 Pro", "IPhone")
        );
        validateCategoryList(validList);
        System.out.println("合法列表校验通过");

        // 非法顺序的列表
        List<Category> invalidList = Arrays.asList(
                new Category("HW", null),
                new Category("13 Pro", "IPhone"),
                new Category("IPhone", "Phones"),
                new Category("Phones", "HW")
        );
        try {
            validateCategoryList(invalidList);
        } catch (CategoryValidationException e) {
            System.out.println("非法列表校验失败:" + e.getMessage());
        }
    }
}

代码说明

  • 映射表:categoryMap用于快速查找父节点是否存在,避免重复遍历列表;
  • 层级栈:hierarchyStack记录当前的层级路径,确保每个非根节点紧跟其父节点;
  • 循环引用校验:isCircularReference方法通过遍历父节点链,检查是否存在循环;
  • 异常处理:自定义CategoryValidationException明确抛出校验错误信息,便于定位问题。

内容的提问来源于stack exchange,提问作者v_1403

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 22:10:26