笔者之前学习过Spring系列的使用,但是对Java的初始语法一直不太明白。在leetcode刷题过程,发现很多Java基础的方法都不会,因此通过写这个文档来进行初始语法的学习
Java中语法的问题
Java如何向数组中插入元素?
Java中的数组中长度是固定的,一旦创建,就不能改变大小
方法1:创建一个更大的数组,并手动复制插入
1 | int[] oldArray = {1, 2, 4}; |
输出的结果:{1,2,3,4}
方法2:使用ArrayList(推荐用于频繁增删)
1 | import java.util.ArrayList; |
ArrayList支持动态扩容,是恶化需要频繁插入/删除的场景。
在 Java 中,Map 接口提供了丰富的常用方法,用于操作键值对(key-value pairs)。以下是 Map 最常用的函数及其详细说明、用法和示例。
Java中List<List<String>>如何初始化
List<list<String>>是一个双层列表,实际上是一个二维数组
Java中对于这种数组的创建,一般采用先创建外层的空列表,后续依据需求添加内层列表
1 | List<List<String>> result = new ArrayList<>(); |
Java中Map的常用实现类
该部分由通义千问生成
在 Java 中,Map 是一个非常重要的接口,用于存储 键值对(key-value pairs),即通过一个“键”来查找对应的“值”。它类似于数学中的映射关系。
📚 一、Map 的常用实现类(核心)
以下是 Java 中最常用的 Map 实现类及其特点:
| 实现类 | 是否有序 | 线程安全 | 允许 null 键/值 | 性能 | 适用场景 |
|---|---|---|---|---|---|
HashMap |
❌ 无序 | ❌ 不安全 | ✅ 允许一个 null 键,多个 null 值 | ⭐⭐⭐⭐ 平均 O(1) | 默认首选,高性能 |
LinkedHashMap |
✅ 按插入/访问顺序 | ❌ 不安全 | ✅ 允许 | ⭐⭐⭐ 稍慢于 HashMap | 需要顺序输出 |
TreeMap |
✅ 按键自然排序或自定义排序 | ❌ 不安全 | ❌ 不允许 null 键(会抛异常),值可为 null | ⭐⭐ O(log n) | 需要排序的场景 |
Hashtable |
❌ 无序 | ✅ 安全(方法加锁) | ❌ 不允许 null 键或值 | ⭐⭐ 较慢(同步开销) | 老旧,基本被取代 |
ConcurrentHashMap |
❌ 无序(Java 8+) | ✅ 高并发安全 | ❌ 不允许 null 键或值 | ⭐⭐⭐⭐ 高并发下性能好 | 多线程环境 |
🔍 二、详细说明每个实现类
1. HashMap<K, V> ✅ 最常用
- 特点:
- 基于哈希表实现,查找、插入、删除平均时间复杂度为 **O(1)**。
- 不保证顺序(遍历顺序可能变化)。
- 允许 一个
null键 和 任意多个null值。 - 非线程安全,多线程环境下可能出错。
- 使用场景:
- 绝大多数单线程场景下的键值映射。
- 如缓存、计数器、Two Sum 算法等。
1 | Map<String, Integer> map = new HashMap<>(); |
2. LinkedHashMap<K, V>
- 特点:
- 继承自
HashMap,但内部维护了一个双向链表。 - 保持 插入顺序 或 访问顺序(可通过构造函数设置)。
- 允许
null键和null值。 - 性能略低于
HashMap(因维护链表)。 - 非线程安全。
- 继承自
- 使用场景:
- 需要按插入顺序遍历的场景。
- 实现 LRU 缓存(最近最少使用)。
1 | Map<String, Integer> map = new LinkedHashMap<>(); |
💡 实现 LRU 示例(简化):
1 | // accessOrder=true 表示按访问顺序排序 |
3. TreeMap<K, V>
- 特点:
- 基于红黑树(自平衡二叉搜索树)实现。
- 键(key)会自动按 自然顺序 或 自定义 Comparator 排序。
- 不允许
null键(会抛NullPointerException),值可以为null。 - 时间复杂度为 **O(log n)**。
- 非线程安全。
- 使用场景:
- 需要按键排序的场景。
- 范围查询(如查找 10~50 之间的键)。
1 | Map<Integer, String> sortedMap = new TreeMap<>(); |
4. Hashtable ❌ 已过时(不推荐)
- 特点:
- 早期的线程安全哈希表。
- 方法都加了
synchronized关键字,性能较差。 - 不允许
null键或null值(否则抛NullPointerException)。 - 无序。
- 替代方案:
ConcurrentHashMap或Collections.synchronizedMap()
1 | Map<String, String> map = new Hashtable<>(); // 不推荐 |
5. ConcurrentHashMap<K, V> ✅ 高并发首选
- 特点:
- 专为并发环境设计。
- 使用 分段锁(Java 7) 或 CAS + synchronized(Java 8+) 实现高效并发。
- 不允许
null键或null值(避免歧义)。 - 性能在高并发下远优于
Hashtable和synchronizedMap。
- 使用场景:
- 多线程环境下共享的缓存、计数器等。
1 | Map<String, Long> counter = new ConcurrentHashMap<>(); |
🛠 三、如何选择合适的 Map 实现?
| 需求 | 推荐实现类 |
|---|---|
| 单线程,高性能,无序 | HashMap |
| 需要保持插入顺序 | LinkedHashMap |
| 需要按键排序 | TreeMap |
| 多线程,高性能并发 | ConcurrentHashMap |
| 老项目兼容 | Hashtable(不推荐) |
🧩 四、其他相关工具
1. Collections.synchronizedMap()
将普通 Map 包装成线程安全的:
1 | Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>()); |
2. Map.of() (Java 9+)
创建不可变的小 Map:
1 | Map<String, Integer> map = Map.of("A", 1, "B", 2); // 最多 10 对 |
3. Map.ofEntries() (Java 9+)
创建更灵活的不可变 Map:
1 | Map<String, Integer> map = Map.ofEntries( |
✅ 总结
| 实现类 | 推荐程度 | 关键词 |
|---|---|---|
HashMap |
⭐⭐⭐⭐⭐ | 高性能、无序、默认选择 |
LinkedHashMap |
⭐⭐⭐⭐☆ | 保持顺序、LRU |
TreeMap |
⭐⭐⭐☆☆ | 排序、范围查询 |
ConcurrentHashMap |
⭐⭐⭐⭐⭐ | 高并发、线程安全 |
Hashtable |
⭐☆☆☆☆ | 过时、不推荐 |
📌 一句话建议:
日常开发用
HashMap,需要顺序用LinkedHashMap,要排序用TreeMap,多线程用ConcurrentHashMap。
如果你有具体使用场景(比如缓存、排序、并发),我可以帮你推荐最合适的 Map 实现!
Java中Map的常用函数及使用
该部分由通义千问生成
📚 一、Map 的常用函数(方法)一览
| 方法 | 作用 | 返回类型 | 是否修改 Map |
|---|---|---|---|
put(K, V) |
添加或更新键值对 | V(旧值,若存在) |
✅ 是 |
get(Object) |
根据键获取值 | V |
❌ 否 |
containsKey(Object) |
检查是否包含某个键 | boolean |
❌ 否 |
containsValue(Object) |
检查是否包含某个值 | boolean |
❌ 否 |
remove(Object) |
删除指定键的映射 | V(被删除的值) |
✅ 是 |
size() |
获取键值对的数量 | int |
❌ 否 |
isEmpty() |
判断是否为空 | boolean |
❌ 否 |
clear() |
清空所有映射 | void |
✅ 是 |
keySet() |
获取所有键的集合 | Set<K> |
❌ 否(但集合是视图) |
values() |
获取所有值的集合 | Collection<V> |
❌ 否(但集合是视图) |
entrySet() |
获取所有键值对的集合 | Set<Map.Entry<K,V>> |
❌ 否(但集合是视图) |
getOrDefault(Object, V) |
获取值,若键不存在则返回默认值 | V |
❌ 否 |
putIfAbsent(K, V) |
若键不存在才添加 | V(当前值) |
✅ 可能 |
computeIfAbsent(K, Function) |
若键不存在,用函数生成值并放入 | V |
✅ 可能 |
forEach(BiConsumer) |
遍历所有键值对 | void |
❌ 否 |
🔍 二、详细说明与示例
我们以 HashMap<String, Integer> 为例:
1 | Map<String, Integer> map = new HashMap<>(); |
1. put(K key, V value)
添加或更新一个键值对。
1 | map.put("David", 28); // 添加新键值对 |
返回值:如果键已存在,返回旧值;否则返回
null。
2. get(Object key)
根据键获取对应的值。
1 | Integer age = map.get("Alice"); // 返回 26 |
⚠️ 如果键不存在,返回
null。建议配合containsKey使用,或用getOrDefault。
3. containsKey(Object key)
检查是否包含某个键。
1 | boolean hasAlice = map.containsKey("Alice"); // true |
4. containsValue(Object value)
检查是否包含某个值。
1 | boolean hasAge30 = map.containsValue(30); // true (Bob) |
⚠️ 性能较差(O(n)),因为要遍历所有值。
5. remove(Object key)
删除指定键的映射。
1 | Integer removed = map.remove("Bob"); // 返回 30,并删除 |
6. size()
返回键值对的数量。
1 | int count = map.size(); // 3(Alice, Charlie, David) |
7. isEmpty()
判断 Map 是否为空。
1 | boolean isEmpty = map.isEmpty(); // false |
8. clear()
清空所有键值对。
1 | map.clear(); |
9. keySet()
返回所有键的集合(Set<K>)。
1 | Set<String> keys = map.keySet(); |
🔔 返回的是视图(view),修改
keys会影响原map。
10. values()
返回所有值的集合(Collection<V>)。
1 | Collection<Integer> values = map.values(); |
11. entrySet()
返回所有键值对的集合(Set<Map.Entry<K,V>>),用于遍历。
1 | for (Map.Entry<String, Integer> entry : map.entrySet()) { |
✅ 这是遍历 Map 的推荐方式。
12. getOrDefault(Object key, V defaultValue)
获取值,如果键不存在,返回默认值。
1 | Integer age = map.getOrDefault("Eve", 18); // 返回 18 |
✅ 避免
null值带来的空指针异常。
13. putIfAbsent(K key, V value)
只有当键不存在时才插入。
1 | map.putIfAbsent("Alice", 20); // Alice 已存在,不更新 |
返回当前值(可能是旧值或新插入的值)。
14. computeIfAbsent(K key, Function<K,V> mappingFunction)
如果键不存在,使用函数计算值并放入。
1 | map.computeIfAbsent("Frank", k -> k.length()); // k="Frank" → 长度=5 |
✅ 常用于延迟初始化、缓存等场景。
15. forEach(BiConsumer<K,V> action)
遍历所有键值对(Java 8+)。
1 | map.forEach((key, value) -> { |
✅ 简洁的 Lambda 写法。
🧩 三、Map.Entry<K,V> 常用方法
当你使用 entrySet() 时,会得到 Map.Entry 对象:
1 | Map.Entry<String, Integer> entry = ...; |
✅ 四、总结:最常用的方法(Top 10)
| 排名 | 方法 | 用途 |
|---|---|---|
| 1️⃣ | put(K,V) |
添加/更新 |
| 2️⃣ | get(K) |
查找值 |
| 3️⃣ | containsKey(K) |
判断键是否存在 |
| 4️⃣ | getOrDefault(K, default) |
安全获取值 |
| 5️⃣ | entrySet() + forEach |
遍历所有键值对 |
| 6️⃣ | keySet() |
获取所有键 |
| 7️⃣ | values() |
获取所有值 |
| 8️⃣ | remove(K) |
删除 |
| 9️⃣ | size() / isEmpty() |
判断大小 |
| 🔟 | computeIfAbsent(K, func) |
懒加载、避免重复创建 |
💡 小贴士
- 使用
Map.of()(Java 9+)创建不可变小 Map:
1 | Map<String, Integer> map = Map.of("A", 1, "B", 2); |
- 使用
Map.ofEntries()创建更灵活的不可变 Map。 - 多线程环境下优先使用
ConcurrentHashMap。
如果你有具体使用场景(如缓存、计数、分组),我可以告诉你该用哪个方法组合!欢迎继续提问 😊
Java中List的实现类
在 Java 中,List 是一个非常重要的接口,属于 java.util 包,是 Collection 框架的一部分。它表示一个有序的集合(也称为序列),允许重复元素,并且可以通过索引(下标)访问元素。
📚 一、List 的核心特点
| 特性 | 说明 |
|---|---|
| ✅ 有序 | 元素按插入顺序排列(或指定顺序) |
| ✅ 可重复 | 允许存储相同的元素多次 |
| ✅ 可索引访问 | 可以通过 get(index) 获取指定位置的元素 |
| ✅ 动态大小 | 大多数实现支持动态扩容 |
🔍 二、List 的主要实现类
Java 中最常用的 List 实现类有以下几种:
| 实现类 | 底层结构 | 是否可变 | 线程安全 | 性能特点 | 适用场景 |
|---|---|---|---|---|---|
ArrayList |
动态数组 | ✅ 可变 | ❌ 不安全 | 随机访问快 O(1),插入/删除慢 O(n) | 默认首选 |
LinkedList |
双向链表 | ✅ 可变 | ❌ 不安全 | 插入/删除快 O(1),随机访问慢 O(n) | 频繁增删 |
Vector |
动态数组 | ✅ 可变 | ✅ 安全(方法同步) | 慢(同步开销) | 老旧,基本被取代 |
Stack |
继承 Vector |
✅ 可变 | ✅ 安全 | 后进先出(LIFO) | 已过时,建议用 Deque |
CopyOnWriteArrayList |
写时复制数组 | ✅ 可变 | ✅ 安全 | 读快写慢,适合读多写少 | 并发场景 |
🧩 三、详细解析每个实现类
1. ArrayList<E> ✅ 最常用
- 底层结构:动态数组(基于
Object[]) - 优点:
- 支持快速随机访问(
get(index)时间复杂度 O(1)) - 遍历效率高
- 支持快速随机访问(
- 缺点:
- 在中间插入或删除元素较慢(需要移动元素,O(n))
- 扩容时会创建新数组并复制数据
- 默认初始容量:10(首次添加元素时扩容)
- 扩容机制:每次增长约 50%(
oldCapacity + (oldCapacity >> 1))
✅ 推荐作为
List的默认选择,除非你有特殊需求。
1 | List<String> list = new ArrayList<>(); |
2. LinkedList<E> 🔄 链表结构
- 底层结构:双向链表(每个节点包含前驱和后继指针)
- 优点:
- 在头部/尾部/中间插入、删除效率高(O(1),如果已有节点引用)
- 无需扩容
- 缺点:
- 随机访问慢(必须从头或尾遍历,O(n))
- 占用更多内存(每个节点要存指针)
✅ 适合频繁在中间插入/删除的场景。
1 | List<String> list = new LinkedList<>(); |
💡 注意:
LinkedList还实现了Deque接口,可以用作队列或栈。
3. Vector<E> ⚠️ 已过时(不推荐)
- 底层结构:动态数组(类似
ArrayList) - 特点:
- 方法都是
synchronized的,线程安全 - 性能较差(同步开销大)
- 默认扩容翻倍(比
ArrayList浪费空间)
- 方法都是
❌ 不推荐使用,除非维护老代码。
✅ 替代方案:
- 需要线程安全 →
Collections.synchronizedList(new ArrayList<>()) - 或使用
CopyOnWriteArrayList
1 | List<String> list = Collections.synchronizedList(new ArrayList<>()); |
4. Stack<E> ⚠️ 已过时
- **继承自 **
Vector - 提供
push()、pop()、peek()等栈操作 - 问题:
- 基于
Vector,性能差 - 设计不合理(应该用组合而不是继承)
- 基于
✅ 推荐替代:使用
Deque实现栈
1 | Deque<String> stack = new ArrayDeque<>(); |
5. CopyOnWriteArrayList<E> ✅ 高并发场景
- 特点:
- “写时复制”机制:每次修改都创建新数组,读操作不加锁
- 线程安全
- 读操作非常快,写操作较慢(因为要复制数组)
- 适用场景:
- 读多写少的并发环境(如监听器列表、观察者模式)
1 | List<String> list = new CopyOnWriteArrayList<>(); |
⚠️ 不适合写频繁的场景,否则性能很差。
🛠 四、如何选择合适的 List 实现?
| 需求 | 推荐实现类 |
|---|---|
| 一般用途,随机访问多 | ArrayList ✅ |
| 频繁在头部/中间插入删除 | LinkedList |
| 多线程环境,读多写少 | CopyOnWriteArrayList |
| 多线程环境,读写均衡 | Collections.synchronizedList(new ArrayList<>()) |
| 实现栈(LIFO) | ArrayDeque(用 push/pop) |
| 实现队列(FIFO) | ArrayDeque 或 LinkedList |
🧪 五、创建不可变 List(Java 9+)
如果你不需要修改,可以创建不可变列表:
1 | // Java 9+ |
⚠️
List.of()和Arrays.asList()返回的列表都不能添加或删除元素。
✅ 六、总结:推荐使用指南
| 实现类 | 推荐程度 | 一句话总结 |
|---|---|---|
ArrayList |
⭐⭐⭐⭐⭐ | 默认首选,性能好,使用最广泛 |
LinkedList |
⭐⭐⭐☆☆ | 仅在频繁插入/删除时使用 |
CopyOnWriteArrayList |
⭐⭐⭐⭐☆ | 并发读多写少场景 |
Vector / Stack |
⭐☆☆☆☆ | 已过时,避免使用 |
📌 一句话建议:
日常开发用
ArrayList,并发读多写少用CopyOnWriteArrayList,实现栈/队列用ArrayDeque。
如果你有具体场景(比如“我要实现一个缓存”或“高频增删的列表”),我可以帮你推荐最合适的 List 实现!
在 Java 中,List 接口继承自 Collection,提供了比普通集合更丰富的操作方法,特别是基于索引(下标)的操作。它是开发中最常用的集合类型之一。
Java中List中的常用方法
📚 一、List 的核心特点回顾
- ✅ 有序:元素按插入顺序排列
- ✅ 可重复:允许存储相同的元素
- ✅ 可索引访问:可以通过
index(下标)获取或修改元素 - ✅ 动态大小:大多数实现支持自动扩容
🔍 二、List 的常用方法一览表
| 方法 | 作用 | 返回类型 | 是否修改 List |
|---|---|---|---|
add(E e) |
在末尾添加元素 | boolean |
✅ 是 |
add(int index, E element) |
在指定位置插入元素 | void |
✅ 是 |
get(int index) |
获取指定位置的元素 | E |
❌ 否 |
set(int index, E element) |
替换指定位置的元素 | E(旧值) |
✅ 是 |
remove(int index) |
删除指定位置的元素 | E(被删除的元素) |
✅ 是 |
remove(Object o) |
删除第一个匹配的元素 | boolean |
✅ 是 |
size() |
获取元素个数 | int |
❌ 否 |
isEmpty() |
判断是否为空 | boolean |
❌ 否 |
contains(Object o) |
判断是否包含某个元素 | boolean |
❌ 否 |
indexOf(Object o) |
返回首次出现的索引 | int(-1 表示不存在) |
❌ 否 |
lastIndexOf(Object o) |
返回最后一次出现的索引 | int |
❌ 否 |
clear() |
清空所有元素 | void |
✅ 是 |
subList(int from, int to) |
截取子列表(视图) | List<E> |
✅ 视图可修改原 list |
toArray() |
转为数组 | Object[] |
❌ 否 |
equals(Object o) |
比较两个 List 是否相等 | boolean |
❌ 否 |
toString() |
返回字符串表示 | String |
❌ 否 |
💡 所有方法都定义在
java.util.List<E>接口中,ArrayList、LinkedList等实现类都会提供这些方法。
🧩 三、详细说明与代码示例
我们以 ArrayList<String> 为例:
1 | List<String> list = new ArrayList<>(); |
1. add(E e) —— 添加到末尾
1 | list.add("D"); // [A, B, C, B, D] |
2. add(int index, E element) —— 插入到指定位置
1 | list.add(1, "X"); // 在索引1处插入 "X" |
⚠️ 如果
index超出范围(index < 0 || index > size()),抛IndexOutOfBoundsException
3. get(int index) —— 获取元素
1 | String elem = list.get(0); // 返回 "A" |
4. set(int index, E element) —— 修改元素
1 | String old = list.set(0, "Z"); // 将索引0的元素改为 "Z",返回旧值 "A" |
5. remove(int index) —— 按索引删除
1 | String removed = list.remove(1); // 删除索引1的元素 "X",返回它 |
6. remove(Object o) —— 按对象删除
1 | boolean isRemoved = list.remove("B"); // 删除第一个 "B" |
⚠️ 只删除第一个匹配项
7. size() —— 获取大小
1 | int count = list.size(); // 4 |
8. isEmpty() —— 判断是否为空
1 | boolean empty = list.isEmpty(); // false |
9. contains(Object o) —— 判断是否包含
1 | boolean hasC = list.contains("C"); // true |
使用
equals()判断相等性。
10. indexOf(Object o) 和 lastIndexOf(Object o)
1 | list.indexOf("B"); // 返回第一次出现的索引 → 2 |
如果找不到,返回
-1
11. clear() —— 清空
1 | list.clear(); |
12. subList(int from, int to) —— 截取子列表
1 | List<String> sub = list.subList(1, 3); // 左闭右开 [1,3) → 索引1和2 |
🔔 重要:
subList返回的是原List的视图(view),修改sub会影响原list!
1 | sub.remove(0); // 删除 "X" |
13. toArray() —— 转为数组
1 | Object[] arr = list.toArray(); |
或者指定类型(推荐):
1 | String[] arr = list.toArray(new String[0]); |
14. equals(Object o) —— 比较两个 List
1 | List<String> a = Arrays.asList("A", "B"); |
✅
List的equals比较的是元素内容和顺序,不是引用。
15. toString() —— 查看内容
1 | System.out.println(list); |
方便调试,自动调用。
🔄 四、遍历 List 的 4 种方式
方式 1:增强 for 循环(最常用)
1 | for (String s : list) { |
方式 2:普通 for 循环(适合需要索引)
1 | for (int i = 0; i < list.size(); i++) { |
方式 3:迭代器(Iterator)
1 | Iterator<String> it = list.iterator(); |
⚠️ 遍历时不能用
list.remove(),要用it.remove()
方式 4:forEach + Lambda(Java 8+)
1 | list.forEach(System.out::println); |
⚠️ 五、常见错误与注意事项
| 错误 | 正确做法 |
|---|---|
list.get(100) 索引越界 |
先判断 index < list.size() |
遍历时用 list.remove() |
改用 Iterator.remove() |
认为 Arrays.asList() 返回可变列表 |
它返回固定大小列表,不能 add/remove |
| 直接比较两个 List 引用 | 应使用 list1.equals(list2) 比较内容 |
✅ 六、总结:最常用方法 Top 10
| 排名 | 方法 | 使用频率 |
|---|---|---|
| 1️⃣ | add(E) |
⭐⭐⭐⭐⭐ |
| 2️⃣ | get(int) |
⭐⭐⭐⭐⭐ |
| 3️⃣ | size() |
⭐⭐⭐⭐☆ |
| 4️⃣ | remove(int) / remove(Object) |
⭐⭐⭐⭐☆ |
| 5️⃣ | set(int, E) |
⭐⭐⭐☆☆ |
| 6️⃣ | contains(Object) |
⭐⭐⭐☆☆ |
| 7️⃣ | indexOf(Object) |
⭐⭐☆☆☆ |
| 8️⃣ | subList(...) |
⭐⭐☆☆☆ |
| 9️⃣ | clear() |
⭐⭐☆☆☆ |
| 🔟 | toArray() |
⭐☆☆☆☆ |
📌 一句话建议:
日常开发中,
add、get、remove、size是最常用的方法,配合增强 for 循环即可完成大部分操作。
如果你有具体需求(比如“如何删除所有偶数”或“找出重复元素”),我可以给出对应的 List 方法组合!欢迎继续提问 😊