Java存储数据之数组与集合的详细操作

 更新时间:2026年01月22日 14:16:29   作者: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))实现不同,性能各异
功能基本操作丰富的高级操作
存储基本类型和对象只能存储对象
线程安全不安全大部分不安全

六、最佳实践建议

  1. 优先使用集合:除非对性能有极致要求,否则优先使用集合
  2. 选择合适的集合
    • 需要频繁查询 → ArrayList
    • 需要频繁增删 → LinkedList
    • 需要去重 → HashSet
    • 需要键值对 → HashMap
  3. 使用泛型:确保类型安全
  4. 考虑线程安全:多线程环境使用ConcurrentHashMap、CopyOnWriteArrayList
  5. 初始化大小:如果知道大概数据量,可以指定初始容量
// 指定初始容量
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 + 增强formap.forEach()
  • 需要在遍历时删除 → 迭代器removeIf()
  • Java 8+环境 → 多用 forEach + Lambda(代码简洁)

性能考虑

  • 大数据量List → ArrayList用普通for最快,LinkedList用迭代器
  • Map遍历 → 一定用entrySet,别用keySet+get

记忆口诀

  • List遍历:普通for要索引,增强for最方便,要删就用迭代器
  • Map遍历:entrySet是王道,keySet效率低,Java8 forEach潮

这样清楚了吗?实际写代码时多试试,自然就熟练了!

到此这篇关于Java存储数据:数组与集合的文章就介绍到这了,更多相关java存储数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot整合RabbitMQ实现通配符模式

    SpringBoot整合RabbitMQ实现通配符模式

    本文主要介绍了SpringBoot整合RabbitMQ实现通配符模式,包括依赖添加、配置、队列与交换机声明及绑定,生产者发送消息,两个消费者分别接收并处理,验证消息正确分发至不同队列,感兴趣的可以了解一下
    2025-06-06
  • 面试题:Java中如何停止线程的方法

    面试题:Java中如何停止线程的方法

    这篇文章主要介绍了Java中如何停止线程的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • Java常用内置注解用法分析

    Java常用内置注解用法分析

    这篇文章主要介绍了Java常用内置注解用法,结合实例形式分析了java使用@SuppressWarnings关闭警告信息以及@Depreca标注的元素不使用两种注解使用方法,需要的朋友可以参考下
    2019-08-08
  • springboot logback调整mybatis日志级别无效的解决

    springboot logback调整mybatis日志级别无效的解决

    这篇文章主要介绍了springboot logback调整mybatis日志级别无效的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • 比较java中Future与FutureTask之间的关系

    比较java中Future与FutureTask之间的关系

    在本篇文章里我们给大家分享了java中Future与FutureTask之间的关系的内容,有需要的朋友们可以跟着学习下。
    2018-10-10
  • MyBatis解决Update动态SQL逗号的问题

    MyBatis解决Update动态SQL逗号的问题

    这篇文章主要介绍了MyBatis解决Update动态SQL逗号的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • 解决springboot的aop切面不起作用问题(失效的排查)

    解决springboot的aop切面不起作用问题(失效的排查)

    这篇文章主要介绍了解决springboot的aop切面不起作用问题(失效的排查),具有很好的参考价值,希望对大家有所帮助。 一起跟随小编过来看看吧
    2020-04-04
  • Java使用Spire.Presentation for Java库合并PowerPoint的技术教程

    Java使用Spire.Presentation for Java库合并PowerPoint的技术教

    在现代企业和个人开发中,文档处理是不可或缺的一环,尤其是在报告演示、内容整合等场景下,PowerPoint 文件的自动化处理需求日益增长,本文将深入探讨如何利用 Java 编程语言,结合强大的 Spire.Presentation for Java库,实现PowerPoiont文件的合并
    2026-01-01
  • 本地编译打包项目部署到服务器并且启动方式

    本地编译打包项目部署到服务器并且启动方式

    这篇文章主要介绍了本地编译打包项目部署到服务器并且启动方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Java环境下高德地图Api的使用方式

    Java环境下高德地图Api的使用方式

    这篇文章主要介绍了Java环境下高德地图Api的使用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06

最新评论