目录
前言
UML
plantuml
类图
实战代码
Iterator
ArrayList
Client
自定义迭代器
TreeNode
TreeUtils
Client
前言
在实际开发过程中,常用各种集合来存储业务数据并处理,比如使用 List,Map,Set 等等集合来存储业务数据。存储在集合中的数据,往往需要遍历集合元素再进行相应的业务处理。
不同的集合类型有不同的数据结构,遍历的方式也各不相同。
而迭代器模式,就是用来简化这项工作,让开发者不必关心底层的数据结构是如何组织的,只需关注如何取用数据。它解决了数据的获取与表示之间的耦合问题,提升了集合管理的灵活性与可维护性。
UML
plantuml
@startuml 'https://plantuml.com/class-diagraminterface Iterator {+ hasNext() : boolean+ next() : type }class ConcreteIterator {+ hasNext() : boolean+ next() : type }class Client {+ iterator() : Iterator }Iterator <|.. ConcreteIteratorClient ..> Iterator@enduml
类图
实战代码
Iterator
JDK 提供了 Iterator 这个顶级接口,JDK 下的集合都实现了 Iterator 接口,这样在遍历集合时,便可以直接使用 iterator 来遍历集合元素,而不用关心底层的数据结构。
ArrayList
以 ArrayList 为例,内部类 Itr 实现了 Iterator 接口,iterator 方法则实例化一个迭代器返回
Client
public class Client { public static void main(String[] args) { List<Integer> array = Arrays.asList(1, 2, 3, 4, 5); Iterator<Integer> iterator = array .iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } }
}
自定义迭代器
如果 JDK 的集合类不满足业务需求,则需要自定义集合类,那么就需要自己实现 Iterator 接口,从而让自定义集合也能用统一的方式来遍历集合元素
以实际业务中最常见的分类树来举例,自定义 TreeNode 类,并实现 Iterator 接口
TreeNode
public class TreeNode {String id;String pid;String value;List<TreeNode> children;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getPid() {return pid;}public void setPid(String pid) {this.pid = pid;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}public List<TreeNode> getChildren() {return children;}public void setChildren(List<TreeNode> children) {this.children = children;}public Iterator<TreeNode> iterator() {return new TreeNode.Itr(this);}private class Itr implements Iterator<TreeNode> {TreeNode currentNode;private Deque<TreeNode> stack;public Itr(TreeNode root) {currentNode = root;stack = new LinkedList<>();stack.push(root);}@Overridepublic boolean hasNext() {return !stack.isEmpty();}@Overridepublic TreeNode next() {if (!hasNext()) {throw new NoSuchElementException("No more elements to iterate.");}TreeNode node = stack.pop();currentNode = node;List<TreeNode> children = node.getChildren();if (children != null) {for (int index = children.size() - 1; index >= 0; index--) {stack.push(children.get(index));}}return currentNode;}}
}
TreeUtils
public class TreeUtils {public final static String ROOT = "root";/*** 递归构造树** @param sources 按parentId分类的节点* @param parentId 父id,根节点父id为null* @param getId 获取id* @param setChildren 设置子节点* @return 根节点集合* @param <T> 节点类* @param <R> id类型*/public static <T, R> List<T> buildTree(Map<R, List<T>> sources, R parentId,Function<T, R> getId, BiConsumer<T, List<T>> setChildren) {List<T> nodes = sources.getOrDefault(parentId, emptyList());for (T node : nodes) {List<T> subNodes = buildTree(sources, getId.apply(node), getId, setChildren);setChildren.accept(node, subNodes);}return nodes;}}
Client
public class Client {public static void main(String[] args) {TreeNode root = new TreeNode();root.setId("1");root.setPid(null);root.setValue("root");TreeNode child1 = new TreeNode();child1.setId("2");child1.setPid("1");child1.setValue("child1");TreeNode child2 = new TreeNode();child2.setId("3");child2.setPid("1");child2.setValue("child2");TreeNode child3 = new TreeNode();child3.setId("4");child3.setPid("2");child3.setValue("child3");//模拟从数据库中查到的节点数据List<TreeNode> nodes = Arrays.asList(root, child1, child2, child3);//按父节点分类Map<String, List<TreeNode>> sources = nodes.stream().collect(groupingBy(e -> Objects.isNull(e.getPid()) ? ROOT : e.getPid()));//构造树List<TreeNode> tree = TreeUtils.buildTree(sources, ROOT, TreeNode::getId, TreeNode::setChildren);for (TreeNode node : tree) {Iterator iterator = node.iterator();while (iterator.hasNext()) {TreeNode child = (TreeNode) iterator.next();System.out.println(child.getId() + " " + child.getValue());}}}
}