🌿🌿🌿跟随博主脚步,从这里开始→博主主页🌿🌿🌿
- 欢迎大家:这里是我的学习笔记、总结知识的地方,喜欢的话请三连,有问题可以私信🌳🌳🌳
您的点赞👍、关注➕、收藏⭐️、评论📝、私信📧是我最大的支持与鼓舞!!!🌻🌻🌻
异常处理
- 主要内容
- 1️⃣异常与异常类
- 异常
- 异常类
- 2️⃣异常处理
- 异常的抛出与捕获
- try-catch-finally语句
- 用catch捕获多个异常
- 声明方法抛出异常
- 用throw语句抛出异常
- 使用try-with-resources语句
- 实战演练
- 3️⃣自定义异常
- 实战演练
- 4️⃣断言
- 使用断言
- 开启和关闭断言
- 何时使用断言
- 断言示例
主要内容
1️⃣异常与异常类(异常是什么?Java内部提供了哪些异常类)
2️⃣异常处理(如何处理异常?)
3️⃣自定义异常类(用户自己如何定义异常类?)
4️⃣ 断言(高级的异常处理形式)
1️⃣异常与异常类
异常
- 异常(exception)是在程序运行过程中产生的使程序终止正常运行的错误对象。
- 如数组下标越界、整数除法中零作除数、文件找不到等都可能使程序终止运行。
异常类
- Java定义了多种异常类。都是java.lang.Throwable类的子类,它是Object类的直接子类。
- Throwable类有两个子类
① Error类
② Exception类
2️⃣异常处理
异常的抛出与捕获
- 方法运行过程中如果产生了异常,在这个方法中就生成一个代表该异常类的对象,并把它交给运行时系统,运行时系统寻找相应的代码来处理该异常。这个过程称为抛出异常。
- 运行时系统在方法的调用栈中查找,从产生异常的方法开始进行回溯,直到找到包含相应异常处理的方法为止,这一过程称为捕获异常。
- 方法调用与回溯如图所示。
try-catch-finally语句
try{// 需要处理的代码
} catch (ExceptionType1 exceptionObject){// 异常处理代码
}[catch (ExceptionType2 exceptionObject){// 异常处理代码
}
finally{// 最后处理代码
} ]
用catch捕获多个异常
- 如果在多个catch块捕获的异常**使用相同的代码处理,**则可以仅用一个catch块处理,而不必单独捕获每个异常,这就减少了代码重复。
- 要在一个catch语句中处理多个异常,需要使用“或”运算符(|)分隔多个异常。
声明方法抛出异常
- 有时方法中产生的异常不需要在该方法中处理,可能需要由该方法的调用方法处理,这时可以在声明方法时用throws子句声明抛出异常,将异常传递给调用该方法的方法处理。
returnType methodName([paramlist]) throws ExceptionList{// 方法体}
用throw语句抛出异常
- 可以创建一个异常对象,然后用throw语句抛出,或者将捕获到的异常对象用throw语句再次抛出,throw语句的格式如下:
throw exceptInstance;
使用try-with-resources语句
- 在JDK 7之前,通常使用finally语句确保调用close()方法:
try{// 打开资源}catch(Exception e){// 处理异常}finally{// 关闭资源}
实战演练
下面是打开一个数据库连接的典型代码:
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语句的基本形式如下:
try(声明和创建某种资源 )//(只有实现了java.lang.AutoCloseable接口的那些资源才可自动关闭。)
{// 使用资源
}[catch(Exception e){}][finally{ }]
3️⃣自定义异常
- 编写自定义异常类实际上是继承一个标准异常类,通常继承Exception类,如下所示:
class CustomException extends Exception { public CustomException(){} public CustomException(String message) { super(message); }}
实战演练
问题描述:
程序中需要验证用户输入的数据值必须是正值。如果用户提供的是负值,程序抛出异常。
编写一个自定义异常类NegativeValueException,负值异常。
// 自定义运行时异常类 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:
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关键字来声明的,断言的使用有两种格式:
assert expression ;//如果该表达式值为false,抛出AssertionError异常
assert expression : detailMessage ;
开启和关闭断言
- 编译带有断言的程序与一般程序相同。默认情况下,断言在运行时是关闭的,要开启断言功能,在运行程序时需要使用 –enableassertions或-ea选项,例如:
D:\study>java –ea AssertionDemo
- 在Eclipse中要开启断言,按下列步骤操作:
Run→ Run Configurations → 选择Arguments选项卡
→ Arguments文本框中输入–enableassertions 或-ea 然后执行程序何时使用断言
- 通常来说,断言用于检查一些关键的值,并且这些值对整个应用程序或局部功能的实现有较大影响,并且当断言失败,这些错误是不容易恢复的。
- 以下是一些使用断言的情况,它们可以使Java程序的可靠性更高。
-
- 检查控制流
在ifelse和switchcase结构中,可以在不应该发生的控制支流上加上assert false语句。如果这种情况发生了,断言就能够检查出来。
例如,假设x的值只能取1、2或3,可以编写下面的代码:
- 检查控制流
switch (x) {case 1: …;case 2: …;case 3: …;default: assert false : “x 值非法:" + x;}
-
- 检查前置条件(precondition)
在private
修饰的方法前检查输入参数是否有效。
例如,某方法可能要求输入的参数param
不能为null,就可以在方法的开头加上下面语句:
- 检查前置条件(precondition)
assert param != null:"参数不能为null";
-
- 检查后置条件(postcondition)
在方法计算之后检查结果是否有效。对于一些计算方法,运行完成后,某些值需要保证一定的性质。
例如,对计算绝对值的方法可以在方法的结束处使用下面语句进行检查:
- 检查后置条件(postcondition)
assert value >= 0:"结果应该大于等于0:" + value;
-
- 检查程序不变量
在程序的运行过程中这些变量的值是不变的,称为不变量。这些不变量可能是一个简单表达式,也可能是一个复杂表达式。对于一些关键的不变量,可以通过assert进行检查。
- 检查程序不变量
断言示例
问题描述
使用对象数组实现一个简单的栈类,在push()、pop()和topValue()方法中使用断言。
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,如果断言被启用 }
}
博主用心写,读者点关注,互动传真情,只是不迷路。