HashMap.values().addAll()异常

问题:在使用一个Collection.addAll()方法时报告UnsupportedOperationException。追溯原因发现该collection是来自于hashMap.values()。

分析原因:通过查看源代码,发现hashMap.values()实现如下:

   //HashMap.java
   public Collection<V> values() {
        Collection<V> vs = values;
        return (vs != null ? vs : (values = new Values()));
    }
    
      private final class Values extends AbstractCollection<V> {
        public Iterator<V> iterator() {
            return newValueIterator();
        }
        public int size() {
            return size;
        }
        public boolean contains(Object o) {
            return containsValue(o);
        }
        public void clear() {
            HashMap.this.clear();
        }
    }
    
    //其中values的定义如下:AbstractMap.java
      transient volatile Collection<V> values = null;
       public Collection<V> values() {
        if (values == null) {
            values = new AbstractCollection<V>() {
                public Iterator<V> iterator() {
                    return new Iterator<V>() {
                        private Iterator<Entry<K,V>> i = entrySet().iterator();

                        public boolean hasNext() {
                            return i.hasNext();
                        }

                        public V next() {
                            return i.next().getValue();
                        }

                        public void remove() {
                            i.remove();
                        }
                    };
                }

                public int size() {
                    return AbstractMap.this.size();
                }

                public boolean isEmpty() {
                    return AbstractMap.this.isEmpty();
                }

                public void clear() {
                    AbstractMap.this.clear();
                }

                public boolean contains(Object v) {
                    return AbstractMap.this.containsValue(v);
                }
            };
        }
        return values;
    }

从上面代码看到,hashMap.values()先看values是否为空:

  • 如果不为空,则直接返回values。values是在在AbstractMap中定义的,初始化时new了一个AbstractCollection,并实现了若干方法,但是并没有实现all()和addAll()方法。
  • 如果为空,则new一个内部实现类Values。Values同样没有实现AbstractCollection的没有实现all()和addAll()方法。

再来看一下AbstractCollection的add()和addAll()方法:

 //AbstractCollection.java
 public boolean add(E e) {
        throw new UnsupportedOperationException();
    }
    
 public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }

可以看到,add方法的实现是直接抛出UnsupportedOperationException,addAll方法调用add方法,也间接抛出异常,同样的,HashMap.values()调用add()和addAll()也会抛出异常。

结论:通过以上分析,明确了HashMap.values()调用add()和addAll()抛出异常的原因。也告诉我们在实际使用中,要注意避免直接使用HashMap.values().add()和HashMap.values().addAll()。

时间: 2024-10-29 19:06:14

HashMap.values().addAll()异常的相关文章

Java 之HashMap.values()方法误用

1.出错 今天在测试代码的时候发现程序报错,看代码才知道是使用HashMap.values()方法的时候出错.因为项目中需要获取Map的值的集合然后进行遍历,所以就很自然的调用了HashMap.values()方法,如下所示 package collections; import java.util.HashMap; import java.util.List; import java.util.Map; public class Test { /** * @param args */ publ

jdk7 HashMap阅读笔记

基于版本jdk1.7.0_80 java.util.HashMap 代码如下 /* * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package java.util;

JAVA API HashMap 分析

AbstractMap: 数据结构: Entry<K,V> 是 Map接口内部的一个接口,在具体的实现类中会被实现成不同静态内部类,他们有不同的的键值对结构.Set<K> keySet();Collection<V> values(); transient volatile Set<K> keySet = null;transient volatile AbstractCollection<V> values = null;keySet,valu

【集合之HashMap】HashMap实现原理及非线程安全原因

要知道HashMap是什么,首先要搞清楚它的数据结构,在Java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外.HashMap实际上是一个数组和链表的结合体(在数据结构中,一般称之为“链表散列“). 从图中我们可以看到一个HashMap就是一个数组结构,当新建一个HashMap的时候,就会初始化一个数组. HashMap源码中的3个常量, 1 /** 2 * The default initial c

hashmap&amp;concurrenthashMap

让HashMap陷入死循环 多线程下HashMap陷入死循环的场景,get/put都会陷入死循环的风险 public class HashMapDead { private static Logger logger = Logger.getLogger("hashMapDead"); private static long Cycle = 100000; public static void main(String[] args) throws InterruptedException

HashMap概述及其三种遍历方式

一.HashMap概述: 1.HashMap是一个散列表,它存储的是键值对(key-value)映射: 2.HashMap继承AbstractMap,实现了Map,Cloneable,Serializable接口: 3.HashMap的实现不是同步的,线程不安全,但是效率高: 4.HashMap允许null键和null值,是基于哈希表的Map接口实现: 5.哈希表的作用是用来保证键的唯一性: 6.HashMap的实例有两个参数影响其性能:初试容量和加载因子,当哈希表中的条目数超出加载因子与当前容

Map-HashMap-LinkedHashMap-Map.Entry-Collections-可变参数

一.Map 接口(java.util) 定义:public interface Map<K,V> 介绍:     (1)Map是一个接口,含有两个泛型,创建子类对象的时候,需要传递两个泛型的值;     (2)将键映射到值的对象.一个映射不能包含重复的键:每个键最多只能映射到一个值.(值可以重复)     (3)Map集合是双列集合的顶层接口,Map中的方法,所有的子类都可以使用; 特点:     (1)所有的键(K)必须唯一不能重复;     (2)操作数据(增删改查)的时候,都是以键值对的

里氏替换原则(Liskov Substitution Principle, LSP)

以此回顾所读<设计模式之禅>与<高校程序员的45个习惯>中Liskov部分 定义: 第一种:If for each object O1 of type S there is an object O2 fo type T such that for all programs P defined in terms of T, the behavior of P is unchanged when O1 is substitueted for O2 then S is a subtype

Java培训第二周小结

import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Scanner; i