java迭代器原理及迭代map的四种方式
作者:dandeseed 发布时间:2021-08-27 12:04:30
目录
迭代器原理:
什么是迭代器,使用迭代器的好处?
迭代器怎么实现的?
迭代器的陷阱?
为什么会产生这样的错误?
遍历map的四种方式
迭代器原理:
什么是迭代器,使用迭代器的好处?
迭代器就是用来遍历集合中对象的东西,也就是说,对于集合,我们不像对原始数组那样通过直接访问元素来迭代的,而是通过迭代器来遍历对象。这么做的好处是将对于集合类型的遍历行为与被遍历集合对象分离,这样以来,就不需要关心该集合类型的具体实现是怎么样的。只要获取这个集合对象的迭代器便可以遍历这个集合中的对象。而像遍历对象顺序以及怎么访问对象元素这些细节,全部由它自己的迭代器来处理。
迭代器怎么实现的?
首先集合要先实现iterable接口来表示此对象是可以进行迭代的。而实现iterable接口的对象实现了iterator方法,这个方法返回了一个Iterator对象。一个迭代器对象需要Iterator接口中的方法:hasNext(),next(),remove()。remove()方法会删除最近一次调用的元素,如果remove()之前没有调用next()的话直接调用remove()会产生报错信息(IllegalStateException)。我们在进行对集合对象迭代的时候,next()会返回当前对象第一个对象并返回,然后next会指向下一个元素,hasNext方法就是看这个指针后面还有没有元素了。
迭代器的陷阱?
使用for迭代的时候不可以使用集合进行remove操作。这时候需要使用迭代器进行迭代,然后使用迭代器中的remove方法进行删除。
为什么会产生这样的错误?
remove()方法在删除元素的时候,还会修改一个修改次数的标志位modCount,如果iterator的expectedModCount与modCount的大小不相等时,会抛出一个ConcurrentModificationException异常。modCount的目的主要是为了防止当前对象迭代过程中存在其他线程对当前对象的修改。
// iterable接口源代码
public interface Iterable<T> {
/**
* Returns an iterator over elements of type {@code T}.
*
* @return an Iterator.
*/
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
// iterator接口源代码
public interface Iterator<E> {
/**
* 如果迭代拥有更多元素,那么返回true
*/
boolean hasNext();
/**
* 返回iteration中的下一个元素
*/
E next();
/**
* 如果删除一个集合中的元素没有调用这个方法,二十直接中集合中删除,那么这个迭代器的行为没有被指定
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
/**
* 遍历集合中的剩余元素(如果之前调用了两次next()那么只会遍历集合中剩余元素
* 使用案例:
* Iterator<Integer> it = map.keySet().iterator();
it.next();
it.next();
it.forEachRemaining(System.out::println);
*/
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
HashMap中实现迭代的核心代码:
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next; // 对象属性中的next是下一个值
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
// next = e.next 如果e.next为null,那么继续找数组下一个不为null的值
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
遍历map的四种方式
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
public class MapTest {
public static void main(String[] args) {
HashMap<Integer,Integer> map = new HashMap();
map.put(0,1);
map.put(2,2);
map.put(1,2);
map.put(4,5);
map.put(3,4);
// 遍历hashmap entry foreach
Set<Map.Entry<Integer,Integer>> ent = map.entrySet();
for(Map.Entry<Integer,Integer> entry:ent){
System.out.println(entry.getKey()+" : "+entry.getValue());
//map.remove(0);
}
System.out.println();
// 通过keySet或者values()遍历
Set<Integer> set = map.keySet();
for(Integer key:set){
System.out.println(key+" -- "+map.get(key));
}
Collection<Integer> set1 = map.values();
for(Integer val:set1){
System.out.println(val);
}
System.out.println();
// iterator原理是什么 通过iterator遍历map
Iterator<Map.Entry<Integer,Integer>> iter = map.entrySet().iterator();
while(iter.hasNext()){
Map.Entry entry = iter.next();
System.out.println(entry.getKey()+" : "+entry.getValue());
iter.remove();
}
System.out.println();
Iterator<Integer> keys = map.keySet().iterator();
while(keys.hasNext()){
int k = keys.next();
System.out.println(k+" -- "+ map.get(k));
}
}
}
参考链接:https://blog.csdn.net/fuzhongmin05/article/details/72460658
来源:https://blog.csdn.net/qq_41082953/article/details/120057402


猜你喜欢
- 本文实例介绍了手机号码归属地接口调用基于C#实现,分享给大家供大家参考,具体内容如下using System;using System.Co
- 前言最近在使用Spring框架时遇到了一些问题,主要是Spring的事务传播问题,一个不带事务的方法调用带事务的方法,有时候会出现不回滚的情
- WPF 实现面包屑控件框架使用.NET4 至 .NET6Visual Studio 2022创建 BreadCrumbBar.xa
- 错误Mybatis-Plus (简称MP) 是mybatis的一个增强工具,在mybatis的基础上只做增强不做改变,简化了开发效率。其实就
- 大家好,我是为广大程序员兄弟操碎了心的小编,每天推荐一个小工具/源码,装满你的收藏夹,每天分享一个小技巧,让你轻松节省开发效率,实现不加
- 说明:当程序中出现频繁变化的数据时,如果采用认为的方式进行修改并且编译打包则会导致代码的耦合性较高,不便于维护!所以能否为属性动
- 映射匹配兼容性前面我们已经能从表中查询出数据,并将数据封装到模型类中,这整个过程涉及到一张表和一个模型类:之所以数据能够成功的从表中获取并封
- Spring-Data-Redis项目(简称SDR)对Redis的Key-Value数据存储操作提供了更高层次的抽象,类似于Spring F
- Android绘图操作,通过继承View实现,在onDraw函数中实现绘图。下面是一个简单的例子:public class AndroidT
- 使用 AppbarLayout 和 MotionLayout 实现常用的布局效果前文我们讲了协调滚动的一些定义方式,我们在开发中常用的几种效
- 这一篇主要是用来介绍关于C#中的XML序列化的问题,这个相信大家一定会经常使用它,特别是在WPF中,有时候我们需要将我们后台的数据保存在数据
- 一、材料准备1、jdk1.8的安装包2、maven安装包3、idea工具二、配置jdk1.8环境变量1.jdk下载jdk下载网址(点击此链接
- 1.添加加载更多布局1_初始化和隐藏代码在RefreshListView构造方法中调用private void initFooterView
- 我们还是来讨论c++吧,这几年在c++里面玩代码自动生成技术,而预处理是不可避免,也是不可或缺的重要工具。虽然boost pp预处理库在宏的
- 概述在mvn clean install时,控制台各种报错,大概有:java:[8,52] 程序包com.xxx不存在java:[98,27
- 有时我们获取到了页面需要在Java代码中进行解析,获取html中的数据,Jsoup是一个很方便的工具。一、什么是Jsoup?官网网站:htt
- 本文实例为大家分享了JavaWeb实现用户登录与注册的具体代码,供大家参考,具体内容如下所用知识客户端:HTML CSS JS (JQuer
- 本文实例讲述了Android编程设计模式之中介者模式。分享给大家供大家参考,具体如下:一、介绍中介者模式(Mediator Pattern)
- 为大家分享的解决MyEclipse中的Building workspace问题的方法如下方法一:点击“Project”,取消勾选“Build
- 在Android里面,一些炫酷的动画确实是很吸引人的地方,让然看了就赏心悦目,一个好看的动画可能会提高用户对软件的使用率。另外说到动画,在A