Java集合框架:Collection和Map

作者:陆金龙    发表时间:2019-08-05 08:53   

关键词Collection,TreeSet ,EnumSet ,LinkedList,PriorityQueue,ArrayDequeMap,LinkedHashMap,IdentityHashMap,TreeMap,WeakHashMap,ConcurrentHashMap,锁分段

1.Java集合框架体系

Java集合框架:从Collection和Map两大根接口延伸出来的子接口和实现类。

1.1 Collection

Collection没有get方法来获取某个元素,只能通过Iterator遍历元素。

1.1.1 Set

不包含重复元素的集合,根据equals方法判读两个对象是否相同。

HashSet类 无序的,加入的元素要注意hashCode()方法的实现,元素可以是null。

LinkedHashset 继承自HashSet,使用链表维护元素次序,根据元素的hashCode值决定元素的存储位置。性能略低于HashSet(要维护插入顺序),迭代访问元素时会有好性能(采用链表维护了顺序)。

TreeSet 自动排序,实现SortedSet 接口。要排序,性能比HashSet差。

EnumSet 有序的,EnumSet中的所有元素都必须是指定枚举类型的枚举值。

1.1.2 List

可包含重复元素的集合。

Vector类  线程安全的,实现同步的。基于数组实现的List类。不推荐使用Vector类。

ArrayList类 基于数组实现的List类。

LinkedList类 有序的 基于链表实现的List类。

1.1.3 Queue

队列先进先出,出栈机制既保证了顺序,又不需要单独管理元素的删除。

队列不允许随机访问队列中的元素。

应用场景:耗时任务在主线程逐个处理容易产生阻塞,可在主线程中将要处理的任务暂存到一个队列里,由一个新的线程负责取出执行。

PriorityQueue类 已排序。

ArrayDeque类 双端队列。

1.2 Map

通用Map,用于在应用程序中管理映射,通常在 java.util 程序包中实现。

Map提供了一种映射关系,其元素是以键值对(key-value)的形式存储的,能够根据key查找value,key和value可以是任意类型的对象。

key和value属于Entry类的对象实例。

key值不能重复。 

1.2.1 HashMap

根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。

key值和value值可以为null,但是只能有一个key为null,因为key不可重复。

HashMap中的Entry对象是无序排列的。

1.2.2 HashTable

与 HashMap类似,不同的是:key和value的值均不允许为null。

支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此在写入时会比较慢。

1.2.3 LinkedHashMap

保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,按插入的顺序得到元素,会比HashMap慢。

1.2.4 IdentityHashMap

key不能重复,key重复的判断条件与HashMap不同。key相等的条件是key1==key2,而不是equals。

1.2.5 TreeMap

能够把它保存的记录根据键(key)排序,默认是按升序排序,也可以指定排序的比较器。

不允许key的值为null。

1.2.6 WeakHashMap

WeakHashMap 继承于AbstractMap,实现了Map接口

和HashMap一样,WeakHashMap 也是一个散列表,它存储的内容也是键值对(key-value)映射,而且键和值都可以是null。

WeakHashMap的键是“弱键”。在 WeakHashMap 中,当某个键不再正常使用时,会被从WeakHashMap中被自动移除。

“弱键”通过WeakReference和ReferenceQueue实现的。 WeakHashMap的key是“弱键”,即是WeakReference类型的;ReferenceQueue是一个队列,它会保存被GC回收的“弱键”。

1.2.7 Properties

Properties类是HashTable(实现了Map接口)的子类。HashTable是同步的。

Properties在HashTable基础上扩展了一些功能。

Properties的key和value都是字符串类型。

1.2.8 ConcurrentHashMap

多线程环境下,使用Hashmap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap。

HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable的效率非常低下。因为所有访问HashTable的线程都必须竞争同一把锁。

ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁。

 应用场景:当有一个大数组时需要在多个线程共享时就可以考虑是否把它给分层多个节点了,避免大锁。

 

1.3创建线程安全的集合对象

使用以下方式,可以避免使用Vector和HashTable:

Collection c = Collections.synchronizedCollection(new ArrayList());

List list = Collections.synchronizedList(new ArrayList());

Set s = Collections.synchronizedSet(new HashSet());

Map m = Collections.synchronizedMap(new HashMap());

 

2.Java集合框架方法

2.1 Collection操作

2.1.1 Collection基本操作

· add(Object o):增加元素

· addAll(Collection c):...

· clear():...

· contains(Object o):是否包含指定元素

· containsAll(Collection c):是否包含集合c中的所有元素

· iterator():返回Iterator对象,用于遍历集合中的元素

· remove(Object o):移除元素

· removeAll(Collection c):相当于减集合c

· retainAll(Collection c):相当于求与c的交集

· size():返回元素个数

· toArray():把集合转换为一个数组

2.1.2 Treeset操作

· first():返回第一个元素

· last():返回最后一个元素

· lower(Object o):返回指定元素之前的元素

· higher(Obect o):返回指定元素之后的元素

· subSet(fromElement, toElement):返回子集合

2.1.3 List操作

与Set相比,增加了与索引位置相关的操作:

· add(int index, Object o):在指定位置插入元素

· addAll(int index, Collection c):...

· get(int index):取得指定位置元素

· indexOf(Obejct o):返回对象o在集合中第一次出现的位置

· lastIndexOf(Object o):...

· remove(int index):删除并返回指定位置的元素

· set(int index, Object o):替换指定位置元素

· subList(int fromIndex, int endIndex):返回子集合

2.1.4 Queue操作

增加了以下操作:

· boolean add(E e) : 将元素加入到队尾,不建议使用

· boolean offer(E e): 将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时,此方法通常要优于 add(E),后者可能无法插入元素,而只是抛出一个异常。推荐使用此方法取代add

· E remove(): 获取头部元素并且删除元素,不建议使用

· E poll(): 获取头部元素并且删除元素,队列为空返回null;推荐使用此方法取代remove

· E element(): 获取但是不移除此队列的头

· E peek(): 获取队列头部元素却不删除元素,队列为空返回null

2.2 Map操作

clear()

从 Map 中删除所有映射

remove(Object key)

从 Map 中删除键和关联的值

put(Object key, Object value)

将指定值与指定键相关联

putAll(Map t)

将指定 Map 中的所有映射复制到此 map

entrySet()

返回 Map 中所包含映射的 Set 视图。Set 中的每个元素都是一个 Map.Entry 对象,可以使用 getKey() 和 getValue() 方法(还有一个 setValue() 方法)访问后者的键元素和值元素

keySet()

返回 Map 中所包含键的 Set 视图。删除 Set 中的元素还将删除 Map 中相应的映射(键和值)

values()

返回 map 中所包含值的 Collection 视图。删除 Collection 中的元素还将删除 Map 中相应的映射(键和值)

get(Object key)

返回与指定键关联的值

containsKey(Object key)

如果 Map 包含指定键的映射,则返回 true

containsValue(Object value)

如果此 Map 将一个或多个键映射到指定值,则返回 true

isEmpty()

如果 Map 不包含键-值映射,则返回 true

size()

返回 Map 中的键-值映射的数目

 

 

本文参考和使用了以下文章的部分内容:

https://www.cnblogs.com/nayitian/p/3266090.html#LinkedHashSet

https://www.cnblogs.com/shan1393/p/9020564.html