Java集合框架
集合框架是Java强大核心之一,是Java开发的基础。
集合概览
- Collection: 一组对象的集合
- Set: 没有重复对象
- List: 元素按顺序排列,可能有重复 (和数组区别是大小可以按需变化)
- Queue
- Map: 对象间的一系列映射或关联关系
List/列表 接口
是一种有序集合,也称为序列,实现了Iterable 接口。
List接口通用实现:
- ArrayList: 最佳全能实现, get()/set()
- LindedList: 高效插入和删除, add()/remove()的性能更好
- CopyOnWriteArrayList: 线程安全;遍历快,修改慢
注: 过时的Stack用Deque替代
常用方法:
- add(): 添加到末尾
- size(): 获取大小
- get(index): 检索某项
一些注意事项:
- ArrayList.subList 结果不可强转换为ArrayList, 因为返回的是视图(内部类SubList) . 注意对原列表的修改会造成子列表操作产生异常.
Set/集
包含唯一元素(没有重复元素),确保唯一性,但不保证(添加)顺序。
实现Set接口的类:
- HashSet: 最佳通用实现
- LinkedHashSet: 保留插入顺序
- EnumSet: 枚举值
- TreeSet: 元素类型可比较,升序排列
- CopyOnWriteArraySet: 线程安全
Map/映射 接口
键值对集合。
实现Map的类:
-
HashMap: 通用实现
-
EnumMap: 键是枚举类型
-
LinkdedHashMap: 保留插入和访问顺序
-
TreeMap: 按照键排序
-
Properties: 使用String类的方法扩展Hashtable接口
-
并发线程安全: ConcurrentHashMap(通用实现)和ConcurrentSkipListMap
-
HashMap常用方法:
- getOrDefault() 取值,如果不存在用默认值
- computeIfAbsent() 存值,如果不存在用默认值
-
TreeMap:
- firstKey()/lastKey()
- headMap()/tailMap()/subMap(): 返回一个新映射
-
线程安全ConcurrentMap
- putIfAbsent() 注:使用entrySet遍历Map类集合KV,而不是keySet方式进行遍历. JDK8使用Map.foreach方法.
map.put("key","value");
map.remove("Android");
// keys to Array
return map.keySet().toArray(new String[map.keySet().size()]);
// keys to List
List<String> list = new ArrayList<String>(map.keySet());
Queue/队列
Queue接口实现类:
- LinkedList: 无界FIFO顺序 (用作队列时不建议使用null)
- PirorityQueue: 元素实现Comparator,队头为最小值
- ArrayQueue: 双端队列,用做栈
使用队列时,最好选定一种处理失败的方式。
- 如果想在操作成功之前 一直阻塞,应该选择 put() 和 take() 方法
- 如果想检查方法的返回值,判断操作是否成功,应该选择offer() 和poll() 方法
实用方法
Collections
- clone() : Deep Copy 不改变原数据
- Collections.nCopies(1000, new Object()) : 填充N个默认对象副本
- Collections.copy(list, list)
- Collections.sort(list)
集合相关
Iterable/迭代变量
快速迭代语法:
for (objectType varName : collectionReference) {}
泛型/Generics
声明时用<>指明特定类型,确保类型安全,属于编译时特性。
约定T/Type,K/Key,V/Value,E/Element
Bounded Generics: 方法接受一种类型和它的所有子类(upper bound) 或类型和它的所有超类 (lower bound).
- List一般作为参数来接受外部的集合,或返回一个不知道具体元素类型(类型未知)的集合。
- <? extend T>的场景是put功能受限,适用于消费集合元素为主的场景。赋值T及子类。
- <? super T>的场景是get功能受限,适用于生产集合元素为主的场景。赋值T及父类。
// 泛型方法
// 返回类型前有类型参数定义,可以有多个以","分开的类型参数
public <T> List<T> fromArrayToList(T[] a) {
return Arrays.stream(a).collect(Collectors.toList());
}
数组与集合的转换
从索引的角度看,数组和集合很像。
数组转集合
- 集合转数组必须使用 toList(T[] array),传入实际列表大小
- Arrays.asList(): 返回不可变集合(只可通过set修改原值),不能做修改个数操作。因为返回是不带操作实现的内部类(适配器模式,后台仍为数组)
- 如果需要,则创建新集合new ArrayList(Arrays.asList(数组))
集合转数组
- toArray()无参会导致泛型丢失