如何声明可保留引用值的ListIterator 解决调用displayNextPhoto的异常问题
问题解决方案
一、迭代器状态保留(解决每次仅展示第一张照片的问题)
你当前问题的根源是每次调用displayNextPhoto方法时,都在方法内部新建了ListIterator实例,迭代器每次都会从列表头部开始遍历,自然每次都返回第一张照片。要保留迭代器的遍历进度,只需将迭代器改为Album类的成员变量,仅在首次调用/需要重置遍历进度时初始化即可。
修改后的代码示例:
Album类新增成员变量
public class Album { // 原有成员变量 private List<Photo> photos; private boolean goingForward = false; // 新增:存储迭代器实例,保留遍历状态 private ListIterator<Photo> listIterator; // 新增:提供重置遍历进度的方法,需要从头开始看照片时调用即可 public void resetPhotoIterator() { this.listIterator = photos.listIterator(); } // 修改后的displayNextPhoto方法 public void displayNextPhoto(){ // 首次调用未初始化时自动创建迭代器 if(listIterator == null) { listIterator = photos.listIterator(); } if(listIterator.hasNext()){ Photo photo = listIterator.next(); System.out.println("Displaying "+photo.getName()+" on "+photo.getDate()); goingForward = true; } else{ System.out.println("End of album"); } } // 其他原有方法 }
二、并发修改异常解决
ConcurrentModificationException触发的原因是:迭代器创建之后,你在其他代码位置直接修改了photos列表的结构(增/删元素),ArrayList迭代器的fail-fast检测机制就会抛出该异常,可根据你的业务场景选择以下解决方案:
- 如果遍历期间不需要修改相册列表内容:保证所有对
photos的增删操作都在首次调用displayNextPhoto之前完成,或者每次修改完photos列表后主动调用resetPhotoIterator()重置迭代器即可。 - 如果遍历期间需要修改相册列表内容:不要直接调用
photos.add()/photos.remove()方法,改用迭代器自带的listIterator.add()/listIterator.remove()方法修改列表结构。 - 如果涉及多线程同时操作相册:可以把
photos的实现类换成CopyOnWriteArrayList,它的迭代器是快照式实现,不会触发并发修改异常;多线程调用时也可以给操作方法加synchronized同步锁,避免线程安全问题。
注意:如果同时实现了上一张照片的回退逻辑,要注意goingForward变量和迭代器状态的同步,避免出现顺序错乱的问题
内容的提问来源于stack exchange,提问作者محمد المغربى
相关产品推荐
相关产品推荐

