java异常处理
java异常处理
Jin异常的理解
异常指的是程序在执行过程中,出现非正常情况,不处理会导致 JVM 非正常停止,并非代码逻辑或语法出现问题,比如,客户端输入的数据格式错误,要读取的文件不存在,网络不畅通等等…
异常抛出的机制
java 把不同异常用不同的类表示,一旦出现异常,就会创建该异常类的对象,并且抛出
throw
程序员就可以捕获catch
这个异常对象
异常体系
Throwable 异常体系的根父类
常用方法
public void printStackTrace()
:打印异常的类型、异常的原因、异常出现的位置、在开发和调试阶段都得使用 printStackTracepublic void getMessage()
:获取发生异常的信息
Error 错误 与 Exception 异常
Error
:
- Java 虚拟机无法解决的严重问题。如:JVM 系统内部错误、资源耗尽等 严重情况。一般不编写针对性的代码进行处理
- 例如:StackOverflowError(栈内存溢出)和 OutOfMemoryError(堆内存溢出,简称 OOM)
Exception
:
- 其它因编程错误或偶然的外在因素导致的一般性问题,需要使用针对性的代码进行处理,使程序继续运行、否则一旦发生异常,程序也会挂掉
- 例如:数组越界,空指针异常….
编译时异常和运行时异常
编译时异常
(checked 异常、受检异常):
- 在编译代码阶段,编译器就给出明确警告,去处理异常代码,否则无法编译生成字节码文件
- 例如:FileNotFoundException,文件找不到异常
运行时异常
(runtime 异常、unchecked 异常、非受检异常):
- 在编译代码阶段,编译器不做异常检查,只有代码运行起来,发现异常,通常是代码编写不当引起的
- java.lang.RuntimeException: 类及它的子类都是运行时异常
- 例如:ArrayIndexOutOfBoundsException,数组越界、ClassCastException类型转换异常
异常的处理方式⭐
Java 采用的异常处理机制,是将异常处理的程序代码集中在一起,与正常的程序 代码分开,使得程序简洁、优雅,并易于维护
try-catch-finally
(捕获异常)
try-catch-finally 即、抓抛模型
过程1(抛):程序在执行的过程当中,一旦出现异常,就会在出现异常的代码处,生成对应异常类的对象,并将此对象抛出,一旦抛出,此程序就不执行其后的代码
过程2(抓):针对于过程1中抛出的异常对象,进行捕获处理,此捕获处理的过程,就称为抓、 一旦将异常进行了处理,代码就可以继续执行
注:如果一个异常回到 main()方法,并且 main()也不处理,则程序运行终止
捕获异常语法
try{
// 可能产生异常的代码
}
catch(异常类型 e){
// 产生形参类型的异常时的处理
}
catch(异常类型 e){
// 产生形参类型的异常时的处理
}
finally{
// 最后执行的代码,无论有无异常
}
catch 中常用异常处理的方式
public void printStackTrace()
:打印异常的类型、异常的原因、异常出现的位置、在开发和调试阶段都得使用 printStackTracepublic void getMessage()
:获取发生异常的信息
例如
@Test
public void TestException(){
try{
String str = "hello";
str = null;
}catch(NullPointerException e){
// 空指针异常 NullPointerException
e.printStackTrace();
}catch(ClassCastException e){
// 类型转换异常 ClassCastException
e.printStackTrace();
}finally{
System.out.printIn("finally!");
}
//此处的代码,在异常被处理了以后,是可以正常执行的
System.out.println("hello")
}
thorws
(声明抛出异常)
在编写方法时,可能有些代码会出现异常,在方法体中不适合处理,即可声明抛出异常,让调用方法者负责处理异常
声明抛出异常格式
修饰符 返回值类型 方法名(参数) throws 异常类名1, 异常类名2,...{}
// 例如
public void method throws FileNotFoundException,IOException{
// 读文件的操作可能产生 FileNotFoundException
// 或 IOException 类型的异常
FileInputStream fis = new FileInputStream(file);
}
@Test
public void TestThrows(){
// 调用有声明抛出异常的方法
// 处理
try{
method();
} catch(FileNotFoundException e){
e.getMessage();
} catch(IOException e){
e.printStackTrace();
}
}
总结体会:
如果是运行时异常(RuntimeException)没有 try 和 catch 捕获,Java 自己也能捕获,并且编译通过 ( 但运行时 会发生异常使得程序运行终止 ),所以可以不作处理
如果抛出的异常是 IOException 等类型的非运行时异常,则必须捕获处理
开发中,方法 a 中依次调用了方法 b,c,d 等方法,方法 b,c,d 之间是递进关系, 如果方法 b,c,d 中有异常,通常使用 throws,而方法 a 中选择使用 try-catch-finally
自定义与手动抛异常
手动抛出异常 throw
格式:throw new 异常类名(参数)
throw 语句抛出的异常对象,和 JVM 自动创建和抛出的异常对象一样
- 编译时异常类型的对象,同样需要使用 throws 或者 try…catch 处理,否则编译 不通过
- 运行时异常类型的对象,编译器不提示
- 可以抛出的异常必须是 Throwable 或其子类的实例
自定义异常
自定义异常用来:需要根据自己业务的异常情况 来定义异常类。例如年龄负数问题,考试成绩负数问题等等
使用步骤:
- 继承一个异常类型:Exception(编译时异常)或 RuntimeException(运行时异常)
- 建议提供至少两个构造器,一个是无参构造,一个是 (String message) 构造器
- 提供 serialVersionUID
例如
class MyException extends Exception{
static final long serialVersionUID = 23423423435L;
private int idNumber;
public MyException(){}
public MyException(String message, int id){
super(message);
this.idNumber = id;
}
public int getId(){
return idNumber;
}
}
class TestMyException {
public void regist(int num) throws MyException{
if(num<0){
throw new MyException("人数为负数不合理",num);
} else System.out.println("登记人数" + num);
}
public static void main(String args[]) {
TestMyException t = new TestMyException();
try{
t.regist(100);
}catch(MyException e){
e.getMessage();
}
}
}
注意:
- 自定义的异常只能 throw 抛出
- 自定义异常最重要的是异常类的名字和 message 属性。当异常出现时,可以根据名字 判断异常类型
- 自定义异常对象只能手动抛出。抛出后由 try..catch 处理,也可以甩锅 throws 给调用 者处理
总结:类比上游排污,下游治污
参考资料