Java基础快速入门:集合入门

本文纲要

1 ) 集合概述

  1. 集合与数组对比
  2. 集合体系结构

2 ) 单列集合 Collection 入门

  1. Collection 常用方法

    • 添加元素:add
    • 删除元素:remove
    • 条件删除:removeIf
    • 清空集合:clear
    • 判断存在:contains
    • 判断为空:isEmpty
    • 获取大小:size
  2. 迭代器 Iterator

    • 迭代器基本使用
    • 迭代器原理分析
    • 迭代器删除方法
  3. 增强 for 循环

    • 基本格式
    • 注意点
  4. 集合练习:存储学生对象并遍历

3 ) 总结

集合概述

1 ) 集合与数组对比

在 Java 中,如果需要同时存储多个元素,可以使用数组或集合。它们的主要区别如下:

  • 长度可变性:数组的长度是固定的,一旦定义就不能改变;集合的长度是可变的,可以根据需要自动扩容。
  • 存储数据类型:数组既可以存储基本数据类型(如 intdouble),也可以存储引用数据类型(如 String、自定义对象);集合只能存储引用数据类型,不能直接存储基本数据类型。如果确实需要存储基本数据类型,则必须使用它们对应的包装类(例如 int 对应 Integer)。

代码演示

项目结构如下:

mycollection/
└── src/
    └── com/
        └── wb/
            └── mycollectiondemo1/
                ├── MyCollectonDemo1.java
                ├── MyCollectonDemo2.java
                ├── MyCollectonDemo3.java 
                ├── MyCollectonDemo4.java
                ├── MyCollectonDemo5.java
                ├── MyCollectonDemo6.java
                ├── MyCollectonDemo7.java
                ├── MyCollectonDemo8.java
                └── Student.java

下面通过 MyCollectonDemo1 类来对比数组和集合的存储能力:

package com.wb.mycollectiondemo1;
 
import java.util.ArrayList;
import java.util.Arrays;
 
public class MyCollectonDemo1 {
    public static void main(String[] args) {
        // 数组可以存储基本数据类型也可以存储引用数据类型
        int[] arr1 = {1, 2, 3};
        String[] arr2 = {"a", "b", "c"};
        System.out.println(Arrays.toString(arr1));
        System.out.println(Arrays.toString(arr2));
 
        // 集合存储引用数据类型
        ArrayList<String> list1 = new ArrayList<>();
        list1.add("a");
        list1.add("b");
        list1.add("c");
        System.out.println(list1);
 
        // 集合不能直接存储基本数据类型,必须使用包装类
        // ArrayList<int> list2 = new ArrayList<int>();   // 错误写法
        ArrayList<Integer> list2 = new ArrayList<>();
        list2.add(1);
        list2.add(2);
        list2.add(3);
        System.out.println(list2);
    }
}

运行结果:

[1, 2, 3]
[a, b, c]
[a, b, c]
[1, 2, 3]

小结

  • 数组长度固定,集合长度可变。
  • 数组可以存储基本类型和引用类型,集合只能存储引用类型;存基本类型时需要包装类。

2 ) 集合体系结构

Java 中的集合分为两大派系:

  • 单列集合:一次只存储一个元素,顶层接口为 Collection
  • 双列集合:一次存储一对元素(键值对),顶层接口为 Map

单列集合又根据是否允许重复元素分为:

  • List 集合:允许重复元素,常见实现类有 ArrayListLinkedList
  • Set 集合:不允许重复元素,常见实现类有 HashSetTreeSet

双列集合 Map 的常见实现类有 HashMapTreeMap

集合体系结构可用下图表示:

«interface»

Collection

«interface»

List

«interface»

Set

«interface»

Map

ArrayList

LinkedList

HashSet

TreeSet

HashMap

TreeMap

后续学习将按照自上而下的顺序进行:先掌握顶层接口或父类中的共性方法,再了解子类特有的功能,这样可以更好地举一反三

单列集合 Collection 入门

1 ) Collection 常用方法

Collection 是单列集合的顶层接口,不能直接实例化,通常使用多态方式创建其实现类对象(如 ArrayList)。下面是 Collection 中需要掌握的常用方法。

添加元素:add(E e)

Collection<String> collection = new ArrayList<>();
collection.add("aaa");
collection.add("bbb");
collection.add("ccc");
collection.add("dddd");
System.out.println(collection);

删除元素:remove(Object o)

该方法返回 boolean 值,表示删除是否成功

private static void method1(Collection<String> collection) {
    // boolean remove(Object o) 从集合中移除指定的元素
    // 如果删除成功,返回 true;否则返回 false
    boolean result1 = collection.remove("aaa");
    boolean result2 = collection.remove("ddd");
    System.out.println(result1);   // true
    System.out.println(result2);   // false 
    System.out.println(collection); // [bbb, ccc, dddd]
}

条件删除:removeIf(Predicate filter)

该方法接收一个 Predicate 函数式接口,可以使用 Lambda 表达式写出删除条件。底层会遍历集合,将每个元素交给 Lambda 表达式判断,若返回 true 则删除该元素,false 则保留。

private static void method2(Collection<String> collection) {
    // removeIf 底层会遍历集合,s 依次表示集合中的每一个元素
    // 若 lambda 表达式返回 true,则删除该元素;若返回 false,则保留
    collection.removeIf((String s) -> {
        return s.length() == 3;   // 删除长度为3的字符串
    });
    System.out.println(collection); // 删除 aaa, bbb, ccc 后,只剩下 dddd
}

Lambda 表达式的写法依据:removeIf 的参数类型为 Predicate<T>,该接口只有一个抽象方法 boolean test(T t),因此 Lambda 表达式中的参数类型与集合元素类型一致,方法体返回布尔值即可。

清空集合:clear()

private static void method3(Collection<String> collection) {
    // void clear() 清空集合,将集合中所有元素全部删除
    collection.clear();
    System.out.println(collection); // []
}

判断存在:contains(Object o)

private static void method4(Collection<String> collection) {
    // boolean contains(Object o) 判断集合中是否存在指定的元素
    boolean result = collection.contains("a");
    System.out.println(result);   // false 
 
    boolean result2 = collection.contains("aaa");
    System.out.println(result2);  // true
}

判断为空:isEmpty()

private static void method5(Collection<String> collection) {
    // boolean isEmpty() 判断集合是否为空
    collection.clear();
    boolean result = collection.isEmpty();
    System.out.println(result);   // true
}

获取大小:size()

private static void method6(Collection<String> collection) {
    // int size() 返回集合中元素的个数 
    int size = collection.size();
    System.out.println(size);     // 此时集合有4个元素,输出4
}

2 ) 迭代器 Iterator

迭代器是集合特有的遍历方式,所有单列集合都可以通过迭代器遍历。

迭代器基本使用

获取迭代器对象:通过集合的 iterator() 方法,默认指向集合的 0 索引位置。
遍历时需要两个方法:

  • hasNext():判断当前位置是否有元素可以取出。
  • next():取出当前位置的元素,并将迭代器向后移动一个位置。
Collection<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");

// 1. 获取迭代器对象,默认指向 0 索引
Iterator<String> it = list.iterator();
 
// 2. 利用 hasNext 和 next 循环遍历
while (it.hasNext()) {
    System.out.println(it.next());
}

如果直接多次调用 next() 而不判断,当没有元素时继续调用会抛出 NoSuchElementException 异常,因此必须搭配 hasNext() 使用。

迭代器原理分析

迭代器的底层原理可以概括为三个方法的协作:

  1. iterator():创建迭代器对象,等效于一个指针,初始指向集合的 0 索引位置。
  2. hasNext():询问当前指针位置是否有元素,有则返回 true,没有则返回 false。
  3. next():完成两件事——获取当前指针位置的元素,然后将指针移动到下一个位置。

遍历过程可用流程图表示:

true

false

调用 iterator() 获得迭代器对象
指针指向 0 索引

hasNext()?

调用 next()
获取当前元素,指针后移

遍历结束

当指针移动到最后一个元素之后时,hasNext() 返回 false,循环结束,不会再调用 next(),避免了异常。

迭代器删除方法

在遍历过程中,如果需要对元素进行删除,推荐使用迭代器自身的 remove() 方法。
该方法不需要参数,会删除当前迭代器指向的元素。

示例:删除集合中所有值为 “b” 的元素。

ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
 
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String s = it.next();
    if ("b".equals(s)) {
        it.remove();   // 删除当前迭代器指向的元素
    }
}
System.out.println(list);  // [a, c, d]

为什么不用普通 for 循环删除?

普通 for 循环在删除元素时,由于集合长度动态变化,容易漏删相邻的重复元素。例如:

for (int i = 0; i < list.size(); i++) {
	String s = list.get(i);
	if ("b".equals(s)) {
		list.remove(i);
	}
}

当删除一个 “b” 后,后面的元素会整体前移,而循环的索引 i 会继续加 1,导致紧邻的第二个 “b” 被跳过。
若必须使用普通 for 循环,可以在删除后手动执行 i-- 来修正索引,但这种方式容易出错,不如迭代器简洁。

3 ) 增强 for 循环

增强 for 循环(foreach)是 JDK 5 引入的简化遍历语法,其底层同样基于迭代器,适用于所有实现了 Iterable 接口的类(单列集合的顶层接口 Collection 继承了 Iterable,因此所有单列集合都支持增强 for;双列集合 Map 不直接支持,但可通过其他方式间接使用)。
基本格式

for (元素类型 变量名 : 待遍历的集合或数组) {
    // 在此使用变量名,它依次表示每一个元素
}

示例:

ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f");
 
// 增强 for 遍历
for (String str : list) {
    System.out.println(str);
}

格式注意点:

  • 数据类型必须与集合或数组中元素的类型一致。
  • 变量名仅是一个临时变量,在循环过程中依次代表每个元素。
  • 冒号后面是待遍历的集合或数组。

注意点

  • 在增强 for 中修改临时变量的值,不会影响集合中的元素。
  • 因为临时变量仅仅是一个副本,修改它并不会改变集合本身。
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
 
for (String str : list) {
    str = "q";          // 修改的是临时变量 str 
    System.out.println(str);  // 输出 q q q q
}
System.out.println(list);  // 依然是 [a, b, c, d]

此外,IDEA 等开发工具提供了快捷生成方式:输入 list.for 并回车,即可自动生成增强 for 循环模板。

遍历方式选择建议

  • 普通 for 循环:需要操作索引时使用。
  • 迭代器:遍历过程中需要删除元素时使用。
  • 增强 for 循环:仅单纯遍历时使用,代码最简洁。

集合练习:存储学生对象并遍历

需求:创建一个 Collection 集合,存储三个学生对象,并分别使用迭代器和增强 for 循环进行遍历。

学生类 Student

public class Student {
    private String name;
    private int age;
 
    public Student() { }
 
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    // getter / setter 省略 
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试类

ArrayList<Student> list = new ArrayList<>();
 
Student s1 = new Student("小皮同学", 23);
Student s2 = new Student("小路同学", 31);
Student s3 = new Student("小贾同学", 33);
 
list.add(s1);
list.add(s2);
list.add(s3);
 
// 迭代器遍历
Iterator<Student> it = list.iterator();
while (it.hasNext()) {
    Student s = it.next();
    System.out.println(s);
}
 
System.out.println("-------------------------");
 
// 增强 for 遍历
for (Student student : list) {
    System.out.println(student);
}

运行结果:

Student{name='小皮同学', age=23}
Student{name='小路同学', age=31}
Student{name='小贾同学', age=33}
Student{name='小皮同学', age=23}
Student{name='小路同学', age=31}
Student{name='小贾同学', age=33}

总结

本文从集合与数组的对比入手,介绍了 Java 集合的体系结构,并重点讲解了单列集合 Collection 的常用方法、迭代器遍历、增强 for 循环等内容。通过代码实例和原理分析,帮助读者快速掌握:

  • 集合长度可变、只能存储引用类型的特点;
  • 单列集合与双列集合的顶层接口;
  • addremoveremoveIfclearcontainsisEmptysize 等方法的使用;
  • 迭代器的工作原理及删除操作的优势;
  • 增强 for 循环的格式与注意事项。

后续文章将继续深入 ListSetMap 及其实现类的具体用法,敬请期待

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值