文章目录
1 异常
- 异常是程序在编译或运行时可能出现的问题
- 用户输入的数据格式不正确等…
- 数组越界、空指针异常、等…
1.1 异常分类
- 异常层次结构
- Error
- 系统级别问题、JVM退出等,代码无法控制
- 运行时异常又叫非检查型异常 (RuntimeException及其子类)
- RuntimeException异常,一定是你的代码有问题
- 举例:
package exception; public class Demo01 { public static void main(String[] args) { //数字转换异常:NumberFormatException System.out.println(Integer.valueOf("aa")); //数学操作异常:ArithmeticException System.out.println(1/0);//ArithmeticException //类型转换异常:ClassCastException Object o = 10; String c = (String)o; System.out.println(c); //数组索引越界异常:ArrayIndexOutOfBoundsException int[] a = {1,2,3,2,1}; System.out.println(a[5]); //空指针异常:NullPointerException String b = null; System.out.println(b.startsWith("a")); } }
- 编译时异常又叫检查型异常 (除RuntimeException之外所有的异常)
- 举例:
- 试图超越文件末尾继续读取数据
- 试图打开一个不存在的文件
- 举例:
2 处理异常
- 有两种方式:
- 抛出异常:throws 不对异常进行处理,如果异常最终抛给虚拟机将导致程序死亡
- 捕获异常:try-catch 捕获异常可以在发生异常时处理异常,避免程序终止
2.1 抛出异常
2.1.1 抛出异常步骤
- 1、首先明白要抛出什么类型的异常类 (EOFException)
- 2、然后创建这个异常类对象 (new EOFException()😉
- 3、 将对象抛出 (throw new EOFExcepton()😉
package core_Exception;
import java.io.EOFException;
public class Demo01 {
...
public void m() throws EOFException {
...
if(...){
throw new EOFException();
}
...
}
}
- throws: 用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者。
2.1.2 抛出自定义异常类
- Java自带的异常类都不能很清楚描述问题,需要自己创建异常类
- 自定义异常类的步骤
- 1、定义一个异常类继承Exception或它的子类
- 2、包含两个构造器 (无参构造器和包含父类构造器的有参构造器)
- 3、在可能出现异常的地方 throw new 自定义对象
- 举例:自定义了一个异常类 IlleagalNumberException
package exception; public class IlleagalNumberException extends Exception{ public IlleagalNumberException() { } public IlleagalNumberException(String message) { super(message); } }
2.2 捕获异常
2.2.1 try-catch
- 捕获异常语句:
try{
...
}catch(某种异常类 e){
e.printStackTrace();
}catch(另一种异常类 e){
e.printStackTrace();
}
- 如果try语句块中的代码发生异常,抛出的异常和catch中的某个匹配。
- 程序将跳过try语句块的剩余代码
- 执行对应catch块中的代码
- 如果try语句块没有异常,则跳过catch
- 如果try抛出的异常在catch中都没有,则方法立即退出,程序终止
- 举例:
package exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo03 {
public static void main(String[] args) {
m("2021-01-01 12:21:00");
}
public static void m(String date) {
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parse = simpleDateFormat.parse(date);
System.out.println(parse);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
/*
官方建议
try{
...
}catch(Exception e){
e.printStackTrace();
}
*/
2.2.2 catch中再次抛出异常
package core_Exception;
public class Demo02 {
public static void main(String[] args) throws IlleagalException {
//方式一
try {
System.out.println("");
} catch (ArrayIndexOutOfBoundsException e) {
throw new IlleagalException("hello" + e.getMessage());
}
//方式二 提倡
try {
System.out.println("");
} catch (ArrayIndexOutOfBoundsException e) {
IlleagalException iE = new IlleagalException("hello");
iE.initCause(e);
throw iE;
}
}
}
class IlleagalException extends Exception {
public IlleagalException() {
}
public IlleagalException(String message) {
super(message);
}
}
- 提倡方式二的这种包装技术,因为可以使用下面语句获取原始异常
Throwable cause = iE.getCause();
2.2.3 finally子句
- try-catch-finally
try{
...
}catch(IOException e){
...
}finally{
...
}
- 如果try语句块中的资源在抛出异常前就已经获得,如果发生异常,会导致资源没有关闭。
- finally 就是用来关闭资源的。finally不管try中是否发生异常,finally代码最后都会执行。
var fis = new FileInputStream(...); try{ ... }catch(IOException e){ e.printStackTrace(); }finally{ fis.close(); }
- 注意:finally 中不要放return continue thro break这些会改变控制流的语句
- 关闭资源更好的方式: try-with-resources
2.2.4 try-with-rsources语句
//1.7
//try块退出后,会自动运行rs.close(); 关闭资源
try( Resources rs = ...){
work with rs;
}
//1.9+
Resources rs = ...; //资源声明可以在try块外
try(rs){
work with rs;
}
- try-with-Resources 也可以有 catch子句、finally子句。这些子句在资源关闭后执行。
try(var in = new Scanner(new FileInputStream("/"), StandardCharsets.UTF_8)){
while(in.hasNext()){
System.out.println(in.next());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
System.out.println("");
}
3 处理异常的技巧
- throws 用于不知道怎样处理的异常
- try/catch 用于知道如何处理的异常
- 异常处理不能代替简单的测试,只在异常情况下使用异常
- 不过分地细化异常 多个try-catch 可以写成 try-catch-catch
- 不要压制异常
- 尽量抛出合适的子类,而不是只是RuntimeException异常
- 早抛出,晚捕获;不要羞于抛出异常,更高层的方法通常可以更好的通知用户发生了错误。