java迭代器原理及迭代map的四种方式

目录
  • 迭代器原理:
    • 什么是迭代器,使用迭代器的好处?
    • 迭代器怎么实现的?
    • 迭代器的陷阱?
    • 为什么会产生这样的错误?
  • 遍历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

到此这篇关于java迭代器原理及迭代map的四种方式的文章就介绍到这了,更多相关java迭代map内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java实现的自定义迭代器功能示例

    本文实例讲述了Java实现的自定义迭代器功能.分享给大家供大家参考,具体如下: 编写自己的Iterator,实现Iterator接口,这里多说一句,实现Iterable后,可以用"foreach"循环遍历你的对象. import java.util.Iterator; import java.util.NoSuchElementException; /** * 演示Iterator和Iterable接口,并说明怎样编写一个用于对象数组的简单迭代器. */ public class Aa

  • java 迭代器模式实例详解

    java 迭代器模式实例详解 今天来818设计模式中的迭代器模式,也是java中Stack,List,Set等接口以及数组这个数据结构都会使用的一种模式. 首先,为什么使用迭代器模式,目的就是通过一个通用的迭代方法,隐藏stack,list,set以及数组中不同的遍历细节.也就是说,我不想让那些调用我的遍历容器的方法的人知道我到底是怎么一个一个的获取这些元素的(stack的pop,list的get,数组的array[i]),我只想让他知道他能 通过一个迭代器Iterator或者通过一个for e

  • 详解Java中Iterator迭代器的用法

    迭代器(Iterator) 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构.迭代器通常被称为"轻量级"对象,因为创建它的代价小. Java中的Iterator功能比较简单,并且只能单向移动: (1) 使用方法iterator()要求容器返回一个Iterator.第一次调用Iterator的next()方法时,它返回序列的第一个元素.注意:iterator()方法是java.lang.Iterable接口,被Collection继承

  • Java集合框架中迭代器Iterator解析

    Java里面的数组数据可以通过索引来获取,那么对象呢?也是通过索引吗?今天我们就来分析一下Java集合中获取集合对象的方法迭代-Iterator. 本篇文章主要分析一下Java集合框架中的迭代器部分,Iterator,该源码分析基于JDK1.8,分析工具,AndroidStudio,文章分析不足之处,还请指正! 一.简介 我们常常使用 JDK 提供的迭代接口进行 Java 集合的迭代. Iterator iterator = list.iterator(); while(iterator.has

  • java 中迭代器的使用方法详解

    java 中迭代器的使用方法详解 前言: 迭代器模式将一个集合给封装起来,主要是为用户提供了一种遍历其内部元素的方式.迭代器模式有两个优点:①提供给用户一个遍历的方式,而没有暴露其内部实现细节:②把元素之间游走的责任交给迭代器,而不是聚合对象,实现了用户与聚合对象之间的解耦. 迭代器模式主要是通过Iterator接口来管理一个聚合对象的,而用户使用的时候只需要拿到一个Iterator类型的对象即可完成对该聚合对象的遍历.这里的聚合对象一般是指ArrayList,LinkedList和底层实现为数

  • java迭代器和for循环优劣详解

    在进行迭代的时候,程序运行的效率也是我们挑选迭代方法的重要原因.目前有三种迭代方法:for循环.迭代器和Foreach.前两者相信大家都非常熟悉,为了更加直观分析效率的不同,我们还加入Foreach一起比较.下面我们就三种方法的概念进行理解,然后ArrayList中探索三种方法的效率. 1.概念理解 for循环:是支持迭代的一种通用结构,是最有效,最灵活的循环结构 迭代器:是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的 Foreach:通过阅读源码我们还发现一个It

  • Java基础教程之HashMap迭代删除使用方法

    前言 map的迭代删除,和我们常见的list,set不太一样,不能直接获取Iteraotr对象,提供的删除方法也是单个的,根据key进行删除,如果我们有个需求,将map中满足某些条件的元素删除掉,要怎么做呢? I. Map 迭代删除 迭代删除,在不考虑并发安全的前提下,我们看下可以怎么支持 1. 非常不优雅版本 我们知道map并不是继承自Collection接口的,HashMap 也没有提供迭代支持,既然没法直接迭代,那我就老老实的low b版好了 Map<String, Integer> m

  • java迭代器原理及迭代map的四种方式

    目录 迭代器原理: 什么是迭代器,使用迭代器的好处? 迭代器怎么实现的? 迭代器的陷阱? 为什么会产生这样的错误? 遍历map的四种方式 迭代器原理: 什么是迭代器,使用迭代器的好处? 迭代器就是用来遍历集合中对象的东西,也就是说,对于集合,我们不像对原始数组那样通过直接访问元素来迭代的,而是通过迭代器来遍历对象.这么做的好处是将对于集合类型的遍历行为与被遍历集合对象分离,这样以来,就不需要关心该集合类型的具体实现是怎么样的.只要获取这个集合对象的迭代器便可以遍历这个集合中的对象.而像遍历对象顺

  • Java FineReport报表工具导出EXCEL的四种方式

    在实际的应用中会经常需要将数据导出成excel,导出的方式除原样导出还有分页导出.分页分sheet导出和大数据量导出.对于excel2003版,限制了每个sheet的最大行数和列数,大数据量导出时会默认时分多个sheet,而excel2007不会出现这样的问题.这些导出方式在JAVA程序中分别有不同的接口来实现: 1. 原样导出 原样导出就是不预览直接导出excel 其程序接口代码如下: outputStream = new FileOutputStream(new File("E:\\Exce

  • Java实现PDF在线预览功能(四种方式)

    目录 Java实现PDF在线预览 Java快捷实现PDF在线预览 Java实现PDF在线预览 @RequestMapping("/preview1") public void er(HttpServletResponse response){ File file = new File("G:\\桌面\\Thymeleaf3.0中文翻译文档@www.java1234.com.pdf"); if (file.exists()){ byte[] data = null;

  • Java遍历Map四种方式讲解

    Java中遍历Map的四种方式 在java中所有的map都实现了Map接口,因此所有的Map(如HashMap, TreeMap, LinkedHashMap, Hashtable等)都可以用以下的方式去遍历. 方法一:在for循环中使用entries实现Map的遍历: /** * 最常见也是大多数情况下用的最多的,一般在键值对都需要使用 */ Map <String,String>map = new HashMap<String,String>(); map.put("

  • Java遍历Map对象的四种方式

    关于java中遍历map具体哪四种方式,请看下文详解吧. 方式一 这是最常见的并且在大多数情况下也是最可取的遍历方式.在键值都需要时使用. Map<Integer, Integer> map = new HashMap<Integer, Integer>(); for (Map.Entry<Integer, Integer> entry : map.entrySet()) { System.out.println("Key = " + entry.g

  • Java中遍历ConcurrentHashMap的四种方式详解

    这篇文章主要介绍了Java中遍历ConcurrentHashMap的四种方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 方式一:在for-each循环中使用entries来遍历 System.out.println("方式一:在for-each循环中使用entries来遍历");for (Map.Entry<String, String> entry: map.entrySet()) { System.out.pr

  • Java详解实现多线程的四种方式总结

    目录 前言 一.四种方式实现多线程 1.继承Thread类创建线程 2.实现Runnable接口创建线程 3.实现Callable接口 4.实现有返回结果的线程 二.多线程相关知识 1.Runnable 和 Callable 的区别 2.如何启动一个新线程.调用 start 和 run 方法的区别 3.线程相关的基本方法 4.wait()和 sleep()的区别 5.多线程原理 前言 Java多线程实现方式主要有四种: ① 继承Thread类.实现Runnable接口 ② 实现Callable接

  • 详解JAVA中获取文件MD5值的四种方法

    JAVA中获取文件MD5值的四种方法其实都很类似,因为核心都是通过JAVA自带的MessageDigest类来实现.获取文件MD5值主要分为三个步骤,第一步获取文件的byte信息,第二步通过MessageDigest类进行MD5加密,第三步转换成16进制的MD5码值.几种方法的不同点主要在第一步和第三步上.具体可以看下面的例子: 方法一. private final static String[] strHex = { "0", "1", "2"

  • java 创建线程的四种方式

    1.继承Thread类方式 这种方式适用于执行特定任务,并且需要获取处理后的数据的场景. 举例:一个用于累加数组内数据的和的线程. public class AdditionThread extends Thread { private int sum = 0; private int[] nums; ​ public AdditionThread(int[] nums, String threadName) { super(threadName); this.nums = nums; } ​

  • 详解Java创建多线程的四种方式以及优缺点

    java有以下四种创建多线程的方式 1:继承Thread类创建线程 2:实现Runnable接口创建线程 3:使用Callable和FutureTask创建线程 4:使用线程池,例如用Executor框架创建线程 DEMO代码 package thread; import java.util.concurrent.*; public class ThreadTest { public static void main(String[] args) throws ExecutionExceptio

随机推荐