SafeIterableMap

SafeIterableMap

LinkedList, which pretends to be a map and supports modifications during iterations. It is NOT thread safe.

  1. 其底层用时链表(双向)实现,pretends to be (假装) map.
  2. 支持在迭代过程中直接修改(调用其自身的put 或者remove),比如删除,添加 。其他集合需要通过其Iterator 来实现对集合的修改。否则会抛出ConcurrentModificationException,虽然Iterator 支持迭代过程中删除,但并不是所有的Iterrator都支持迭代过程中添加,
  3. 线程不安全
  4. 一般不能直接在项目中使用,Studio 会变红,但是不影响正常编译和使用,可以通过添加注解@SuppressLint("RestrictedApi") 来抑制警告
  5. 在迭代过程中不能像其他集合一样调用 Iterator 的remove 方法,其默认实现是抛出 UnsupportedOperationException

概述

SafeIterableMap 他是google工程师在 Androidx 中提供的一个简单数据结构,非线程安全,以键值对方式存取数据,看似一个map,其底层是一个双向链表,每一个键值对被包装成一个 Entry<K,V> 被保存。支持双向遍历,并且支持在迭代过程中直接对集合的修改(直接调用map的put 或者remove方法,比如添加删除,不能调用Iteratorr的remove方法)。其他集合在迭代过程中只能通过Iterator进行修改操作。并且不是所有的Iterator 都支持添加,只有List 中的ListIterator 支持添加操作,当然SafeIterableMap 支持迭代过程中支持修改操作,是因为他自己实现的Iterator 支持了, SafeIterableMap 一共有三个 Iterator 实现类,AscendingIterator (顺序迭代),DescendingIterator (反向迭代)IteratorWithAdditions(顺序迭代,支持添加操作),三个都实现了SupportRemove 接口,并且实现了SupportRemove接口中的supportRemove方法,该方法就是用来当 SafeIterableMapEntry 被删除时,让Iterator 感知到,使其把对SafeIterableMap 的修改同步到Iterator 中。因此 这三个Iterator 都支持迭代过程中删除,但是只有IteratorWithAdditions支持迭代过程中添加新的。其他两个Iteratro 在迭代的时候调用SafeIterableMap 的put方法不会抛出异常,只是不能迭代到新put的数据而已。

因为我们到知道其他集合不支持在迭代过程中直接调用集合的修改方法对集合进行修改,就是因为集合中有一个变量 modCount 记录了集合修改的次数,每修改一次 modCount 都会加一,迭代集合时Iterator 在被创建出来(new)的时记录了集合当前的一个状态,比如集合的修改次数modCount ,集合的size等,在调用Iterator方法进行迭代的时候会去判断Iterator 中记录的modCount 次数是否和集合中最新的modCount 是否相等,如果相等意味着集合没有发生修改,如果不相等意味着集合一定发生了修改,直接抛出了ConcurrentModificationException

File Structure

在这里插入图片描述

源码解析



/**
 * LinkedList, which pretends to be a map and supports modifications during iterations.
 * It is NOT thread safe.
 * 一个底层用链表实现的类似与Map的集合,并且支持在迭代过程中对map 进行修改
 */

//这个注解导致了我们在项目代码中使用此api studio 会有警告提示,但不影响编译和正常运行。可以通过注解消除警告
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public class SafeIterableMap<K, V> implements Iterable<Map.Entry<K, V>> {
   
   

		//链表的头结点
    Entry<K, V> mStart;
  	// 链表的尾结点
    private Entry<K, V> mEnd;
  	
  

		/**
		 * using WeakHashMap over List<WeakReference>, so we don't have to manually remove
		 * WeakReferences that have null in them.
		 *
		 * 使用WeakHashMap代替List<WeakReference>,这样就不用再手动删除WeakReferences,
		 * 意思就是说,如果用List<WeakReference> 存储Iterator,其结构将是这样的List<WeakReference<Iterator>>
		 * 那么当Iterrator被回收后,还需要手动从List中把WeakReference这个对象删,用WeakHashMap则省掉了这个操作.
		 * 
		 * 该Map用来保存迭代时new 出来的迭代器,以便在调用 sefaIterableMap.remove()方法时通知到所有迭代器,更新迭代
		 * 器里面的状态,使迭代器能够响应 map 的修改,比如你在迭代过程中对map删除了某一个key,那么在迭代过程中,将不会获取
		 * 道这个entry.如果是使用InteratorWithAdditions这个迭代器,在迭代过程中还可以调用map.putIfAbsend方法添加一个
		 * 新的entry,别切会在迭代过程中会被输出
		 */

    private WeakHashMap<SupportRemove<K, V>, Boolean> mIterators = new WeakHashMap<>();
  
  	// map 中 元素的个数,也即是链表的长度
    private int mSize = 0;

  /**
   * 从头开始遍历链表中的每一个Eetry,如果entry.key equals 传入的key
   * 则返回该entry。如果链表为null,或者找不到对应的entry 返回null
   */
    protected Entry<K, V> get(K k) {
   
   
        Entry<K, V> currentNode = mStart;
        while (currentNode != null) {
   
   
            if (currentNode.mKey.equals(k)) {
   
   
                break;
            }
            currentNode = currentNode.mNext;
        }
        return currentNode;
    }

    /**
     * 如果不存在则保存,返回null
     * 如果已经存在则返回存在的旧值
     */
    public V putIfAbsent(@NonNull K key, @NonNull V v) {
   
   
        Entry<K, V> entry = get(key);
        if (entry != null) {
   
   
            return entry.mValue;
        }
        put(key, v);
        return null;
    }
		
  	/**
  	 * 把key,value 包装成 Entry 插入到链表尾部,size++
  	 * 并返回新保存entry对象
  	 *
  	 */
    protected Entry<K, V> put(@NonNull K key, @NonNull V v) {
   
   
        Entry<K, V> newEntry = new Entry<>(key, v);
        mSize++;
        if (mEnd == null) {
   
    // 表示链表为null,首尾都指向这个newEntry
            mStart = newEntry;
            mEnd = mStart;
            return newEntry;
        }
				// 更新尾结点,使newEntry为新的尾结点
        mEnd.mNext = newEntry;
        newEntry.mPrevious = mEnd;
        mEnd = newEntry;
        return newEntry;

    }

    /**
     * Removes the mapping for a key from this map if it is present.
     *
     * @param key key whose mapping is to be removed from the map
     * @return the previous value associated with the specified key,
     * or {@code null} if there was no mapping for the key
     *
     *  从链表中移除一个key对应的entry,如果不存在返回null.如果存在返回这个entry.value
     */
    public V remove(@NonNull K key) {
   
   
      
        Entry<K, V> toRemove = get(key); //从头开始遍历链表,找到一个与key对应的entry
        if (toRemove == null) {
   
   
            return null; // 如果找不到,返回null
        }
        mSize--; // 如果找到了,size--
      
      	// 遍历还未被回收的iterator,通知其要删除一个entry,
      	// 这就是safeIterableMap 支持迭代过程中删除的关键代码
        if (
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皮克桃在写代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值