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()无参会导致泛型丢失

扩展阅读