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拦截器的自定义设计与实现全攻略

    深入探究SpringBoot拦截器的自定义设计与实现全攻略

    拦截器是Spring框架提供的核心功能之⼀,主要用来拦截用户的请求,在指定方法前后,根据业务需要执行预先设定的代码,本文将给大家和大家一起深入探究SpringBoot拦截器的自定义设计与实现,需要的朋友可以参考下
    2024-05-05
  • Java比较问题详细分析

    Java比较问题详细分析

    本篇文章主要给大家讲解了Java中比较问题的相关知识,一起参考学习下吧。
    2017-12-12
  • 探索Java中的equals()和hashCode()方法_动力节点Java学院整理

    探索Java中的equals()和hashCode()方法_动力节点Java学院整理

    这篇文章主要介绍了探索Java中的equals()和hashCode()方法的相关资料,需要的朋友可以参考下
    2017-05-05
  • SpringBoot初始化加载配置的八种方式总结

    SpringBoot初始化加载配置的八种方式总结

    在日常开发时,我们常常需要 在SpringBoot应用启动时执行某一段逻辑,如获取一些当前环境的配置或变量、向数据库写入一些初始数据或者连接某些第三方系统,确认对方可以工作,那么在实现初始化逻辑代码时就需要小心了,所以本文介绍了SpringBoot初始化加载配置的方式
    2024-12-12
  • 基于SpringBoot实现轻量级的动态定时任务调度的方法

    基于SpringBoot实现轻量级的动态定时任务调度的方法

    本文介绍了如何在SpringBoot框架中实现轻量级的动态定时任务调度,通过将任务以类为基础单位,并通过配置数据进行任务读取和反射生成任务对象,感兴趣的朋友跟随小编一起看看吧
    2024-11-11
  • 利用Java Set 去除重复object的方法

    利用Java Set 去除重复object的方法

    下面小编就为大家带来一篇利用Java Set 去除重复object的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • Java对象字段拷贝最佳实践分享

    Java对象字段拷贝最佳实践分享

    文章介绍了几种常见的对象字段拷贝方法,包括手动set、BeanUtils.copyProperties、Lombok的@Builder和MapStruct,每种方法都有其优缺点和适用场景,推荐使用MapStruct,因为它在编译期生成代码,性能最优,支持复杂对象映射,需要的朋友可以参考下
    2025-03-03
  • Java中Lambda表达式的使用详解

    Java中Lambda表达式的使用详解

    Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑
    2021-09-09
  • mybatis自动生成时如何设置不生成Example类详解

    mybatis自动生成时如何设置不生成Example类详解

    这篇文章主要给大家介绍了关于mybatis自动生成时如何设置不生成Example类的相关资料,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-05-05
  • Springmvc项目web.xml中servlet-mapping路径映射配置注意说明

    Springmvc项目web.xml中servlet-mapping路径映射配置注意说明

    这篇文章主要介绍了Springmvc项目web.xml中servlet-mapping路径映射配置注意说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12

最新评论