温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么在Java中利用Set&List实现迭代器

发布时间:2021-05-27 18:05:05 来源:亿速云 阅读:185 作者:Leah 栏目:编程语言

本篇文章给大家分享的是有关怎么在Java中利用Set&List实现迭代器,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

ArrayList

private class Itr implements Iterator<E> {
    int cursor;    // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;

    // prevent creating a synthetic constructor
    Itr() {}

    public boolean hasNext() {
      return cursor != size;
    }

    @SuppressWarnings("unchecked")
    public E next() {
      checkForComodification();
      int i = cursor;
      if (i >= size)
        throw new NoSuchElementException();
      Object[] elementData = ArrayList.this.elementData;
      if (i >= elementData.length)
        throw new ConcurrentModificationException();
      cursor = i + 1;
      return (E) elementData[lastRet = i];
    }

    public void remove() {
      if (lastRet < 0)
        throw new IllegalStateException();
      checkForComodification();

      try {
        ArrayList.this.remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        expectedModCount = modCount;
      } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
      }
    }
  }

从代码中我们不难看出迭代器维护上一次return的元素下边和下一个将要return的元素下标,并且迭代器在进行修改操作时会检查在本次操作与上次操作之间是否有迭代器以外的操作,并且适时抛出ConcurrentModificationException(并发修改异常)来阻止更多错误的发生

LinkedList

private class ListItr implements ListIterator<E> {
    private Node<E> lastReturned;
    private Node<E> next;
    private int nextIndex;
    private int expectedModCount = modCount;

    ListItr(int index) {
      // assert isPositionIndex(index);
      next = (index == size) ? null : node(index);
      nextIndex = index;
    }

    public boolean hasNext() {
      return nextIndex < size;
    }

    public E next() {
      checkForComodification();
      if (!hasNext())
        throw new NoSuchElementException();

      lastReturned = next;
      next = next.next;
      nextIndex++;
      return lastReturned.item;
    }

    public boolean hasPrevious() {
      return nextIndex > 0;
    }

    public E previous() {
      checkForComodification();
      if (!hasPrevious())
        throw new NoSuchElementException();

      lastReturned = next = (next == null) ? last : next.prev;
      nextIndex--;
      return lastReturned.item;
    }

    public int nextIndex() {
      return nextIndex;
    }

    public int previousIndex() {
      return nextIndex - 1;
    }

    public void remove() {
      checkForComodification();
      if (lastReturned == null)
        throw new IllegalStateException();

      Node<E> lastNext = lastReturned.next;
      unlink(lastReturned);
      if (next == lastReturned)
        next = lastNext;
      else
        nextIndex--;
      lastReturned = null;
      expectedModCount++;
    }

    public void set(E e) {
      if (lastReturned == null)
        throw new IllegalStateException();
      checkForComodification();
      lastReturned.item = e;
    }

    public void add(E e) {
      checkForComodification();
      lastReturned = null;
      if (next == null)
        linkLast(e);
      else
        linkBefore(e, next);
      nextIndex++;
      expectedModCount++;
    }

    public void forEachRemaining(Consumer<? super E> action) {
      Objects.requireNonNull(action);
      while (modCount == expectedModCount && nextIndex < size) {
        action.accept(next.item);
        lastReturned = next;
        next = next.next;
        nextIndex++;
      }
      checkForComodification();
    }

    final void checkForComodification() {
      if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    }
  }

LinkedList的迭代器类的实现逻辑与ArrayList大致相近但是其访问元素的方式由原来的下标变为 "指针"(Java强引用)

Set

通过看Java源码可以知道Set全家桶基本上都包含了Map,相当于是一种组合的方式

HashSet

构造方法

HashSet有多个构造方法但都是初始化一个HashMap或其子类

/**
   * Constructs a new, empty set; the backing {@code HashMap} instance has
   * default initial capacity (16) and load factor (0.75).
   */
  public HashSet() {
    map = new HashMap<>();
  }

  /**
   * Constructs a new set containing the elements in the specified
   * collection. The {@code HashMap} is created with default load factor
   * (0.75) and an initial capacity sufficient to contain the elements in
   * the specified collection.
   *
   * @param c the collection whose elements are to be placed into this set
   * @throws NullPointerException if the specified collection is null
   */
  public HashSet(Collection<? extends E> c) {
    map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
    addAll(c);
  }

  /**
   * Constructs a new, empty set; the backing {@code HashMap} instance has
   * the specified initial capacity and the specified load factor.
   *
   * @param   initialCapacity  the initial capacity of the hash map
   * @param   loadFactor    the load factor of the hash map
   * @throws   IllegalArgumentException if the initial capacity is less
   *       than zero, or if the load factor is nonpositive
   */
  public HashSet(int initialCapacity, float loadFactor) {
    map = new HashMap<>(initialCapacity, loadFactor);
  }

  /**
   * Constructs a new, empty set; the backing {@code HashMap} instance has
   * the specified initial capacity and default load factor (0.75).
   *
   * @param   initialCapacity  the initial capacity of the hash table
   * @throws   IllegalArgumentException if the initial capacity is less
   *       than zero
   */
  public HashSet(int initialCapacity) {
    map = new HashMap<>(initialCapacity);
  }

  /**
   * Constructs a new, empty linked hash set. (This package private
   * constructor is only used by LinkedHashSet.) The backing
   * HashMap instance is a LinkedHashMap with the specified initial
   * capacity and the specified load factor.
   *
   * @param   initialCapacity  the initial capacity of the hash map
   * @param   loadFactor    the load factor of the hash map
   * @param   dummy       ignored (distinguishes this
   *       constructor from other int, float constructor.)
   * @throws   IllegalArgumentException if the initial capacity is less
   *       than zero, or if the load factor is nonpositive
   */
  HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
  }

iterator方法

该接口在HashSet中的实现相当的简单,可以看到iterator返回了keySet().iterator()

public Iterator<E> iterator() {
    return map.keySet().iterator();
  }

HashMap的KeySet

从这一处代码可以看到iterator()返回了对象 KeyIterator

final class KeySet extends AbstractSet<K> {
    public final int size()         { return size; }
    public final void clear()        { HashMap.this.clear(); }
    public final Iterator<K> iterator()   { return new KeyIterator(); }
    public final boolean contains(Object o) { return containsKey(o); }
    public final boolean remove(Object key) {
      return removeNode(hash(key), key, null, false, true) != null;
    }
    public final Spliterator<K> spliterator() {
      return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
    }
    public final void forEach(Consumer<? super K> action) {
      Node<K,V>[] tab;
      if (action == null)
        throw new NullPointerException();
      if (size > 0 && (tab = table) != null) {
        int mc = modCount;
        for (Node<K,V> e : tab) {
          for (; e != null; e = e.next)
            action.accept(e.key);
        }
        if (modCount != mc)
          throw new ConcurrentModificationException();
      }
    }
  }

HashMap的KeyIterator

KeyIterator是HashIterator一个子类在此一并展示了,这个类从字段结构上跟LinkedList的ListItr还是很像的

获取next的机制 Node<K,V> 内部本身包含一个next引用当HashIterator或其子类对象调用方法nextNode时,若该引用非空者优先返回该引用指向的对象,否则掩盖引用的index在HashMap内部的 Node<K,V> 数组table中向后找, 直到找到一个不为空的引用,或者到table结束也没有找到, 那么此时返回空引用

abstract class HashIterator {
    Node<K,V> next;    // next entry to return
    Node<K,V> current;   // current entry
    int expectedModCount; // for fast-fail
    int index;       // current slot

    HashIterator() {
      expectedModCount = modCount;
      Node<K,V>[] t = table;
      current = next = null;
      index = 0;
      if (t != null && size > 0) { // advance to first entry
        do {} while (index < t.length && (next = t[index++]) == null);
      }
    }

    public final boolean hasNext() {
      return next != null;
    }

    final Node<K,V> nextNode() {
      Node<K,V>[] t;
      Node<K,V> e = next;
      if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
      if (e == null)
        throw new NoSuchElementException();
      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;
      removeNode(p.hash, p.key, null, false, false);
      expectedModCount = modCount;
    }
  }

  final class KeyIterator extends HashIterator
    implements Iterator<K> {
    public final K next() { return nextNode().key; }
  }

以上就是怎么在Java中利用Set&List实现迭代器,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI