`
- 浏览:
25798 次
- 性别:
- 来自:
北京
-
写在前面
编辑
在深入了解Java集合前,有必要先来了解它的设计哲学。引用Java集合框架项目带头人
Joshua Bloch的一句话:
"The main design goal of Collections Framework was to produce an API that was
reasonably small, both in size, and, more importantly, in conceptual weight."
这里的重点是conceptual weight,即概念上轻量。概念上的轻量意味着使用者们可以“不必
掌握大量信息,就能使用该API完成复杂的功能”。在Java集合框架中最直观的表现就是:
轻量、骨感的接口等级结构。为此,Java集合框架项目组做出了大量的取舍。这也是该
集合与著名的C++ STL的重要区别,同时也是Java这么多年一直有趣、易用、受欢迎的原因
之一。
在开始之前先让我们思考一个问题,为什么一门流行的编程语言需要至少一个公共或标准
集合包?
这是因为,如果没有这样一个包,就可能会存在大量的第三方集合库。而使用这些集合库的
代码想要达到互相复用,则需要互相编写适配器。需要多少个适配器呢?当n个代码模块一共
使用了n个集合库时,则需要n的阶乘(n!)个适配器。这显然是不可接受的。因此一门语言
想要被广泛地使用,就需要拥有一个被广泛接受的集合。
两道开胃菜
编辑
开胃菜1:在Java编程中为什么总是在红色代码执行完后的第二次循环,总是倾向于(而非总是)抛出
ConcurrentModificationException(strList的实现是ArrayList)?
这就是fail-fast机制。在strList的内部维护了一个Modification Counter,它会在非迭代器
修改元素的情况下+1。并在迭代器初始化时以final的形式赋给了迭代器对象。之后,每次迭代
时都会比较这两个counter,如果不相等,就尽可能早的抛出ConcurrentModificationException,
以避免程序在未来引起令人困惑行为。
for(String str : strList){
if(condition)
strList.remove(str)
}
开胃菜2:为什么在Java集合框架的接口中会出现大量的选择性实现的方法(optional methods)?
这些方法通常是修改或删除元素的方法。当某一个类不想要实现一个接口中的选择性方法时,就可
以简单粗暴地抛出UnsupportedOperationException(这是一个RuntimeException,你不应该捕获它
)。
这个问题的答案是,如果不这么做,Java集合框架接口结构就会呈现爆炸式地增长。比如对于一个
List是否可修改元素,你可能会需要:UnmodifiableList和ModifiableList两个接口。当一切都乘以2
之后,你可能仍然无法避免RuntimeException。例如当我们需要增加一个类似日志的数据结构,它需
要不断地append元素,但是它不应该支持修改元素和删除元素以及在尾部以外任何位置插入元素。
这时你该怎么办?难道再增加一个对应的接口吗?别忘了我们的设计哲学,概念上的轻量!
三条总的原则
编辑
1. 永远使用接口去定义你的类型。包括变量声明,参数类型和方法返回类型
Effective Java的item 19曾介绍使用接口定义类型的重要性。把这一条作为第一条原则的原因
是,在集合的领域,它更加重要,而且更加严格。也即,当使用集合类型作为你的变量声明类型、参数
类型或方法返回类型时,你永远可以,也永远应该使用接口而非抽象类或实体类来定义该类型。
这样做能够为你带来最大程度的灵活性,这在涉及到集合时尤为重要。当你切换到一个新的数据结构时,
你的外层代码永远不需要做出不必要的改动。
2. 在多线程环境下,优先选择concurrent的家族成员
Concurrnt家族下,没有一个实现类是简单地使用内部锁(独占锁)来保证线程安全。它们一般会通过
大锁化小锁,final,valitile关键字或者copy on write甚至无锁技术来保证线程安全。它们带来的并
行度提升通常是十分可观的。当然,它们受到使用场景的限制。
3. 在相应的场景下,选择最为合适集合实现类
这是一个相当粗犷的说法。但确实是集合运用进阶的分水岭。当没有一个实现类能够针对你的使用场景
时,你可能需要考虑重新设计一个非常能够针对你的问题的数据结构。当然,为了互通有无,和不影响外层
代码,你也许应该考虑将它引入到Java集合框架中来。本篇分享的剩余部分会重点讨论这个问题。
16条建议(General Programming 8 条, Concurrent 4条,Expanding 4条)
编辑
建议1:放弃Emmeration,开始使用Iterator
Iterator设计的目的就是为了取代Emmeration,它拥有更为清新的方法名和一个新增的删除元素的方法。
建议2:在遍历一个List的时候,可以使用ListIterator来增加一个元素和双向遍历
ListIterator保证有序遍历,而Iterator不保证。
建议3: 在面对稀疏数据结构时,可考虑使用HashSet
例如,当一个BitSet拥有99%的false时,你可以使用HashSet来替代它。
建议4:当你需要频繁地查找某个元素是否在一个List或数组中时,最好的方法是先对它进行排序,然后
使用binarySearch
建议5:使用集合的转化构造器在运行时改变你的实现类,从而带来执行效率提升
例如,当你需要使用TreeMap,而且需要往这个数据结构中添加大量的元素。TreeMap的put操作时十分昂贵
的,这个时候的最佳做法时。先加所有的元素添加到一个HashMap,然后再使用:
TreeMap treeMap = new TreeMap(hashMap);
来拿到你的TreeMap实例。
建议6:当你需要元素的有序遍历时,考虑使用“Linked”家族
诸如LinkedHashSet和LinkedHashMap能保证元素按照插入的顺序遍历,而这样做带来的性能损耗相比HashSet和
HashMap来说是十分微小的。
建议7:使用LinkedHashMap做出简单的LRU cache
代码如下:
public class LruCache<K, V> extends LinkedHashMap<K, V> {
private static final long serialVersionUID = 1L;
private final int maxCapacity;
public LruCache(int maxCapacity) {
super(maxCapacity, 0.7F, true);
this.maxCapacity = maxCapacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> entry) {
return size() > maxCapacity;
}
}
建议8:使用WeakHashMap来维护短暂使用的数据
WeakHashMap中的entry会在它的key不再被任何线程的执行栈中引用到时,在下一次垃圾回收的周期
被GC回收掉。它非常适合实时性消费数据,例如画图数据。
建议9:在并发环境下,当List中的元素被频繁遍历而少量修改时,可考虑使用CopyOnWriteArrayList
例如,观察者模式中的Event handlers
建议10:在并发环境下,如果不需要强一致性的遍历器,可考虑使用ConcurrentHashMap,否则,请使用HashTable
建议11:在生产者消费者模式下,考虑使用BlockingQueue
通常,请考虑使用LinkedBlockingQueue,因为它拥有更大的吞吐量。
建议12:想要在并发环境下使用TreeMap,请考虑ConcurrentSkipListSet和ConcurrentSkipListMap
它们实现基于经典的无锁队列实现。
建议13:不要使用继承来“加强”一个既有的实现,composition更适合你
这里的加强指的是提供新的API。来看一个例子:
/**
* This class is useful when you need to store a List value
* in a map. It saves many redundant operations.
*
* @author eric.zhang
*
* @param <K> type of the key
* @param <V> value type in a list
*/
public class HashMapForListValue <K,V>{
private Map<K,List<V>> innerMap;
public HashMapForListValue(){
this.innerMap = new HashMap<K,List<V>>();
}
public List<V> put(K key, V value){
List<V> list = null;
if(!innerMap.containsKey(key)){
list = new ArrayList<V>();
list.add(value);
innerMap.put(key, list);
}else{
list = innerMap.get(key);
list.add(value);
}
return list;
}
public List<V> get(K key){
return innerMap.get(key);
}
public Map<K,List<V>> getMap(){
return innerMap;
}
}
这个类在一个key对应一个List value时会帮你省去大量冗余代码。
建议14:使用decorator和builder模式来为既有实现“添加新的功能”
这里的添加新的功能是指,经过装饰或build的实现完全兼有原来实现的功能,
它们对外提供的API没有变化,只是支持了一些额外的功能。
例如:Collections.synchronizedList
Collections.unmodifiableList
又比如builder模式:
建议15:通过继承abstract家族,可以大大简化设计新的实现的过程
当你需要设计新的的Map时,考虑继承AbstractMap。
建议16:通过写适配器可以将第三方的数据结构引入到Java集合框架中来,以达到互通有无
分享到:
Global site tag (gtag.js) - Google Analytics
相关推荐
Java集合框架是Java编程语言中的一个核心特性,它为存储、管理和操作对象提供了一组统一的接口和类。本章内容主要围绕Java集合框架展开,包括ArrayList、LinkedList、HashSet、HashMap等常见数据结构的使用方法及其...
Java集合框架是Java编程语言中处理对象集合的一套接口和类。该框架提供了用于存储和操作集合的标准方法。在Java集合框架中,基本的接口分为两大类:Collection和Map。 Collection接口用于表示一组对象,称为其元素...
6. **并发集合**:Java集合框架还包括并发集合,如`ConcurrentHashMap`、`CopyOnWriteArrayList`等,它们在多线程环境下提供了线程安全的访问和修改。 7. **Collections工具类**:`Collections`类提供了大量静态...
Java集合框架是Java编程语言中的一个核心组成部分,它为数据存储和操作提供了丰富的类库。在Java中,集合框架主要包括接口(如List、Set、Queue)和实现这些接口的类(如ArrayList、HashSet、LinkedList等)。这个...
Java集合框架是Java编程语言中用于存储和管理对象的核心组件,它包括了各种接口和类,为处理数据提供了丰富的选择。在本次实验中,我们深入学习了Java集合框架中的两个主要部分:List接口和Map接口,以及它们的主要...
7. **并发处理**:Java集合框架还包含了`Concurrent`系列类,如`ConcurrentHashMap`和`CopyOnWriteArrayList`,它们在多线程环境下提供了高效率和安全性。 8. **流(Stream)API**:从Java 8开始,引入了流API,它...
内容概要:本文详细介绍了Java集合框架的重要性和在Android开发中的应用。首先,阐述了集合框架的基本概念,包括接口(Collection、Set、List、Map)和其实现类(ArrayList、LinkedList、HashSet、TreeSet、HashMap...
三、:locked_with_key:Java多线程与并发框架:unlocked: Java多线程与并发框 (第 13 篇) 深入理解:Fork/Join框架 Java多线程与并发框 (第 14 篇) 深入理解:原子操作 Java多线程与并发框 (第 15 篇) 深入理解...
最后,Java集合框架的并发处理也是重要一环。ConcurrentHashMap和CopyOnWriteArrayList等线程安全的集合类,在多线程环境下保证数据一致性,提升了性能。 总的来说,Java集合框架是一个强大的工具箱,为开发者提供...
Java集合框架是Java编程语言中的核心部分,它提供了一组高效、灵活的数据结构,使得开发者可以方便地存储和管理各种类型的数据。Java集合框架主要包括两大类:Collection和Map。 Collection接口是所有单值容器的父...
Java集合框架是Java语言提供的用于存储数据和操作数据的集合类库。在Java集合框架中,Map接口的实现类广泛用于存储键值对数据结构。主要实现类包括HashMap、Hashtable、LinkedHashMap和TreeMap。 1. HashMap:它...
Java集合框架是Java编程语言中不可或缺的一部分,它提供了一组接口和类,用于高效地存储、管理和操作数据。本篇文章将深入探讨Java集合框架的各个方面,帮助开发者从基础到高级全面掌握这一关键知识。 首先,我们要...
数据结构和Java集合框架是Java编程中至关重要的概念,它们是高效编程和算法设计的基础。在Java中,数据结构指的是组织、存储和管理数据的方式,而集合框架则是一组接口和类,为处理各种数据结构提供了统一的API。 ...
- 针对多线程环境,Java集合框架提供了线程安全的实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`等,它们在并发环境下提供了更高的性能。 7. **扩展和高级特性**: - `LinkedHashSet`和`...
15. **垃圾回收与内存管理**:了解集合对象的生命周期和如何避免内存泄漏也是使用Java集合框架的重要方面。 通过这个PPT,学习者将能够深入了解Java集合框架的各个方面,包括其设计原则、常用方法、性能考量以及在...
此外,还可能讲解到泛型、迭代器、并发集合(如ConcurrentHashMap)等内容,这些都是Java集合框架中的重要知识点。 对于初学者来说,了解这些接口的基本操作,如add、remove、contains等,以及它们的区别,是掌握...
了解和熟练掌握Java集合框架对于编写高效的Java程序至关重要,这包括选择适当的集合类型、理解不同实现的性能特征以及正确使用并发容器来处理多线程场景。通过深入学习,开发者可以更好地应对各种数据结构和算法问题...
1. **集合与接口**:Java集合框架包括List、Set和Queue等接口,它们都是继承自Collection接口。ArrayList、LinkedList、HashSet、TreeSet、LinkedList和PriorityQueue是常见的实现类。 2. **ArrayList与LinkedList*...
Java集合框架还包括并发集合,如`ConcurrentHashMap`、`CopyOnWriteArrayList`和`CopyOnWriteArraySet`,它们在多线程环境下提供高并发性能。 8. **流API**: 自Java 8起,引入了流API(Stream API),提供了一种...