Java存储数据之数组与集合的详细操作
作者:invicinble
这篇文章主要介绍了Java中数组和集合的基本概念、优势和使用场景,并详细探讨了集合的各个子类及其特性,同时,文章还涵盖了如何遍历集合以及遍历过程中的一些注意事项,感兴趣的朋友跟随小编一起看看吧
Java存储数据:数组与集合
一、数组(Array)
1. 逻辑特征
- 固定大小:创建时指定长度,不能动态改变
- 类型统一:所有元素必须是相同数据类型
- 内存连续:元素在内存中连续存储
- 效率高:通过索引直接访问,时间复杂度O(1)
- 功能简单:提供基本的存储和访问能力
2. 代码层面
// 1. 声明和初始化
int[] numbers = new int[5]; // 长度为5的整型数组
String[] names = {"张三", "李四", "王五"};
// 2. 访问和修改
numbers[0] = 10;
System.out.println(numbers[0]); // 输出: 10
// 3. 遍历数组
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]);
}
// 4. 增强for循环
for (int num : numbers) {
System.out.println(num);
}
// 5. 多维数组
int[][] matrix = new int[3][3];
matrix[0][0] = 1;3. 数组的局限性
// 问题1: 数组大小固定,无法动态扩展 int[] arr = new int[3]; // arr[3] = 4; // ArrayIndexOutOfBoundsException // 问题2: 只能存储同一类型数据 // arr[0] = "hello"; // 编译错误 // 问题3: 缺少高级操作方法 // 没有内置的add(), remove(), contains()等方法
二、为什么需要集合(Collection)
1. 数组的不足
- 大小固定:不能动态增长或收缩
- 功能有限:缺少增删改查的高级方法
- 类型限制:只能存储相同类型
- 代码繁琐:需要手动处理很多逻辑
2. 集合的优势
- 动态扩容:自动调整大小
- 功能丰富:提供各种操作方法
- 类型灵活:通过泛型支持类型安全
- 算法支持:内置排序、查找等算法
三、集合知识体系
Java集合框架 (Java Collections Framework)
│
├── Collection接口 (单列集合)
│ ├── List接口 (有序、可重复)
│ │ ├── ArrayList: 数组实现,查询快,增删慢
│ │ ├── LinkedList: 链表实现,增删快,查询慢
│ │ └── Vector: 线程安全的ArrayList(已过时)
│ │
│ ├── Set接口 (无序、不可重复)
│ │ ├── HashSet: 哈希表实现
│ │ ├── LinkedHashSet: 有序的HashSet
│ │ └── TreeSet: 红黑树实现,可排序
│ │
│ └── Queue接口 (队列)
│ ├── LinkedList: 也实现了Queue
│ ├── PriorityQueue: 优先级队列
│ └── ArrayDeque: 双端队列
│
└── Map接口 (双列集合,键值对)
├── HashMap: 最常用的Map
├── LinkedHashMap: 有序的HashMap
├── TreeMap: 可排序的Map
└── Hashtable: 线程安全的Map(已过时)四、主要集合类示例
1. ArrayList(最常用)
// 创建ArrayList
List<String> list = new ArrayList<>();
// 添加元素(自动扩容)
list.add("Java");
list.add("Python");
list.add("C++");
// 获取元素
String first = list.get(0);
// 修改元素
list.set(1, "JavaScript");
// 删除元素
list.remove(2);
// 遍历
for (String language : list) {
System.out.println(language);
}
// 其他常用方法
int size = list.size(); // 大小
boolean empty = list.isEmpty(); // 是否为空
boolean contains = list.contains("Java"); // 是否包含2. LinkedList
// 创建LinkedList LinkedList<Integer> linkedList = new LinkedList<>(); // 添加元素 linkedList.add(10); linkedList.addFirst(5); // 头部添加 linkedList.addLast(20); // 尾部添加 // 作为队列使用 linkedList.offer(30); // 入队 int head = linkedList.poll(); // 出队 // 作为栈使用 linkedList.push(40); // 压栈 int top = linkedList.pop(); // 弹栈
3. HashSet
// 创建HashSet
Set<String> set = new HashSet<>();
// 添加元素
set.add("Apple");
set.add("Banana");
set.add("Apple"); // 重复,不会添加
// 遍历(无序)
for (String fruit : set) {
System.out.println(fruit);
}
// 常用操作
set.remove("Banana");
boolean hasApple = set.contains("Apple");4. HashMap
// 创建HashMap
Map<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("Alice", 25);
map.put("Bob", 30);
map.put("Charlie", 28);
// 获取值
int age = map.get("Alice");
// 遍历
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 键集合和值集合
Set<String> keys = map.keySet();
Collection<Integer> values = map.values();
五、集合与数组的对比
| 特性 | 数组 | 集合 |
|---|---|---|
| 大小 | 固定,声明时确定 | 动态,可自动扩容 |
| 类型 | 必须统一 | 通过泛型支持多种类型 |
| 性能 | 访问快(O(1)) | 实现不同,性能各异 |
| 功能 | 基本操作 | 丰富的高级操作 |
| 存储 | 基本类型和对象 | 只能存储对象 |
| 线程安全 | 不安全 | 大部分不安全 |
六、最佳实践建议
- 优先使用集合:除非对性能有极致要求,否则优先使用集合
- 选择合适的集合:
- 需要频繁查询 → ArrayList
- 需要频繁增删 → LinkedList
- 需要去重 → HashSet
- 需要键值对 → HashMap
- 使用泛型:确保类型安全
- 考虑线程安全:多线程环境使用ConcurrentHashMap、CopyOnWriteArrayList
- 初始化大小:如果知道大概数据量,可以指定初始容量
// 指定初始容量 List<String> list = new ArrayList<>(1000); Map<String, Integer> map = new HashMap<>(500);
七、总结
- 数组是Java语言的基础数据结构,简单高效但功能有限
- 集合是对数组的封装和扩展,提供了更强大、更灵活的数据管理能力
- 现代Java开发中,集合是首选,数组主要用于:
- 性能敏感的场景
- 处理基本数据类型
- 与遗留代码或API交互
- 理解不同集合的特性,根据需求选择最合适的工具
实际开发中,ArrayList和HashMap是最常用的集合类,掌握了它们就解决了80%的数据存储问题。
好的,专门说说遍历集合!这是天天要用的操作,分几种情况给你讲清楚。
List遍历(最常用)
1.普通for循环(有索引时用)
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
for (int i = 0; i < list.size(); i++) {
String item = list.get(i);
System.out.println(item);
}优点:能拿到索引,方便操作
缺点:只有 ArrayList 这种基于数组的用着快,LinkedList 用这个就慢(因为要一个个数过去)
2.增强for循环(最常用、最简洁)
for (String item : list) {
System.out.println(item);
}
优点:写法简单,可读性好
缺点:遍历时不能修改集合(删除、新增会抛异常)
3.迭代器Iterator(可以在遍历时安全删除)
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if ("B".equals(item)) {
iterator.remove(); // 安全删除当前元素
}
}
优点:唯一能在遍历时安全删除元素的方式
缺点:代码稍多
4.ListIterator(双向遍历,可以修改)
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {
String item = listIterator.next();
if ("B".equals(item)) {
listIterator.set("B+"); // 修改当前元素
}
}
// 还可以倒着遍历
while (listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
5.Java 8的forEach + Lambda(很流行)
// 方式1:Lambda表达式
list.forEach(item -> System.out.println(item));
// 方式2:方法引用
list.forEach(System.out::println);
// 带索引的(Java 8没有原生支持,但可以这样)
IntStream.range(0, list.size())
.forEach(i -> System.out.println(i + ": " + list.get(i)));Set遍历
Set没索引,所以只能用这几种:
Set<String> set = new HashSet<>(Arrays.asList("A", "B", "C"));
// 1. 增强for循环
for (String item : set) {
System.out.println(item);
}
// 2. 迭代器
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// 3. Java 8 forEach
set.forEach(item -> System.out.println(item));Map遍历(重点!)
1.遍历EntrySet(最推荐、最高效)
Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + "=" + value);
}为什么最推荐?:一次遍历同时拿到key和value,不用再通过key去查value(map.get(key) 还有哈希计算的开销)
2.遍历KeySet(不推荐在遍历中取值)
for (String key : map.keySet()) {
Integer value = map.get(key); // 这里又做了一次哈希查找
System.out.println(key + "=" + value);
}
缺点:多了一次 map.get(key) 的哈希查找,效率低
3.遍历Values(只关心值时用)
for (Integer value : map.values()) {
System.out.println(value);
}
4.迭代器方式
Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> entry = iterator.next();
// 可以在遍历时删除
if ("A".equals(entry.getKey())) {
iterator.remove();
}
}
5.Java 8的forEach(最简洁)
// Lambda表达式
map.forEach((key, value) -> System.out.println(key + "=" + value));
// 或者用entrySet的stream
map.entrySet().stream()
.filter(entry -> entry.getValue() > 1)
.forEach(entry -> System.out.println(entry.getKey()));遍历时的注意事项
1.不要在foreach循环里直接增删元素
// ❌ 错误!会抛 ConcurrentModificationException
for (String item : list) {
if ("B".equals(item)) {
list.remove(item); // 直接调用list的remove
}
}
// ✅ 正确!用迭代器的remove
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if ("B".equals(it.next())) {
it.remove(); // 用迭代器自己的remove方法
}
}2.Java 8的removeIf(删除元素新姿势)
// 删除所有值为"B"的元素 list.removeIf(item -> "B".equals(item)); // Map删除满足条件的entry map.entrySet().removeIf(entry -> entry.getValue() > 10);
3.并行遍历(大数据量时考虑)
// 使用parallelStream(注意线程安全)
list.parallelStream().forEach(item -> {
// 这里可以并行处理
});
// 或者用ConcurrentHashMap的forEach(线程安全)
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.forEach(1, (key, value) -> System.out.println(key));实际工作怎么选?
日常开发:
- 单纯遍历List/Set → 增强for循环(最简洁)
- 遍历Map → entrySet + 增强for 或 map.forEach()
- 需要在遍历时删除 → 迭代器 或 removeIf()
- Java 8+环境 → 多用 forEach + Lambda(代码简洁)
性能考虑:
- 大数据量List →
ArrayList用普通for最快,LinkedList用迭代器 - Map遍历 → 一定用entrySet,别用keySet+get
记忆口诀:
- List遍历:普通for要索引,增强for最方便,要删就用迭代器
- Map遍历:entrySet是王道,keySet效率低,Java8 forEach潮
这样清楚了吗?实际写代码时多试试,自然就熟练了!
到此这篇关于Java存储数据:数组与集合的文章就介绍到这了,更多相关java存储数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
