🌿🌿🌿跟随博主脚步,从这里开始→博主主页🌿🌿🌿
- 欢迎大家:这里是我的学习笔记、总结知识的地方,喜欢的话请三连,有问题可以私信🌳🌳🌳
您的点赞👍、关注➕、收藏⭐️、评论📝、私信📧是我最大的支持与鼓舞!!!🌻🌻🌻
异常处理
主要内容
1️⃣异常与异常类(异常是什么?Java内部提供了哪些异常类)
2️⃣异常处理(如何处理异常?)
3️⃣自定义异常类(用户自己如何定义异常类?)
4️⃣ 断言(高级的异常处理形式)
1️⃣异常与异常类
异常
- 异常(exception)是在程序运行过程中产生的使程序终止正常运行的错误对象。
- 如数组下标越界、整数除法中零作除数、文件找不到等都可能使程序终止运行。
异常类
- Java定义了多种异常类。都是java.lang.Throwable类的子类,它是Object类的直接子类。
- Throwable类有两个子类
① Error类
② Exception类
2️⃣异常处理
异常的抛出与捕获
- 方法运行过程中如果产生了异常,在这个方法中就生成一个代表该异常类的对象,并把它交给运行时系统,运行时系统寻找相应的代码来处理该异常。这个过程称为抛出异常。
- 运行时系统在方法的调用栈中查找,从产生异常的方法开始进行回溯,直到找到包含相应异常处理的方法为止,这一过程称为捕获异常。
- 方法调用与回溯如图所示。
try-catch-finally语句
java
try{
// 需要处理的代码
} catch (ExceptionType1 exceptionObject){
// 异常处理代码
}[catch (ExceptionType2 exceptionObject){
// 异常处理代码
}
finally{
// 最后处理代码
} ]
用catch捕获多个异常
- 如果在多个catch块捕获的异常**使用相同的代码处理,**则可以仅用一个catch块处理,而不必单独捕获每个异常,这就减少了代码重复。
- 要在一个catch语句中处理多个异常,需要使用"或"运算符(|)分隔多个异常。
声明方法抛出异常
- 有时方法中产生的异常不需要在该方法中处理,可能需要由该方法的调用方法处理,这时可以在声明方法时用throws子句声明抛出异常,将异常传递给调用该方法的方法处理。
java
returnType methodName([paramlist])
throws ExceptionList{
// 方法体
}
用throw语句抛出异常
- 可以创建一个异常对象,然后用throw语句抛出,或者将捕获到的异常对象用throw语句再次抛出,throw语句的格式如下:
java
throw exceptInstance;
使用try-with-resources语句
- 在JDK 7之前,通常使用finally语句确保调用close()方法:
java
try{
// 打开资源
}catch(Exception e){
// 处理异常
}finally{
// 关闭资源
}
实战演练
下面是打开一个数据库连接的典型代码:
java
Connection connection = null;
try{
// 创建连接对象并执行操作
}catch(Exception e){
// 处理异常
}finally{
if(connection!=null){
try{
connection.close();
}catch(SQLException e){ // 处理异常 }
}
}
- JDK 7提供的自动关闭资源的功能为管理资源(如文件流、数据库连接等)提供了一种更加简便的方式。这种功能是通过一种新的try语句实现的,叫try-with-resources,有时称为自动资源管理。
- try-with-resources的主要好处是可以避免在资源(如文件流)不需要时忘记将其关闭。
- try-with-resources语句的基本形式如下:
java
try(
声明和创建某种资源 )//(只有实现了java.lang.AutoCloseable接口的那些资源才可自动关闭。)
{
// 使用资源
}
[catch(Exception e){}]
[finally{
}]
3️⃣自定义异常
- 编写自定义异常类实际上是继承一个标准异常类,通常继承Exception类,如下所示:
java
class CustomException extends Exception {
public CustomException(){}
public CustomException(String message) {
super(message);
}
}
实战演练
问题描述:
程序中需要验证用户输入的数据值必须是正值。如果用户提供的是负值,程序抛出异常。
编写一个自定义异常类NegativeValueException,负值异常。
java
// 自定义运行时异常类 NegativeValueException
public class NegativeValueException extends RuntimeException {
// 可以添加一个无参构造器
public NegativeValueException() {
super("输入值不能为负!");
}
// 也可以添加一个带有详细错误信息的构造器
public NegativeValueException(String message) {
super(message);
}
// 还可以添加一个带有错误信息和原因的构造器
public NegativeValueException(String message, Throwable cause) {
super(message, cause);
}
// 还可以添加一个带有原因的构造器
public NegativeValueException(Throwable cause) {
super(cause);
}
// 根据需要,你也可以添加更多的构造器或方法
}
然后,你可以在你的程序中使用这个异常类来验证用户输入的值。下面是一个简单的示例,展示了如何在用户输入负值时抛出NegativeValueException:
java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个正数: ");
double input = scanner.nextDouble();
try {
validatePositive(input);
System.out.println("输入有效,您输入的是: " + input);
} catch (NegativeValueException e) {
System.out.println(e.getMessage());
}
scanner.close();
}
// 验证输入是否为正数
public static void validatePositive(double number) throws NegativeValueException {
if (number < 0) {
throw new NegativeValueException("您输入了一个负数!");
}
}
}
在这个示例中,validatePositive
方法用于检查用户输入的值是否为正数。如果输入的是负数,它将抛出一个NegativeValueException
。在main
方法中,通过try-catch
块捕获并处理这个异常。如果用户输入了负数,程序将输出错误消息而不是崩溃。
4️⃣断言
使用断言
- 所谓断言(assertion)是一个Java语句,其中指定一个布尔表达式,程序员认为在程序执行时该表达式的值应该为true。
- 程序通过计算该布尔表达式执行断言,若该表达式为false程序会报告一个错误。通过验证断言是true,能够使程序员确信程序的正确性。
- 断言是通过assert关键字来声明的,断言的使用有两种格式:
java
assert expression ;//如果该表达式值为false,抛出AssertionError异常
assert expression : detailMessage ;
开启和关闭断言
- 编译带有断言的程序与一般程序相同。默认情况下,断言在运行时是关闭的,要开启断言功能,在运行程序时需要使用 --enableassertions或-ea选项,例如:
D:\study>java --ea AssertionDemo
-
在Eclipse中要开启断言,按下列步骤操作:
Run→ Run Configurations → 选择Arguments选项卡
→ Arguments文本框中输入--enableassertions 或-ea 然后执行程序何时使用断言
-
通常来说,断言用于检查一些关键的值,并且这些值对整个应用程序或局部功能的实现有较大影响,并且当断言失败,这些错误是不容易恢复的。
-
以下是一些使用断言的情况,它们可以使Java程序的可靠性更高。
-
- 检查控制流
在if~else和switch~case结构中,可以在不应该发生的控制支流上加上assert false语句。如果这种情况发生了,断言就能够检查出来。
例如,假设x的值只能取1、2或3,可以编写下面的代码:
- 检查控制流
java
switch (x) {
case 1: ...;
case 2: ...;
case 3: ...;
default: assert false : "x 值非法:" + x;
}
-
- 检查前置条件(precondition)
在private
修饰的方法前检查输入参数是否有效。
例如,某方法可能要求输入的参数param
不能为null,就可以在方法的开头加上下面语句:
- 检查前置条件(precondition)
java
assert param != null:"参数不能为null";
-
- 检查后置条件(postcondition)
在方法计算之后检查结果是否有效。对于一些计算方法,运行完成后,某些值需要保证一定的性质。
例如,对计算绝对值的方法可以在方法的结束处使用下面语句进行检查:
- 检查后置条件(postcondition)
java
assert value >= 0:"结果应该大于等于0:" + value;
-
- 检查程序不变量
在程序的运行过程中这些变量的值是不变的,称为不变量。这些不变量可能是一个简单表达式,也可能是一个复杂表达式。对于一些关键的不变量,可以通过assert进行检查。
- 检查程序不变量
断言示例
问题描述
使用对象数组实现一个简单的栈类,在push()、pop()和topValue()方法中使用断言。
java
public class SimpleStack<T> {
private Object[] elements;
private int size;
private int capacity;
public SimpleStack(int initialCapacity) {
capacity = initialCapacity;
elements = new Object[capacity];
size = 0;
}
// 向栈中添加元素
public void push(T item) {
assert size < capacity : "Stack is full, cannot push new item";
elements[size++] = item;
}
// 从栈中移除并返回顶部元素
@SuppressWarnings("unchecked")
public T pop() {
assert size > 0 : "Stack is empty, cannot pop item";
return (T) elements[--size];
}
// 返回栈顶元素但不移除
@SuppressWarnings("unchecked")
public T topValue() {
assert size > 0 : "Stack is empty, cannot access top value";
return (T) elements[size - 1];
}
// 获取栈的当前大小
public int getSize() {
return size;
}
// 获取栈的容量
public int getCapacity() {
return capacity;
}
// 为了简单起见,这里不实现扩容逻辑
// 在实际应用中,你可能需要在push时检查容量,并在需要时扩容
}
// 使用示例
public class Main {
public static void main(String[] args) {
SimpleStack<Integer> stack = new SimpleStack<>(5);
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println("Top value: " + stack.topValue()); // 应输出 3
stack.pop();
System.out.println("New top value: " + stack.topValue()); // 应输出 2
// 尝试在空栈上调用 pop() 或 topValue(),这将触发断言错误(如果启用了断言)
// 注意:在生产环境中,断言可能会被禁用,因此最好有额外的错误处理逻辑
// stack.pop(); // 这将引发 AssertionError,如果断言被启用
}
}
博主用心写,读者点关注,互动传真情,只是不迷路。