目录
前言
UML
plantuml
类图
实战代码
Iterator
ArrayList
Client
自定义迭代器
TreeNode
TreeUtils
Client
前言
在实际开发过程中,常用各种集合来存储业务数据并处理,比如使用 List,Map,Set 等等集合来存储业务数据。存储在集合中的数据,往往需要遍历集合元素再进行相应的业务处理。
不同的集合类型有不同的数据结构,遍历的方式也各不相同。
而迭代器模式,就是用来简化这项工作,让开发者不必关心底层的数据结构是如何组织的,只需关注如何取用数据。它解决了数据的获取与表示之间的耦合问题,提升了集合管理的灵活性与可维护性。
UML
plantuml
@startuml 'https://plantuml.com/class-diagram interface Iterator { + hasNext() : boolean + next() : type } class ConcreteIterator { + hasNext() : boolean + next() : type } class Client { + iterator() : Iterator } Iterator <|.. ConcreteIterator Client ..> 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);
}
@Override
public boolean hasNext() {
return !stack.isEmpty();
}
@Override
public 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());
}
}
}
}