概述
Java 集合框架主要分为三大类:
- List:有序、可重复
- Set:无序、不可重复
- Map:键值对存储
List 列表
ArrayList
基于动态数组实现,查询快,增删慢。
| 操作 | 时间复杂度 |
|---|---|
| get(index) | O(1) |
| add(e) | O(1) 平均 |
| add(index, e) | O(n) |
| remove(index) | O(n) |
常用方法:
csharp
List<String> list = new ArrayList<>();
// 添加
list.add("a");
list.add(1, "b"); // 插入到指定位置
// 查询
list.get(0);
list.size();
list.contains("a");
list.indexOf("a");
// 修改
list.set(0, "new");
// 删除
list.remove("a");
list.remove(0); // 删除指定索引
list.clear();
// 遍历
for (String s : list) {}
list.forEach(System.out::println);
LinkedList
基于双向链表实现,增删快,查询慢。
| 操作 | 时间复杂度 |
|---|---|
| get(index) | O(n) |
| add(e) | O(1) |
| addFirst/e | O(1) |
| removeFirst/Last | O(1) |
常用方法:
ini
LinkedList<String> list = new LinkedList<>();
// 队列/栈操作
list.addFirst("a");
list.addLast("b");
list.removeFirst();
list.removeLast();
list.peekFirst();
list.peekLast();
// List 操作
list.add("c");
list.get(0);
list.remove("c");
ArrayList vs LinkedList
| 特性 | ArrayList | LinkedList |
|---|---|---|
| 底层结构 | 动态数组 | 双向链表 |
| 查询 | 快 O(1) | 慢 O(n) |
| 增删 | 慢 O(n) | 快 O(1) |
| 内存占用 | 少 | 多(需存储前后指针) |
| 适用场景 | 频繁查询 | 频繁增删 |
Queue 队列
ArrayDeque
基于动态数组的双端队列,推荐作为队列使用。
arduino
Queue<String> queue = new ArrayDeque<>();
// 入队
queue.offer("a"); // 推荐
queue.add("b"); // 失败抛异常
// 出队
queue.poll(); // 推荐,失败返回 null
queue.remove(); // 失败抛异常
queue.peek(); // 查看队首,不删除
PriorityQueue
优先队列,基于堆实现,元素按自然顺序或比较器排序。
ini
Queue<Integer> pq = new PriorityQueue<>();
pq.offer(3);
pq.offer(1);
pq.offer(2);
// 每次取出最小值
pq.poll(); // 1
pq.poll(); // 2
pq.poll(); // 3
// 自定义比较器(大顶堆)
Queue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
Queue<Integer> maxHeap = new PriorityQueue<>((o1, o2) -> o2 - o1);
//默认为最小堆
Queue<Integer> minHeap = new PriorityQueue<>();
Queue<Integer> maxHeap = new PriorityQueue<>((o1, o2) -> o1 - o2);
LinkedList 作为队列
arduino
Queue<String> queue = new LinkedList<>();
queue.offer("a");
queue.poll();
Map 键值对
HashMap
基于哈希表实现,键无序,允许 null 键和 null 值。
arduino
Map<String, Integer> map = new HashMap<>();
// 添加
map.put("a", 1);
map.put("b", 2);
// 查询
map.get("a");
map.containsKey("a");
map.containsValue(1);
map.size();
// 删除
map.remove("a");
map.clear();
// 遍历:键值对遍历要先变成Entry集合
for (Map.Entry<String, Integer> e : map.entrySet()) {
System.out.println(e.getKey() + ": " + e.getValue());
}
map.forEach((k, v) -> System.out.println(k + ": " + v));
LinkedHashMap
保持插入顺序的 HashMap。
arduino
Map<String, Integer> map = new LinkedHashMap<>();
map.put("a", 1);
map.put("b", 2);
// 遍历时按插入顺序:a, b
TreeMap
基于红黑树实现,键按自然顺序或比较器排序。
arduino
Map<String, Integer> map = new TreeMap<>();
map.put("c", 3);
map.put("a", 1);
map.put("b", 2);
// 遍历时按键排序:a, b, c
// 常用方法
map.firstKey(); // 最小键
map.lastKey(); // 最大键
map.subMap("a", "b"); // a <= key < b 的子 map
map.headMap("b"); // key < b 的子 map
map.tailMap("b"); // key >= b 的子 map
Set 集合
HashSet
基于 HashMap 实现,元素无序且不可重复。
dart
Set<String> set = new HashSet<>();
set.add("a");
set.remove("a");
set.contains("a");
set.size();
set.clear();
for (String s : set) {}
LinkedHashSet
保持插入顺序的 HashSet。
csharp
Set<String> set = new LinkedHashSet<>();
set.add("a");
set.add("b");
// 遍历按插入顺序
TreeSet
基于红黑树实现,元素按自然顺序或比较器排序,不可重复。
csharp
Set<Integer> set = new TreeSet<>();
set.add(3);
set.add(1);
set.add(2);
// 遍历按排序:1, 2, 3
set.first(); // 最小元素
set.last(); // 最大元素
set.headSet(2); // < 2 的子 set
set.tailSet(2); // >= 2 的子 set
set.subSet(1, 3); // 1 <= x < 3 的子 set
Java 泛型 <T>
泛型提供编译时类型安全,避免类型转换。
typescript
// 自定义泛型类
class Box<T> {
private T value;
public void set(T value) { this.value = value; }
public T get() { return value; }
}
Box<String> box = new Box<>();
box.set("hello");
String s = box.get();
// 泛型方法
public <T> T first(List<T> list) {
return list.get(0);
}
// 通配符
List<? extends Number> list1; // Number 的子类
List<? super Integer> list2; // Integer 的父类
List<?> list3; // 任意类型
迭代器 Iterator & Iterable
Iterator
用于遍历集合的元素。
ini
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
// 迭代器遍历
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if ("a".equals(s)) {
it.remove(); // 安全删除
}
}
Iterable
实现 Iterable 接口的类可以使用 for-each 循环。
typescript
// for-each 等价于 iterator
for (String s : list) {
System.out.println(s);
}
// 自定义可迭代类
class MyCollection implements Iterable<String> {
private List<String> data = new ArrayList<>();
public void add(String s) { data.add(s); }
@Override
public Iterator<String> iterator() {
return data.iterator();
}
}
MyCollection col = new MyCollection();
col.add("a");
for (String s : col) {} // 可用 for-each
Stream
数据源.零个或多个中间操作.最终操作
中间操作:
- filter:过滤元素
- map:类型 / 数值转换
- distinct:去重
- sorted:排序
- limit:截取前 n 个
- skip:跳过前 n 个
- flatMap :拆分嵌套集合
最终操作: - collect:收集为集合(最常用)
- forEach:遍历输出
- count:统计数量
- max/min:取最大最小值
- sum:求和(数值流)
- anyMatch/allMatch/noneMatch:条件匹配返回布尔:任意、全部、都不满足
- findFirst/findAny :获取元素:取首个、取随机
没什么好说的,上题目
前置
ini
List<Integer> numList = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
List<String> nameList = Arrays.asList("张三","李四","张无忌","赵敏","张三丰");
实现
ini
public class StreamTest {
public static void main(String[] args) {
List<Integer> numList = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
List<String> nameList = Arrays.asList("张三","李四","张无忌","张无忌","赵敏","张三丰");
//排除偶数 --filter List<Integer> collect = numList.stream().filter(num -> num % 2 != 0).collect(Collectors.toList());
System.out.println(collect);
//数字全部翻倍 --map转换
List<Integer> collect1 = numList.stream().map(num -> num * 2).collect(Collectors.toList());
System.out.println(collect1);
//排除姓张的名字
List<String> collect2 = nameList.stream().filter(name -> !name.matches("^张.*")).collect(Collectors.toList());
System.out.println(collect2);
//去重
List<String> collect3 = nameList.stream().distinct().collect(Collectors.toList());
System.out.println(collect3);
//排序(升序 / 降序)
List<Integer> collect4 = numList.stream().sorted().collect(Collectors.toList());
List<Integer> collect5 = numList.stream().sorted((a, b) -> b - a).collect(Collectors.toList());
System.out.println(collect4);
System.out.println(collect5);
//取前 3 个元素 --limit List<String> collect6 = nameList.stream().limit(3).collect(Collectors.toList());
System.out.println(collect6);
//跳过前 2 个 --skip List<String> collect7 = nameList.stream().skip(2).collect(Collectors.toList());
System.out.println(collect7);
//求和 --mapToInt int sum = numList.stream().mapToInt(num -> num).sum();
System.out.println(sum);
//统计元素个数
long count = nameList.stream().count();
System.out.println(count);
//拼接字符串
String collect8 = nameList.stream().collect(Collectors.joining(","));
System.out.println(collect8);
}
}
结果
css
[1, 3, 5, 7, 9]
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
[李四, 赵敏]
[张三, 李四, 张无忌, 赵敏, 张三丰]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[张三, 李四, 张无忌]
[张无忌, 张无忌, 赵敏, 张三丰]
55
6
张三,李四,张无忌,张无忌,赵敏,张三丰