【Java入门】数据结构(五)从 Iterator 到 各种遍历

文章目录

  • 迭代器模式
  • Iterator 接口
  • 对比 Iterable 与 Enumeration
    • Iterable 接口
    • Enumeration 接口
  • ListIterator 接口
  • 三类集合的遍历盘点

迭代器模式

首先,回顾一下迭代器模式这种设计模式。

概述

提供一种方法顺序访问一个聚合对象中各个元素,且不用暴露该对象的内部表示。

将遍历数据的行为从聚合对象中分离出来,封装在迭代器对象中。由迭代器来提供遍历聚合对象内部数据的行为,简化聚合对象的设计,更符合单一职责原则(一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中)。

结构

迭代器模式包含:

  • 迭代器角色(Iterator): 负责定义访问和遍历元素的接口。
  • 具体迭代器角色(Concrete Iterator):实现迭代器接口,并要记录遍历中的当前位置。
  • 容器角色(Container): 负责提供创建具体迭代器角色的接口。
  • 具体容器角色(Concrete Container):实现创建具体迭代器角色的接口, 这个具体迭代器角色与该容器的结构相关。
    在这里插入图片描述
    以销售管理系统为例:
    其中具体聚合类是商品数据类,具体迭代器是商品迭代器。用迭代器模式设计后,商品数据类只负责存储和管理数据,商品迭代器只负责遍历数据。前者对后者是依赖关系(方法使用另一个类的对象作为参数),后者对前者是关联关系。
    在这里插入图片描述

Iterator 接口

public interface Iterator

对 collection 进行迭代的迭代器。

方法摘要

方法名 说明
boolean hasNext() 如果仍有元素可以迭代,则返回 true。
E next() 返回迭代的下一个元素。
void remove() 从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。

迭代出来的元素都是原来集合元素的拷贝。(Java集合中保存的元素实质是对象的引用,而非对象本身;所以迭代出的对象也是引用的拷贝,结果还是引用)
如果集合中保存的元素是可变类型的,那么可以通过迭代出的元素修改原集合中的对象。

使用样例

Iterator<String> iterator = list.iterator();        //如果是List或Set的实现类对象直接获取
// Iterator> it = map.entrySet().iterator();
// 如果是Map的实现类对象则先得到entry再获取

//iterator.hasNext()如果存在元素的话返回true
while(iterator.hasNext()) {
    //iterator.next()返回迭代的下一个元素
    System.out.println(iterator.next());
}

对比 Iterable 与 Enumeration

Iterable 接口

实现这个接口允许对象成为 “foreach” 语句的目标。

功能、实现和使用也很简单。

public interface Iterable<T>
{ 
    Iterator<T> iterator();
}

使用就是典型的 foreach 语句:

for(Type t0 : oneColletionOrArray){
	... do something with t0 ...
}

foreach语句是for语句特殊情况下的增强版本,简化了编程,提高了代码的可读性和安全性(不用怕数组越界)。相对老的for语句来说是个很好的补充。提倡能用foreach的地方就不要再用for了。在用到数组索引的情况下,foreach则显得力不从心。另外,foreach一般结合泛型使用。

for循环与迭代器Iterator对比:(参考)

从数据结构角度分析,for循环适合访问顺序结构,可以根据下标快速获取指定元素。而Iterator 适合访问链式结构,因为迭代器是通过next()和Pre()来定位的,可以访问没有顺序的集合。

例如:采用ArrayList对随机访问比较快,而for循环中的get()方法,采用的即是随机访问的方法,因此在ArrayList里,for循环较快。 采用LinkedList则是顺序访问比较快,iterator中的next()方法,采用的即是顺序访问的方法,因此在LinkedList里,使用iterator较快。

Enumeration 接口

实现 Enumeration(枚举)接口的对象,它生成一系列元素,一次生成一个。连续调用 nextElement 方法将返回一系列的连续元素。

方法摘要

方法名 说明
boolean hasMoreElements() 测试此枚举是否包含更多的元素。
E nextElement() 如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。

下面是一个使用的例子:

//e is an object that implements the Enumeration interface
//如: Enumeration enumeration = hashtable.elements();
while (e.hasMoreElements()) {
    Object o= e.nextElement();
    System.out.println(o);

Iterator 与 Enumeration 的区别

  1. 函数接口不同。
    Enumeration只有2个函数接口。通过Enumeration,只能读取集合的数据,而不能对数据进行修改。而Iterator只有3个函数接口。Iterator除了能读取集合的数据之外,也能数据进行删除操作(虽然不常用)。
  2. Iterator支持fail-fast机制,而Enumeration不支持。
    Enumeration 是JDK 1.0添加的接口。使用到它的函数包括Vector、Hashtable等类,这些类都是JDK 1.0中加入的,Enumeration存在的目的就是为它们提供遍历接口。Enumeration本身并没有支持同步,而在Vector、Hashtable实现Enumeration时,添加了同步。
    而Iterator 是JDK 1.2才添加的接口,它也是为了HashMap、ArrayList等集合提供遍历接口。Iterator是支持fail-fast机制的:当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。

ListIterator 接口

public interface ListIterator
	extends Iterator

系列表迭代器。继承了Iterator接口。允许按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。

ListIterator 没有当前元素;它的光标位置始终位于调用 previous() 所返回的元素和调用 next() 所返回的元素之间。

方法摘要
【Java入门】数据结构(五)从 Iterator 到 各种遍历_第1张图片
用法样例

ListIterator<String> iter = all.listIterator();
System.out.print("由前向后遍历:");
while (iter.hasNext()) {
    System.out.print(iter.next()+"、");
}
System.out.print("\n由后向前遍历:");
while (iter.hasPrevious()) {
    System.out.print(iter.previous()+"、");
}

Iterator和ListIterator区别:(参考)

(1)ListIterator有 add() 方法,可以向List中添加对象,而Iterator不能。
(2)ListIterator 和 Iterator 都有 hasNext() 和 next() 方法,可以实现顺序向后遍历,但是ListIterator有 hasPrevious() 和 previous() 方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
(3)ListIterator可以定位当前的索引位置,nextIndex() 和 previousIndex() 可以实现。Iterator没有此功能。
(4)都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。

三类集合的遍历盘点

三类集合使用Iterator或for进行遍历时候的用法样例和注意事项。感谢这篇博客:https://www.cnblogs.com/alwayswyy/p/6426113.html

List :

public class testArrayList {
    public static void main(String args[]) {
        f1();
        f2();
    }
    public static void f1(){
        List<String> strList = new ArrayList<String>();
        for (int i = 0; i < 10; i++)
        {
            strList.add("string" + i);
        }

        Iterator<String> iterator = strList.iterator();//list.iterator()
        while (iterator.hasNext())  //判断集合中元素是否遍历完毕,如果没有,就返回true
        {
            if (iterator.next().equals("string3"))
            {
                iterator.remove();  //iterator.remove()移除的是最近一次iterator.next()所获取的对象
            }
        }
        iterator = strList.iterator();//此步非常重要,删除后要重新定义迭代器
        while (iterator.hasNext())
        {
            System.out.println(iterator.next()); //iterator.next() 返回下一个元素
        }
    }

        public static void f2() {
            ArrayList arrayList = new ArrayList();
            arrayList.add("wyy");  //arrayList.add
            arrayList.add("12");
            arrayList.add("huhu");
            arrayList.add("897");

            System.out.println("输出整个arraylist" + arrayList);  //[wyy, 12, huhu, 897]

            for (int i = 0; i < arrayList.size(); i++) {
                System.out.println(arrayList.get(i));
            }

            Iterator<String> a = arrayList.iterator();
            System.out.println("剩下的元素有:");
            while (a.hasNext()) {
                if (a.next().equals("12")) {
                    a.remove();
                }
            }
			//用for循环,可以节约内存,开发时一般使用
            for( a = arrayList.iterator(); a.hasNext();)//注意,如果判断结果后删除,必须重新对迭代器进行定义,才能取出剩余的数据
            {
                System.out.println(a.next());
            }
        }

}

Set :

public class SetTest {
    public static void main(String[] args) {
	//set常用的方法:
        Set set = new HashSet();
        set.add("wq");
        set.add("er");
        set.add("er");
        set.add("gee");
        set.add("wdd");
        set.add("3242");
        System.out.println(set);
        Set sortedSet = new TreeSet(set); //添加的元素必须是有效,即可比较排序的,用compareTo
     /* sortedSet.add(new SetTest());
        报错:collection.SetTest cannot be cast to java.lang.Comparable  add的元素必须是可以比较的*/
        System.out.println(sortedSet); //[3242, er, gee, wdd, wq],列表的第二次输出已按字母顺序排序。
        String a="a";
        String b="a";
        System.out.println(a.hashCode());//65
        System.out.println(b.hashCode());//97

        Iterator iterator=set.iterator();//创建一个集合的迭代器,用来取元素
        while (iterator.hasNext()){
              Object obj = iterator.next();
            System.out.println(obj);
        }
    }
}

Map :

public class MapTest {
    public static void main(String[] args) {
        Map<Integer,String> map=new HashMap<>();
        map.put(1,"wo");
        map.put(2,"chi");
        map.put(3,"xi");
        map.put(4,"gua");
        System.out.println(map.size());
        
		/*方法1:使用set存储key的值,然后用for循环获取value的值(效率差)*/
        Set<Integer> set=map.keySet();//获取所有key的值
        for (int i:set ) {
            String value=map.get(i);  //获取value的值
            System.out.println(value);
        }

		/*方法2:使用Map.entrySet<>构造iterator遍历key和value*/
        Iterator<Map.Entry<Integer,String>> it=map.entrySet().iterator();
        while (it.hasNext()){
            Map.Entry<Integer,String> entry=it.next();
            System.out.println("the key is:"+entry.getKey()+",and the value is:"+entry.getValue());

        }

		/*方法3:推荐,通过Map.entrySet遍历key和value,特别是大容量时 */
        for (Map.Entry<Integer,String> en:map.entrySet()){
            System.out.println("the key is:"+en.getKey()+",and the value is:"+en.getValue());
        }
        
		/* 方法4:只能得到value的值  */
        for (String v1:map.values() ) {
            System.out.println("the value is:"+v1);
        }

    }
}

你可能感兴趣的:(JAVA入门)