对 Java 异常处理的学习

throw关键字

  1. 作用:可以使用throw关键字在指定的方法中抛出指定的异常

  2. 使用格式:

    复制
    throw new xxxException(“异常产生的原因“)
  3. 注意事项

    1. throw关键字必须写在方法的内部
    2. throw关键字后边new的对象必须是 Exception或者 Exception的子类对象
    3. throw关键字抛出指定的异常对象,我们就必须处理这个异常对象。
    4. throw关键字后边创建的是 RuntimeException或者是RuntimeException的子类对象,我们可以不处理,默认交给JW处理(打印异常对象,中断程序)
    5. throw关键字后边创建的是编译异常,我们就必须处理这个异常,要么 throws,要么try...catch

举例

例子1

复制
public class DemoThrow {
public static void main(String[] args) {
int[] array = {};
int element = DemoThrow.getElement(array, 1);
}
public static int getElement(int[] array, int index) {
if (array.length == 0) {
throw new NullPointerException("传入的数组为空");
} else if (index == 0 || index > array.length - 1) {
throw new ArrayIndexOutOfBoundsException("传递的索引超出了数组的适用范围");
} else {
return array[index];
}
}
}
复制
抛出错误:
Exception in thread "main" java.lang.NullPointerException: 传入的数组为空
at XXX.DemoThrow.getElement(DemoThrow.java:10)
at XXX.DemoThrow.main(DemoThrow.java:5)

例子2

复制
public class DemoThrow {
public static void main(String[] args) {
int[] array = {1, 2, 3};
int element = DemoThrow.getElement(array, 100);
}
public static int getElement(int[] array, int index) {
if (array.length == 0) {
throw new NullPointerException("传入的数组为空");
} else if (index == 0 || index > array.length - 1) {
throw new ArrayIndexOutOfBoundsException("传递的索引超出了数组的适用范围");
} else {
return array[index];
}
}
}
复制
抛出错误:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 传递的索引超出了数组的适用范围
at XXX.DemoThrow.getElement(DemoThrow.java:12)
at XXX.DemoThrow.main(DemoThrow.java:5)

Objects非空判断requireNonNull

  1. java.util.Objects类是由一些静态实用方法组成,这些方法是空指针安全的(即:容忍空指针的)

  2. 在源码中对对象null值进行了抛出异常错误,源码如下:

    复制
    // 查看指定对象时不时null
    public static <T> T requireNonNull(T obj) {
    if (obj == null)
    throw new NullPointerException();
    return obj;
    }
  3. requireNonNull方法的使用

    复制
    import java.util.Objects;
    public class DemoObjectsNonNull {
    public static void main(String[] args) {
    String s = null;
    Objects.requireNonNull(s, "传入的参数为空");
    }
    }
    复制
    抛出错误:
    Exception in thread "main" java.lang.NullPointerException: 传入的参数为空
    at java.util.Objects.requireNonNull(Objects.java:228)
    at XXX.DemoObjectsNonNull.main(DemoObjectsNonNull.java:6)

自定义非空判断

复制
public class DemoObjectsNonNull {
public static void main(String[] args) {
String s = null;
methodNonNull(s);
}
public static <E> void methodNonNull(E e) {
if (e == null) {
throw new NullPointerException("传入的参数为空");
}
}
}
复制
抛出错误:
Exception in thread "main" java.lang.NullPointerException: 传入的参数为空
at XXX.DemoObjectsNonNull.methodNonNull(DemoObjectsNonNull.java:9)
at XXX.DemoObjectsNonNull.main(DemoObjectsNonNull.java:5)

throws 关键字处理异常

throws作用

当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象。可以使用 throws关键字处理异常对象,它会把异常对象声明抛给方法的调用者处理(自己不处理,绐别人处理)最终交给JVM-->中断处理

使用格式

复制
修饰符 返回值类型 方法名(参数列表) throws AaaException, BbbException ... {
throw new AaaException("产生原因");
throw new BbbException("产生原因");
...
}

注意事项

  1. throws关键字必须写在方法声明处。
  2. throws关键字后边声明的异常必须是Exception或者是Exception的子类。
  3. 方法内部如果抛出了多个异常对象,那么throws后边必须也声明多个异常。如果批出的多个异常对象有子父类关系,那么直接声明父类异常即可
  4. 调用了一个声明抛出异常的方法,我们就必须处理声明的异常,要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM,要么try...catch自己处理异常。

举例

例子1:

复制
import java.io.FileNotFoundException;
public class Demo01Throws {
public static void main(String[] args) throws FileNotFoundException{
String s = "/Users/data.txt";
readFile(s);
}
public static void readFile(String s) throws FileNotFoundException {
if ("/Users/data.txt".equals(s)) {
System.out.println("传入的参数是'/Users/data.txt'");
} else {
throw new FileNotFoundException("传入的参数不是'/Users/data.txt'");
}
}
}
复制
输出结果:
传入的参数是'/Users/data.txt'

例子2:

复制
import java.io.FileNotFoundException;
public class Demo01Throws {
public static void main(String[] args) throws FileNotFoundException{
String s = "/Users/data";
readFile(s);
}
public static void readFile(String s) throws FileNotFoundException {
if ("/Users/data.txt".equals(s)) {
System.out.println("传入的参数是'/Users/data.txt'");
} else {
throw new FileNotFoundException("传入的参数不是'/Users/data.txt'");
}
}
}
复制
抛出错误:
Exception in thread "main" java.io.FileNotFoundException: 传入的参数不是'/Users/data.txt'
at XXX.Demo01Throws.readFile(Demo01Throws.java:11)
at XXX.Demo01Throws.main(Demo01Throws.java:6)

try catch 关键字处理异常

使用格式

复制
try {
...
} catch (异常类名 变量名) {
...
}
...
catch(异常类名 变量名) {
...
} ...

注意事项

  1. try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些异常对象。
  2. 如果try中产生了异常,那么就会执行ctch中的异常处理逻辑,执行完catch中的处理逻辑,会继续执行try...catch之后的代码。
  3. 如果try中没有产生异常,那么就不会执行catch中异常的处理逻辑,执行完try中的代码,继续执行try...catch之后的代码。

举例

复制
public class Demo01TryCatch {
public static void main(String[] args) {
try {
String[] strings = {};
System.out.println(strings[100]);
} catch (ArrayIndexOutOfBoundsException e) {
// 数组索引越界异常
System.out.println("Exception in thread \"main\" java.lang.ArrayIndexOutOfBoundsException");
} catch (NullPointerException e) {
// 空指针异常
System.out.println("Exception in thread \"main\" java.lang.NullPointerException");
}
System.out.println("程序执行完成");
}
}
复制
输出结果:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
程序执行完成

Throwable类中3个异常处理的方法

复制
public void printStackTrace()
// 打印异常的跟踪栈信息,并输出到控制台。包含了异常的类型,异常的原因,还包括异常出现的位置。在开发和调试阶段都得使用printStackTrace。
public String getMessage()
// 获取发生异常的原因。提示给用户时候就提示误原因。
public String toString()
// 获取异常的类型和异常描述信息。

这三个方法源码:

复制
public void printStackTrace() {
printStackTrace(System.err);
}
复制
public String getMessage() {
return detailMessage;
}
复制
public String toString() {
String s = getClass().getName();
String message = getLocalizedMessage();
return (message != null) ? (s + ": " + message) : s;
}

三个方法举例

复制
public class DemoTryCatch {
public static void main(String[] args) {
try {
String[] strings = new String[10];
getElement(strings, 10);
} catch (ArrayIndexOutOfBoundsException e) {
// 获取发生异常的原因
System.out.println(e.getMessage());
// 获取异常的类型和异常描述信息
System.out.println(e.toString());
// 获取栈的跟踪信息(异常的类型、异常的原因、异常出现的位置)
e.printStackTrace();
}
}
public static String getElement(String[] array, int index) {
if (array.length == 0) {
throw new NullPointerException("传入的数组为空");
} else if (index == 0 || index > array.length - 1) {
throw new ArrayIndexOutOfBoundsException("传递的索引超出了数组的适用范围");
} else {
return array[index];
}
}
}
复制
控制台输出:
传递的索引超出了数组的适用范围
java.lang.ArrayIndexOutOfBoundsException: 传递的索引超出了数组的适用范围
java.lang.ArrayIndexOutOfBoundsException: 传递的索引超出了数组的适用范围
at XXX.DemoTryCatch.getElement(DemoTryCatch.java:19)
at XXX.DemoTryCatch.main(DemoTryCatch.java:5)

finally代码块

格式

复制
try {
...
} catch (异常类名 变量名) {
...
}
...
catch(异常类名 变量名) {
...
} finally {
...
}

注意事项

  1. finally不能单独使用,必须要和try一起使用
  2. finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要释放IO

举例

复制
public class DemoFinally {
public static void main(String[] args) {
try {
String[] strings = {};
System.out.println(strings[100]);
} catch (ArrayIndexOutOfBoundsException e) {
// 获取异常的类型和异常描述信息
System.out.println(e.toString());
} finally {
System.out.println("程序执行完成");
}
}
}
复制
控制台输出:
java.lang.ArrayIndexOutOfBoundsException: 100
程序执行完成

多异常的捕获处理

多个异常分别处理

实例理解:

复制
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Demo01ManyException {
public static void main(String[] args) {
try {
int[] array = {1, 2, 3};
int a = array[3];
}
catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e.toString());
}
try {
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3);
int b = list.get(3);
}
catch (IndexOutOfBoundsException e) {
System.out.println(e.toString());
}
}
}
复制
控制台输出:
java.lang.ArrayIndexOutOfBoundsException: 3
java.lang.IndexOutOfBoundsException: Index: 3, Size: 3

多个异常一次捕获多次处理

实例理解:

复制
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Demo01ManyException {
public static void main(String[] args) {
try {
int[] array = {1, 2, 3};
int a = array[3];
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3);
int b = list.get(3);
}
catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e.toString());
}
catch (IndexOutOfBoundsException e) {
System.out.println(e.toString());
}
}
}
复制
控制台输出:
java.lang.ArrayIndexOutOfBoundsException: 3

注意事项

一个try,多个catch,catch里面定义的异常变量,如果有子父类关系,那么子类的异常变量必须写在前面,否则会报错

ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException

img

img

多个异常一次捕获一次处理

实例理解:

复制
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Demo01ManyException {
public static void main(String[] args) {
try {
int[] array = {1, 2, 3};
int a = array[3];
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3);
int b = list.get(3);
}
catch (Exception e) {
System.out.println(e.toString());
}
}
}
复制
控制台输出:
java.lang.ArrayIndexOutOfBoundsException: 3

finally有return语句

如果finally中有return语句,只会返回finally中的值。

如:

复制
public class Demo01FinallyReturn {
public static void main(String[] args) {
System.out.println(Demo01FinallyReturn.method());
}
public static String method() {
try {
String s = "abc";
return s;
} catch (Exception e) {
e.printStackTrace();
} finally {
String s = "ABC";
return s;
}
}
}
复制
控制台输出:
ABC

子父类异常

  1. 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
  2. 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出。

如:

复制
public class Fu {
public static void method1() throws NullPointerException, ClassCastException { }
public static void method2() throws IndexOutOfBoundsException { }
public static void method3() { }
public static void method4() { }
}
复制
public class Zi extends Fu {
/**
* 子类重写父类方法时,抛出和父类相同的异常
* @throws NullPointerException 空指针异常
* @throws ClassCastException 类强制转换异常
*/
public static void method1() throws NullPointerException, ClassCastException { }
/**
* 子类重写父类方法时,抛出父类异常的子类
* @throws ArrayIndexOutOfBoundsException 索引越界异常
*/
public static void method2() throws ArrayIndexOutOfBoundsException { }
/**
* 子类重写父类方法时,不抛出异常
*/
public static void method3() { }
/**
* 父类方法没有抛出异常,子类重写父类方法时,也不可以抛出异常
* 只能捕获处理,不能声明抛出
*/
public static void method4(){
try {
throw new Exception("编译期异常");
} catch (Exception e) {
e.printStackTrace();
}
}
}

自定义异常类的简单练习

要求

模拟注册操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。

分析

  1. 使用数组保存已经注册过的用户名
  2. 使用Scanner获取用户输入的注册的用户名
  3. 定义一个方法,对用户输入中的注册用户名进行判断,遍历存储已经注册过用户名的数组,获取每一个用户名,使用获取到的用户名和用户输入的用户名比较

实现

复制
import java.util.Scanner;
public class MyUsersException {
private static String[] names = {"小红", "小明", "李华", "小军", "大雄"};
public static void registerUser(String scannerUser) {
for (String name : names) {
if (name.equals(scannerUser)) {
try {
throw new RuntimeException("亲,该用户名已被注册!");
} catch (RuntimeException e) {
System.out.println(e.getMessage());
return;
}
}
}
System.out.println("恭喜您注册成功!");
}
public static void main(String[] args) throws RuntimeException{
Scanner scn = new Scanner(System.in);
System.out.print("输入要注册的用户名:");
String registerUserName = scn.next();
MyUsersException.registerUser(registerUserName);
}
}
复制
控制台输入:李华
控制台输出:
亲,该用户名已被注册!
复制
控制台输入:静香
控制台输出:
恭喜您注册成功!
posted @   LeeHua  阅读(936)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示

目录导航