Java零基础之异常处理、泛型、Collection单列集合与List集合详解
作者:季夏124
异常
异常的概念与结构
- 异常是在程序执⾏过程中发⽣的⼀种特殊情况或错误状态。它打断了程序的正常流程,需要特别处理。
- Java的异常体系
Error代表的系统级别错误(属于严重问题)
Exception:叫异常,它代表的才是我们程序可能出现的问题,我们通常用Exception以及它的孩子来封装程序中出现的问题
运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现的异常
索引越界异常
public class Test{
public static void main(String[] args) {
int[] arr = {1,2,3};
System.out.println(arr[3]); //ArrayIndexOutOfBoundsException
}
}
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
at com.bit.ExceptionDemo.Test.main(Test.java:6)
算数异常
public class Test{
public static void main(String[] args) {
System.out.println(10 / 0);//ArithmeticException
}
}
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.bit.ExceptionDemo.Test.main(Test.java:7)
空指针异常
public class Test{
public static void main(String[] args) {
int[] array = null;
System.out.println(array.length);//NullPointerException
}
}
Exception in thread "main" java.lang.NullPointerException: Cannot read the array length because "array" is null
at com.bit.ExceptionDemo.Test.main(Test.java:9)
编译时异常:编译阶段就会出现错误提醒(一般不会遇到)
public class Test{
public static void main(String[] args) {
System.out.println("程序开始====");
String str = "2026-07-13";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(str);
// parse方法会抛出编译时异常ParseException,编译器直接报错标红
//原因:parse()方法声明抛出ParseException,属于编译时异常,Java 强制开发者处理。
System.out.println(date);
System.out.println("程序结束====");
}
}
异常的处理
- 抛出异常(throws)
语法格式:修饰符 返回值类型 ⽅法名(参数列表) throws 异常类型1,异常类型2…{
}
public class Test {
public static void main(String[] args) throws Exception {
System.out.println("程序开始");
System.out.println(div(10, 0));
System.out.println("程序结束");
}
public static int div(int a, int b) throws Exception {
if(b == 0){
System.out.println("除数不能为0");
throw new Exception("除数不能为0"); // 抛出异常,程序会终止
}
return a / b;
}
}
程序开始
除数不能为0
Exception in thread "main" java.lang.Exception: 除数不能为0
at com.bit.ExceptionDemo.Test.div(Test.java:15)
at com.bit.ExceptionDemo.Test.main(Test.java:9)
- try-catch捕获并处理异常
throws对异常并没有真正处理,⽽是将异常报告给抛出异常⽅法的调⽤者,由调⽤者处理。如果真正要对异常进⾏处理,就需要try-catch。
语法格式:
try{
// 将可能出现异常的代码放在这⾥
}catch(要捕获的异常类型 e){
// 如果try中的代码抛出异常了,此处catch捕获时异常类型与try中抛出的异常类型⼀致时,或者是try中抛出异常的基类时,就会被捕获到
// 对异常就可以正常处理,处理完成后,跳出try-catch结构,继续执⾏后序代码
}
public class Test {
public static void main(String[] args) {
System.out.println("程序开始");
try {
System.out.println(div(10, 0));
} catch (Exception e) {
e.printStackTrace();
System.out.println("出现异常");
}
System.out.println("程序结束");
}
public static int div(int a, int b) throws Exception {
if(b == 0){
System.out.println("除数不能为0");
throw new Exception("除数不能为0"); // 抛出异常,程序会终止
}
return a / b;
}
}
自定义异常
- Java 内置异常只能覆盖通用场景,业务特有错误(如年龄非法、用户名重复、余额不足)没有对应的异常类,这时我们可以自己定义异常类,精准区分业务报错,让代码可读性、容错性更强。
实现⾃定义异常
具体⽅式:
- ⾃定义异常类,然后继承⾃Exception 或者 RunTimeException
继承 Exception:自定义编译时(受检)异常,调用方法时必须手动 try-catch 或 throws 抛出,否则编译报错;
继承 RuntimeException:自定义运行时(非受检)异常,编译器不强制处理,代码更简洁,现代开发推荐优先使用。 - 实现⼀个带有String类型参数的构造⽅法
public class Test{
public static void main(String[] args) {
System.out.println("程序开始");
try {
Age(130);
} catch (BitAgeIegalException e) {
e.printStackTrace();
System.out.println("出现异常");
}
System.out.println("程序结束");
}
public static void Age(int age) throws BitAgeIegalException {
if(age < 0 || age > 120) {
throw new BitAgeIegalException("年龄不合法,年龄不能为负数或大于120");
} else {
System.out.println("年龄合法");
System.out.println("年龄是:" + age);
}
}
}
/*
* 自定义异常类,继承Exception类
* 重写Exception类的构造方法,添加一个参数为String类型的构造方法,用于传入异常信息
* 创建一个测试类,演示如何抛出和捕获自定义异常
* 哪里需要判断年龄是否合法,就抛出这个异常,哪里需要处理异常,就捕获这个异常
*/
public class BitAgeIegalException extends Exception{
public BitAgeIegalException(String message) {
super(message);
}
}
在定义编译时异常和运行时异常时看程度定义
1.如果这个错误程序员容易出现或者问题严重时定义为编译时异常
2.如果这个问题程序员不容易出现定义为运行时异常
现在Java全面摒弃编译时异常,今后尽量定义运行时异常
异常的处理方案
常见处理方式:最外层捕获异常后,尝试重新修复
核心思路:外层 while 死循环 + try-catch 捕获异常
以用户输入正确价格为例
import java.util.Scanner;
public class Test{
public static void main(String[] args) {
System.out.println("程序开始");
// 死循环,输入格式错误时会重新走循环,直到输入合法数字跳出循环
while (true) {
try{
double price = UserInputPrice();
System.out.println("用户输入的价格是:" + price);
// 调用方法获取用户输入的价格,若输入非数字会抛出输入不匹配异常
break;
// 输入合法,跳出while死循环,结束输入流程
} catch (Exception e) {
// 捕获所有类型异常,提示用户重新输入正确数字
System.out.println("请输入正确的价格:");
}
}
System.out.println("程序结束");
}
public static double UserInputPrice() {
// 创建Scanner扫描器对象,用于读取控制台输入
Scanner scanner = new Scanner(System.in);
System.out.println("请输入价格:");
double price = scanner.nextDouble();
return price;
}
}
Ctrl + alt + T:快速生成 try-catch、while 等代码包裹结构
泛型
- 定义类,解救,方法时,同时声明了一个或者多个类型变量(如:)
称为泛型类,泛型接口,泛型方法,它们统称为泛型。 - 作用:泛型提供了编译阶段约束所能操作的数据类型,并自动进行检查的能力!这样可以避免强制类 型转换,及其可能出现的异常
泛型类
public class GenericDemo {
//目标:学会自定义泛型类
public static void main(String[] args) {
MyArrayList<String> list = new MyArrayList<>();
list.add("hello");
list.add("world");
//list.add(555); //报错,因为它不属于String类型
list.add("java");
list.add("python");
list.remove("world");
System.out.println(list.toString());
}
}
public class MyArrayList<E> {
public boolean add(E e) {
return true; // 临时返回值,表示添加成功
}
public boolean remove(E e) {
return true; // 临时返回值,表示删除成功
}
@Override
public String toString() {
return "MyArrayList{" + "自定义泛型集合" + '}';
}
}
泛型接口
- 什么是泛型接口
在接口名称后通过声明类型参数,接口内的方法参数、返回值都可以使用该泛型,实现类使用时指定具体实体类型。
public class GenericDemo1 {
public static void main(String[] args) {
// 标准多态(推荐,贴合泛型接口学习)
Data<Student> student = new Student();
student.add(new Student());
student.query(1);
Data<Teacher> teacher = new Teacher();
teacher.add(new Teacher());
teacher.query(2);
}
}
// 泛型接口,定义通用增查方法
interface Data<T>{
void add(T t);
T query(int id);
}
// 重点:实现接口时必须指定泛型<Student>
class Student implements Data<Student> {
@Override
public void add(Student student) {
System.out.println("添加学生数据");
}
@Override
public Student query(int id) {
System.out.println("查询id=" + id + "学生");
return null;
}
}
// 重点:实现接口时必须指定泛型<Teacher>
class Teacher implements Data<Teacher> {
@Override
public void add(Teacher teacher) {
System.out.println("添加教师数据");
}
@Override
public Teacher query(int id) {
System.out.println("查询id=" + id + "教师");
return null;
}
}
泛型方法
泛型方法:在方法返回值前声明类型参数,整个方法内都可以使用T代表任意引用类型。
语法格式:修饰符 返回值类型 方法名(T 参数){}
核心优势:一个方法可以接收、处理任意引用类型数据,不用为每种类型单独重载方法,实现代码复用,同时编译期做类型校验。
public class GenericDemo2 {
//目标:学会定义泛型方法,搞清楚作用
//需求:打印任意数组的内容
public static void main(String[] args) {
String[] arr = {"hello","world","java"};
printArray(arr);
Student[] arr2 = new Student[2];
printArray(arr2);
}
public static <T> void printArray(T[] array){
}
}
注意事项
- 泛型声明位置
public static void printArray(T[] array)
必须写在返回值 void 前面,代表当前方法的泛型标识; - T[ ] array:接收任意类型的引用数组,String [ ]、Student [ ]、Integer [ ] 都能传入。
泛型方法使用总结
- 适用场景:需要一套方法处理多种引用类型,如通用打印、通用数组拷贝、通用集合工具;
- 约束:泛型方法仅支持引用类型数组,不能传入 int []、double [] 等基本类型数组;
- 优势:免去大量方法重载,编译期校验类型,不会出现类型转换异常。
通配符和上下限
- 通配符 ? :代表任意未知类型,常用来统一接收一批有继承关系的泛型集合
- 上限通配符 :(<? extends 父类>)
public class GenericDemo {
public static void main(String[] args) {
ArrayList<XiaoMi> xiaomis = new ArrayList<>();
xiaomis.add(new XiaoMi());
xiaomis.add(new XiaoMi());
xiaomis.add(new XiaoMi());
go(xiaomis);
ArrayList<Byd> byds = new ArrayList<>();
byds.add(new Byd());
byds.add(new Byd());
byds.add(new Byd());
go(byds);
// ArrayList<Dog> dogs = new ArrayList<>();
// dogs.add(new Dog());
// dogs.add(new Dog());
// go(dogs); // Error: dogs is not a subclass of Car
}
public static void go(ArrayList<? extends Car> cars){
}
}
public class Car {
}
public class XiaoMi extends Car {
}
public class Byd extends Car {
}
public class Dog {
}
包装类
| 基本数据类型 | 对应包装类(应用数据类型) |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| char | Character |
| float | Float |
| double | Double |
| boolean | Boolean |
- 自动装箱:基本数据类型的数据可以直接变成包装对象的数据
- 自动拆箱:包装对象的数据可以直接变成基本数据类型的数据
import java.util.ArrayList;
public class GenericDemo3 {
//目标:搞清楚泛型和集合不支持基本数据类型,只支持引用数据类型
//把基本数据类型包装成对象
public static void main(String[] args) {
//手工装箱
Integer i1 = Integer.valueOf(10);
Integer i2 = Integer.valueOf(10);
System.out.println(i1 == i2);
//自动装箱:基本数据类型的数据可以直接变成包装对象的数据
Integer i3 = 10;
Integer i4 = 10;
System.out.println(i3 == i4);
//自动拆箱:包装对象的数据可以直接变成基本数据类型的数据
int i5 = i3;
System.out.println(i5);
ArrayList<Integer> list = new ArrayList<>();
list.add(10);
list.add(20);
list.add(30);
int it = list.get(1);
System.out.println(it);
System.out.println("============================================");
//包装类新增方法
int i = 23;
String s = Integer.toString(i);
System.out.println(s + 1);//231
//2.把字符串数值转换成基本数据类型
String s1 = "123";
//int i6 = Integer.parseInt(s1);
int i6 = Integer.valueOf(s1);
System.out.println(i6 + 1);//124
String s2 = "123.45";
double d = Double.valueOf(s2);
System.out.println(d + 1);//124.45
}
}
集合
单列集合体系结构

Collection 集合特点
List 系列集合:添加的元素是有序、可重复、有索引。
ArrayList、LinkedList:有序、可重复、有索引。
Set 系列集合:添加的元素是无序、不重复、无索引。
HashSet:无序、不重复、无索引;
LinkedHashSet:有序、不重复、无索引。
TreeSet:按照大小默认升序排序、不重复、无索引。
了解Collection集合的常用功能
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class Collection1 {
public static void main(String[] args) {
//搞清楚Collection提供的通用集合功能
Collection<String> list = new ArrayList<String>();
//添加元素
list.add("hello");
list.add("world");
list.add("bit");
System.out.println(list);
//获取集合元素个数
System.out.println(list.size());
//删除元素
list.remove("hello");
System.out.println(list);
//判断集合是否为空
System.out.println(list.isEmpty());
//判断集合是否包含某个元素
System.out.println(list.contains("world"));
// //清空集合
// list.clear();
// System.out.println(list);
//把集合转换成数组
Object[] array = list.toArray();
System.out.println(Arrays.toString(array));
}
}
Collection的遍历方式
- 迭代器遍历
迭代器是用来遍历集合的专用方式(数组没有迭代器),在Java中迭代器的代表对象是Iterator
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Collection2 {
public static void main(String[] args) {
//掌握Collection的遍历方式一:迭代器遍历
//创建一个Collection对象
Collection<String> names = new ArrayList<String>();
names.add("张三");
names.add("李四");
names.add("王五");
names.add("赵六");
System.out.println(names);//[张三, 李四, 王五, 赵六]
//使用迭代器遍历
Iterator<String> it = names.iterator();
//使用while循环遍历
while (it.hasNext()) {
String name = it.next();
System.out.println(name);
}
}
}
- 增强for循环
格式:for(元素的数据类型 变量名 : 数组或者集合){
}
import java.util.ArrayList;
import java.util.Collection;
public class Collection3 {
public static void main(String[] args) {
//掌握Collection的遍历方式一:增强for循环
//创建一个Collection对象
Collection<String> names = new ArrayList<String>();
names.add("张三");
names.add("李四");
names.add("王五");
names.add("赵六");
//使用增强for循环遍历
for (String name : names) {
System.out.println(name);
}
String[] users = {"张三", "李四", "王五", "赵六"};
for (String user : users) {
System.out.println(user);
}
}
}
- Lambda表达式
import java.util.ArrayList;
import java.util.Collection;
public class Collection4 {
public static void main(String[] args) {
//掌握Collection的遍历方式一:Lambda表达式
//创建一个Collection对象
Collection<String> names = new ArrayList<String>();
names.add("张三");
names.add("李四");
names.add("王五");
names.add("赵六");
//使用Lambda表达式遍历
// names.forEach(new Consumer<String>() {
// @Override
// public void accept(String s) {
// System.out.println(s);
// }
// });
names.forEach(s -> System.out.println(s));
}
}
认识并发修改异常问题
- 遍历集合的同时又存在增删集合元素的行为时同时出现业务异常,这种现象称为并发修改异常问题
import java.util.ArrayList;
public class Collection5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
list.add("C#");
list.add("Java");
//删除全部Java
for(int i = 0; i < list.size(); i++) {
String names = list.get(i);
if(names.contains("Java")) {
list.remove(names);
i--;
}
}
System.out.println(list);
}
}
- 用迭代器自己的方法来删除
import java.util.ArrayList;
import java.util.Iterator;
public class Collection5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
list.add("C#");
list.add("Java");
//删除全部Java
//迭代器遍历并删除默认也存在并发修改异常,需要使用迭代器的remove方法
Iterator<String> it = list.iterator();
while (it.hasNext()){
String name = it.next();
if (name.contains("Java")) {
it.remove();
}
}
System.out.println(list);
}
解决并发修改异常问题的方案
① 如果集合支持索引,可以使用 for 循环遍历,每删除数据后做 i–;或者可以倒着遍历
② 可以使用迭代器遍历,并用迭代器提供的删除方法删除数据。
注意:增强 for 循环 / Lambda 遍历均不能解决并发修改异常问题,因此它们只适合做数据的遍历,不适合同时做增删操作。
List集合系列
- 特点,功能以及四种遍历方式
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Collection6 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
System.out.println(list);
//给第三个位置插入一个数据
list.add(2,"JavaScript");
System.out.println(list);
//删除Python
list.remove("Python");
System.out.println(list);
//把C++改成C#
list.set(2,"C#");
System.out.println(list);
//获取C#
System.out.println(list.get(2));
//1.for循环
for(int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//2.迭代器
Iterator<String> it = list.iterator();
while(it.hasNext()) {
String s = it.next();
System.out.println(s);
}
//3.增强for循环
for(String s : list) {
System.out.println(s);
}
//4.Lambda表达式
list.forEach(s -> System.out.println(s));
}
}
四种遍历方式
- 普通 for 循环(唯一支持下标操作)
适合需要获取索引、中途根据下标删除元素的场景 - Iterator 迭代器
底层原生遍历方式,遍历中安全删除元素不会触发并发修改异常 - 增强 for 循环(foreach)
底层基于迭代器,写法简洁,遍历中不能用集合 remove 删除元素 - Lambda 表达式 forEach
代码最简洁,同样不支持遍历内删除集合元素
LinkedList 实现队列、栈
核心方法
- addLast():尾部入队
- removeFirst():头部出队,取出并删除队首元素
import java.util.LinkedList;
public class Collection7 {
public static void main(String[] args) {
LinkedList<String> queue = new LinkedList<>();
//入队
queue.addLast("Java");
queue.addLast("Python");
queue.addLast("C++");
queue.addLast("JavaScript");
queue.addLast("C#");
System.out.println(queue);
//出队
System.out.println(queue.removeFirst());
System.out.println(queue.removeFirst());
System.out.println(queue);
//做一个栈,后进先出
}
}
模拟栈:后进先出 LIFO
核心方法
- push():头部压栈(等价addFirst())
- pop():头部弹栈(等价removeFirst())
import java.util.LinkedList;
public class Collection7 {
public static void main(String[] args) {
//做一个栈,后进先出
LinkedList<String> stack = new LinkedList<>();
stack.push("Java");
stack.push("Python");
stack.push("C++");
stack.push("JavaScript");
stack.push("C#");
System.out.println(stack);//[C#, JavaScript, C++, Python, Java]
//出栈
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack);
}
}
总结
到此这篇关于Java零基础之异常处理、泛型、Collection单列集合与List集合的文章就介绍到这了,更多相关Java异常、泛型、Collection单列集合与List集合内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
