Lambda节点配置-LambdaTreeNodeConfig
# 🎯 简介
LambdaTreeNodeConfig 是 TreeNodeConfig 的子类,它引入了 Lambda 表达式支持,允许使用方法引用而非硬编码字符串来配置树节点的各种属性。这种方式可以避免因字段名变更导致的运行时错误,提高代码的类型安全性和可维护性。
# 📋 核心特性
- ✅ 继承自
TreeNodeConfig,保留所有原有功能 - ✅ 支持使用 Lambda 表达式配置节点属性
- ✅ 支持方法引用,避免硬编码字段名
- ✅ 类型安全,编译时检查字段是否存在
- ✅ 支持链式调用
- ✅ 自动兼容原有字符串配置
- ✅ 实现了序列化接口
# 🛠️ 类结构
typedef LambdaTreeNodeConfig<T, R>
├── 继承自 TreeNodeConfig
├── 泛型参数
│ ├── T: 方法对象类型
│ └── R: 返回值类型
├── 属性
│ ├── idKeyFun: SerFunction<T, R> // ID字段Lambda函数
│ ├── parentIdKeyFun: SerFunction<T, R> // 父节点ID字段Lambda函数
│ ├── weightKeyFun: SerFunction<T, Comparable<?>> // 权重字段Lambda函数
│ ├── nameKeyFun: SerFunction<T, CharSequence> // 名称字段Lambda函数
│ └── childrenKeyFun: SerFunction<T, List<T>> // 子节点字段Lambda函数
└── 方法
├── getIdKeyFun(): SerFunction<T, R> // 获取ID字段Lambda函数
├── setIdKeyFun(idKeyFun): LambdaTreeNodeConfig<T, R> // 设置ID字段Lambda函数(链式)
├── getParentIdKeyFun(): SerFunction<T, R> // 获取父节点ID字段Lambda函数
├── setParentIdKeyFun(parentIdKeyFun): LambdaTreeNodeConfig<T, R> // 设置父节点ID字段Lambda函数(链式)
├── getWeightKeyFun(): SerFunction<T, Comparable<?>> // 获取权重字段Lambda函数
├── setWeightKeyFun(weightKeyFun): LambdaTreeNodeConfig<T, R> // 设置权重字段Lambda函数(链式)
├── getNameKeyFun(): SerFunction<T, CharSequence> // 获取名称字段Lambda函数
├── setNameKeyFun(nameKeyFun): LambdaTreeNodeConfig<T, R> // 设置名称字段Lambda函数(链式)
├── getChildrenKeyFun(): SerFunction<T, List<T>> // 获取子节点字段Lambda函数
├── setChildrenKeyFun(childrenKeyFun): LambdaTreeNodeConfig<T, R> // 设置子节点字段Lambda函数(链式)
├── getIdKey(): String // 重写:获取ID字段名
├── getParentIdKey(): String // 重写:获取父节点ID字段名
├── getWeightKey(): String // 重写:获取权重字段名
├── getNameKey(): String // 重写:获取名称字段名
└── getChildrenKey(): String // 重写:获取子节点字段名
# 🚀 快速开始
# 基本使用
// 定义实体类
class Menu {
private Long id;
private Long parentId;
private String name;
private Integer sort;
private List<Menu> children;
// 构造方法、getter和setter省略
}
// 创建Lambda配置
LambdaTreeNodeConfig<Menu, Long> config = new LambdaTreeNodeConfig<>();
// 使用方法引用配置字段
config.setIdKeyFun(Menu::getId)
.setParentIdKeyFun(Menu::getParentId)
.setNameKeyFun(Menu::getName)
.setWeightKeyFun(Menu::getSort)
.setChildrenKeyFun(Menu::getChildren);
// 构建树
List<Menu> menuList = getMenuList(); // 从数据库获取菜单列表
List<Menu> menuTree = BeanTree.build(menuList, 0L, config);
# 混合使用Lambda和字符串配置
// 创建Lambda配置
LambdaTreeNodeConfig<Menu, Long> config = new LambdaTreeNodeConfig<>();
// 使用Lambda配置ID和父ID
config.setIdKeyFun(Menu::getId)
.setParentIdKeyFun(Menu::getParentId);
// 使用传统字符串配置其他属性
config.setNameKey("menuName")
.setWeightKey("order")
.setChildrenKey("subMenus");
// 构建树
List<Map<String, Object>> tree = TreeUtil.build(menuList, 0L, config);
# 📖 详细方法
# Lambda函数配置
# getIdKeyFun()
功能:获取ID字段的Lambda函数
返回值:ID字段的Lambda函数
示例:
SerFunction<Menu, Long> idFun = config.getIdKeyFun();
# setIdKeyFun(idKeyFun)
功能:设置ID字段的Lambda函数
参数:
idKeyFun- ID字段的Lambda函数,通常使用方法引用返回值:当前配置实例,支持链式调用
使用场景:使用Lambda表达式配置ID字段
示例:
config.setIdKeyFun(Menu::getId);
# getParentIdKeyFun()
功能:获取父节点ID字段的Lambda函数
返回值:父节点ID字段的Lambda函数
示例:
SerFunction<Menu, Long> parentIdFun = config.getParentIdKeyFun();
# setParentIdKeyFun(parentIdKeyFun)
功能:设置父节点ID字段的Lambda函数
参数:
parentIdKeyFun- 父节点ID字段的Lambda函数返回值:当前配置实例,支持链式调用
使用场景:使用Lambda表达式配置父节点ID字段
示例:
config.setParentIdKeyFun(Menu::getParentId);
# getWeightKeyFun()
功能:获取权重字段的Lambda函数
返回值:权重字段的Lambda函数
示例:
SerFunction<Menu, Comparable<?>> weightFun = config.getWeightKeyFun();
# setWeightKeyFun(weightKeyFun)
功能:设置权重字段的Lambda函数
参数:
weightKeyFun- 权重字段的Lambda函数返回值:当前配置实例,支持链式调用
使用场景:使用Lambda表达式配置权重字段
示例:
config.setWeightKeyFun(Menu::getSort);
# getNameKeyFun()
功能:获取名称字段的Lambda函数
返回值:名称字段的Lambda函数
示例:
SerFunction<Menu, CharSequence> nameFun = config.getNameKeyFun();
# setNameKeyFun(nameKeyFun)
功能:设置名称字段的Lambda函数
参数:
nameKeyFun- 名称字段的Lambda函数返回值:当前配置实例,支持链式调用
使用场景:使用Lambda表达式配置名称字段
示例:
config.setNameKeyFun(Menu::getName);
# getChildrenKeyFun()
功能:获取子节点字段的Lambda函数
返回值:子节点字段的Lambda函数
示例:
SerFunction<Menu, List<Menu>> childrenFun = config.getChildrenKeyFun();
# setChildrenKeyFun(childrenKeyFun)
功能:设置子节点字段的Lambda函数
参数:
childrenKeyFun- 子节点字段的Lambda函数返回值:当前配置实例,支持链式调用
使用场景:使用Lambda表达式配置子节点字段
示例:
config.setChildrenKeyFun(Menu::getChildren);
# 重写的父类方法
# getIdKey()
功能:获取ID字段名
返回值:如果设置了Lambda函数,则返回函数对应的字段名;否则返回父类配置的字段名
示例:
config.setIdKeyFun(Menu::getId); Console.log(config.getIdKey()); // 输出: id
# getParentIdKey()
功能:获取父节点ID字段名
返回值:如果设置了Lambda函数,则返回函数对应的字段名;否则返回父类配置的字段名
示例:
config.setParentIdKeyFun(Menu::getParentId); Console.log(config.getParentIdKey()); // 输出: parentId
# getWeightKey()
功能:获取权重字段名
返回值:如果设置了Lambda函数,则返回函数对应的字段名;否则返回父类配置的字段名
示例:
config.setWeightKeyFun(Menu::getSort); Console.log(config.getWeightKey()); // 输出: sort
# getNameKey()
功能:获取名称字段名
返回值:如果设置了Lambda函数,则返回函数对应的字段名;否则返回父类配置的字段名
示例:
config.setNameKeyFun(Menu::getName); Console.log(config.getNameKey()); // 输出: name
# getChildrenKey()
功能:获取子节点字段名
返回值:如果设置了Lambda函数,则返回函数对应的字段名;否则返回父类配置的字段名
示例:
config.setChildrenKeyFun(Menu::getChildren); Console.log(config.getChildrenKey()); // 输出: children
# 🎨 使用场景
# 1. 实体类树构建
// 定义部门实体
class Department {
private Long id;
private Long parentId;
private String deptName;
private Integer orderNum;
private List<Department> subDepts;
// 构造方法、getter和setter省略
}
// 创建Lambda配置
LambdaTreeNodeConfig<Department, Long> config = new LambdaTreeNodeConfig<>();
config.setIdKeyFun(Department::getId)
.setParentIdKeyFun(Department::getParentId)
.setNameKeyFun(Department::getDeptName)
.setWeightKeyFun(Department::getOrderNum)
.setChildrenKeyFun(Department::getSubDepts);
// 从数据库获取部门列表
List<Department> deptList = departmentService.findAll();
// 构建部门树
List<Department> deptTree = BeanTree.build(deptList, 0L, config);
// 输出部门树
Console.log("部门树: {}", deptTree);
# 2. 动态字段配置
// 定义动态实体类
class DynamicEntity {
private String uuid;
private String parentUuid;
private String title;
private Integer priority;
private List<DynamicEntity> items;
// 构造方法、getter和setter省略
}
// 创建Lambda配置
LambdaTreeNodeConfig<DynamicEntity, String> config = new LambdaTreeNodeConfig<>();
// 根据不同业务场景动态配置
if (isNewVersion) {
config.setIdKeyFun(DynamicEntity::getUuid)
.setParentIdKeyFun(DynamicEntity::getParentUuid);
} else {
config.setIdKey("id")
.setParentIdKey("parentId");
}
config.setNameKeyFun(DynamicEntity::getTitle)
.setWeightKeyFun(DynamicEntity::getPriority)
.setChildrenKeyFun(DynamicEntity::getItems);
// 构建树
List<DynamicEntity> tree = BeanTree.build(entityList, "0", config);
# 3. 结合BeanTree使用
// 定义菜单实体
class Menu {
private Long id;
private Long parentId;
private String name;
private Integer sort;
private List<Menu> children;
// 构造方法、getter和setter省略
}
// 创建Lambda配置
LambdaTreeNodeConfig<Menu, Long> config = new LambdaTreeNodeConfig<>();
config.setIdKeyFun(Menu::getId)
.setParentIdKeyFun(Menu::getParentId)
.setNameKeyFun(Menu::getName)
.setWeightKeyFun(Menu::getSort)
.setChildrenKeyFun(Menu::getChildren);
// 使用BeanTree构建实体树
List<Menu> menuList = menuService.findAll();
List<Menu> menuTree = BeanTree.build(menuList, 0L, config);
// 输出结果
Console.log("菜单树: {}", menuTree);
# 💡 注意事项
泛型类型:
T是方法对象类型,通常是实体类R是返回值类型,通常是ID的类型(如Long、String等)
Lambda表达式:
- 必须使用
SerFunction类型,支持序列化 - 通常使用方法引用(
::)来简化代码
- 必须使用
字段名获取:
- Lambda函数通过
LambdaUtil.getFieldName()获取字段名 - 支持私有字段,会通过反射获取
- Lambda函数通过
兼容父类:
- 可以混合使用Lambda配置和传统字符串配置
- Lambda配置优先级高于字符串配置
序列化支持:
- 实现了Serializable接口,可以用于网络传输和持久化
- Lambda函数必须是可序列化的
性能考虑:
- Lambda函数的字段名获取是通过反射实现的,首次调用会有一定开销
- 建议将配置对象缓存起来,避免重复创建
# 🚀 性能优化
- 对于频繁使用的配置,建议将配置对象缓存为静态常量
- 优先使用方法引用而非匿名Lambda表达式,提高性能
- 避免在循环中创建配置对象,减少对象创建开销
- 对于固定配置,考虑使用单例模式管理
# 🔍 最佳实践
- 类型安全:优先使用Lambda配置,利用编译时检查避免字段名错误
- 代码可读性:使用方法引用使配置更直观,便于维护
- 配置复用:将通用配置封装为静态方法或常量,提高代码复用性
- 动态适配:根据不同业务场景灵活选择Lambda或字符串配置
- 注释说明:对复杂配置添加注释,说明配置的用途和规则
- 异常处理:确保Lambda函数指向的字段存在,避免运行时错误
# 📝 总结
LambdaTreeNodeConfig 是 Hutool 树结构模块中的一个重要扩展,它引入了 Lambda 表达式支持,为树结构配置提供了类型安全的解决方案。通过使用方法引用,开发者可以避免硬编码字段名,提高代码的可维护性和可读性。
无论是构建实体类树还是动态配置字段,LambdaTreeNodeConfig 都能提供灵活、安全的配置方式。它继承了 TreeNodeConfig 的所有功能,并在此基础上添加了 Lambda 支持,实现了向下兼容。
在实际开发中,建议优先使用 LambdaTreeNodeConfig,特别是在实体类字段可能发生变化的场景下,它能有效避免因字段名变更导致的运行时错误,提高代码的健壮性。