java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java存储数据

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

作者:invicinble

这篇文章主要介绍了Java中数组和集合的基本概念、优势和使用场景,并详细探讨了集合的各个子类及其特性,同时,文章还涵盖了如何遍历集合以及遍历过程中的一些注意事项,感兴趣的朋友跟随小编一起看看吧

Java存储数据:数组与集合

一、数组(Array)

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);

七、总结

实际开发中,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));

实际工作怎么选?

日常开发

性能考虑

记忆口诀

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

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

您可能感兴趣的文章:
阅读全文