Java构建递归树工具类

Java构建树结构工具类

import java.util.ArrayList;
import java.util.List;

public interface TreeUtil {
	
	/**
	 * 节点树抽象类
	 * @param <K> 节点ID的数据类型
	 * @param <T> 节点的数据类型
	 */
	interface Node<K, T extends Node<K, T>> {
		
		/**
		 * 设置当前节点的ID
		 */
		void setId(K id);
		
		/**
		 * 获取当前节点的ID
		 * @return 当前节点的ID
		 */
		K getId();
		
		/**
		 * 设置当前节点的父节点ID
		 */
		void setPid(K pid);
		
		/**
		 * 获取当前节点的父节点ID
		 * @return 当前节点的父节点ID
		 */
		K getPid();
		
		/**
		 * 设置当前节点所拥有的的子节点数量
		 */
		void setCount(int count);
		
		/**
		 * 获取当前节点所拥有的的子节点数量
		 * @return 当前节点所拥有的的子节点数量
		 */
		int getCount();
		
		/**
		 * 设置当前节点的子节点集合
		 * @param child 待设置的子节点集合
		 */
		void setChild(List<T> child);
		
		/**
		 * 获取当前节点的子节点集合
		 * @return 当前节点的子节点集合
		 */
		List<T> getChild();
		
	}
	
	/**
	 * 构建节点树
	 * @param src  构建树的源集合(包含所有的子父级节点)
	 * @param root 待填充子节点的根节点
	 */
	static <I, E extends Node<I, E>> void buildTree(List<E> src, Node<I, E> root) {
		List<E> child = new ArrayList<>();
		src.removeIf(item -> {
			if (item.getPid().equals(root.getId())) {
				child.add(item);
				return true;
			}
			return false;
		});
		if (!child.isEmpty()) {
			root.setChild(child);
			root.setCount(child.size());
			child.forEach(item -> buildTree(src, item));
		}
	}
	
	/**
	 * 构建节点树的简单方法
	 * @param src   待组装的节点集合
	 * @param clazz 节点的 Class 对象
	 * @param rid   节点树中顶级节点的ID
	 * @return 组装好的节点树
	 */
	static <M, N extends Node<M, N>> List<N> build(List<N> src, Class<N> clazz, M rid) {
		Node<M, N> root;
		try {
			root = clazz.newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			throw new RuntimeException(e);
		}
		root.setId(rid);
		buildTree(src, root);
		return root.getChild();
	}
	
	/**
	 * 非递归方式构建节点树
	 * 注:不要多线程调用此方法,因为不论setChild方法还是LinkedList的add方法都不保证同步
	 * @param src  构建树的源集合(包含所有的子父级节点)
	 * @param root 待填充子节点的根节点
	 */
	static <I, E extends Node<I, E>> List<E> buildTreeNoRecursion(List<E> src, I root) {
		if (root == null) {
			throw new IllegalArgumentException("根节点ID不能为空");
		}
		List<E> result = new LinkedList<>();
		Map<I, E> map = src.stream()
						   .collect(Collectors.toMap(E::getId, e -> e));
		for (E elem : src) {
			if (Objects.equals(root, elem.getPid())) {
				result.add(elem);
			} else {
				E e = map.get(elem.getPid());
				if (e == null) {
					continue;
				}
				List<E> child = e.getChild();
				if (child == null) {
					LinkedList<E> list = new LinkedList<>();
					// 这里不保证多线程的同步性,如需要可自己处理
					list.add(elem);
					e.setChild(list);
				} else {
					e.getChild().add(elem);
				}
			}
		}
		return result;
	}
}
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 链式构造POJO工具类
 */
public class BuilderUtil<T> {
	
	private final Supplier<T> instantiate;
	
	private final List<Consumer<T>> instanceModifiers = new ArrayList<>();
	
	public BuilderUtil(Supplier<T> instantiate) {
		this.instantiate = instantiate;
	}
	
	public static <T> BuilderUtil<T> of(Supplier<T> instantiator) {
		return new BuilderUtil<T>(instantiator);
	}
	
	public <U> BuilderUtil<T> with(BiConsumer<T, U> consumer, U value) {
		Consumer<T> c = instance -> consumer.accept(instance, value);
		instanceModifiers.add(c);
		return this;
	}
	
	public T build() {
		T value = instantiate.get();
		instanceModifiers.forEach(modifier -> modifier.accept(value));
		instanceModifiers.clear();
		return value;
	}
	
}
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.omega.demo.utils.BuilderUtil;
import com.omega.demo.utils.TreeUtil;

import java.util.ArrayList;
import java.util.List;

public class BuildTreeTest {
	
	public static void main(String[] args) {
		List<TreeNode> src = new ArrayList<>();
		src.add(BuilderUtil.of(TreeNode::new).with(TreeNode::setId, 50066159978024960L).with(TreeNode::setName, "四川省").with(TreeNode::setPid, 0L).build());
		src.add(BuilderUtil.of(TreeNode::new).with(TreeNode::setId, 50066159978024961L).with(TreeNode::setName, "重庆市").with(TreeNode::setPid, 0L).build());
		src.add(BuilderUtil.of(TreeNode::new).with(TreeNode::setId, 50066159978024962L).with(TreeNode::setName, "山西省").with(TreeNode::setPid, 0L).build());
		
		src.add(BuilderUtil.of(TreeNode::new).with(TreeNode::setId, 50066159978024963L).with(TreeNode::setName, "成都市").with(TreeNode::setPid, 50066159978024960L).build());
		src.add(BuilderUtil.of(TreeNode::new).with(TreeNode::setId, 50066159978024964L).with(TreeNode::setName, "成都01").with(TreeNode::setPid, 50066159978024963L).build());
		src.add(BuilderUtil.of(TreeNode::new).with(TreeNode::setId, 50066159978024965L).with(TreeNode::setName, "成都02").with(TreeNode::setPid, 50066159978024963L).build());
		
		src.add(BuilderUtil.of(TreeNode::new).with(TreeNode::setId, 50066159978024966L).with(TreeNode::setName, "重庆市").with(TreeNode::setPid, 50066159978024961L).build());
		src.add(BuilderUtil.of(TreeNode::new).with(TreeNode::setId, 50066159978024967L).with(TreeNode::setName, "重庆01").with(TreeNode::setPid, 50066159978024966L).build());
		src.add(BuilderUtil.of(TreeNode::new).with(TreeNode::setId, 50066159978024968L).with(TreeNode::setName, "重庆02").with(TreeNode::setPid, 50066159978024966L).build());
		
		src.add(BuilderUtil.of(TreeNode::new).with(TreeNode::setId, 50066159978024969L).with(TreeNode::setName, "太原市").with(TreeNode::setPid, 50066159978024962L).build());
		src.add(BuilderUtil.of(TreeNode::new).with(TreeNode::setId, 50066159978024970L).with(TreeNode::setName, "太远01").with(TreeNode::setPid, 50066159978024969L).build());
		src.add(BuilderUtil.of(TreeNode::new).with(TreeNode::setId, 50066159978024971L).with(TreeNode::setName, "太远02").with(TreeNode::setPid, 50066159978024969L).build());
		
		List<TreeNode> tree = TreeUtil.build(src, TreeNode.class, 0L);
		
		ObjectMapper objectMapper = new ObjectMapper();
		String str;
		try {
			str = objectMapper.writeValueAsString(tree);
		} catch (JsonProcessingException e) {
			throw new RuntimeException(e);
		}
		System.out.println(str);
	}
	
}
[
    {
        "id":50066159978024960,
        "name":"四川省",
        "pid":0,
        "count":1,
        "child":[
            {
                "id":50066159978024960,
                "name":"成都市",
                "pid":50066159978024960,
                "count":2,
                "child":[
                    {
                        "id":50066159978024960,
                        "name":"成都01",
                        "pid":50066159978024960,
                        "count":0,
                        "child":null
                    },
                    {
                        "id":50066159978024970,
                        "name":"成都02",
                        "pid":50066159978024960,
                        "count":0,
                        "child":null
                    }
                ]
            }
        ]
    },
    {
        "id":50066159978024960,
        "name":"重庆市",
        "pid":0,
        "count":1,
        "child":[
            {
                "id":50066159978024970,
                "name":"重庆市",
                "pid":50066159978024960,
                "count":2,
                "child":[
                    {
                        "id":50066159978024970,
                        "name":"重庆01",
                        "pid":50066159978024970,
                        "count":0,
                        "child":null
                    },
                    {
                        "id":50066159978024970,
                        "name":"重庆02",
                        "pid":50066159978024970,
                        "count":0,
                        "child":null
                    }
                ]
            }
        ]
    },
    {
        "id":50066159978024960,
        "name":"山西省",
        "pid":0,
        "count":1,
        "child":[
            {
                "id":50066159978024970,
                "name":"太原市",
                "pid":50066159978024960,
                "count":2,
                "child":[
                    {
                        "id":50066159978024970,
                        "name":"太远01",
                        "pid":50066159978024970,
                        "count":0,
                        "child":null
                    },
                    {
                        "id":50066159978024970,
                        "name":"太远02",
                        "pid":50066159978024970,
                        "count":0,
                        "child":null
                    }
                ]
            }
        ]
    }
]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值