1.JVM的默认处理方案
如果程序出现了问题,我们没有做任何处理,最终JVM会做默认的处理
- 把异常的名称,异常原因及异常出现的位置等信息输出在控制台
- 程序停止执行
2. 异常处理类的体系结构
程序出现异常是一个正常现象,就像人会生病一样。
(1)Java类中异常类Throwable[类]顶级异常类。
(2)Throwable[类]有两个子类:1.Error(错误) 2.Exception(异常)
(3)Exception又被分为运行时异常与非运行时异常(编译时异常)。
①运行时异常--非检查性异常 ,在代码编写使,可以忽略捕获操作(比如:ArrayIndexOutOfBoundsException),这种异常是在代码编写或者使用过程中通过规范可以避免发生的。
②非运行时异常--检查性异常,必须在编写代码时,使用try catch捕获(比如:IOException异常)。
3.Error与Exception的区别
(1)Error是java程序运行中不可预料的异常情况,这种异常发生以后,会直接导致JVM不可处理或者不可恢复的情况。所以这种异常不可能抓取到,比如OutOfMemoryError、NoClassDefFoundError等。【癌症】
(2)Exception是java程序运行中可预料的异常情况,咱们可以获取到这种异常,并且对这种异常进行业务外的处理。【感冒】
4. java异常处理的原理
如果程序出现了问题,需要我们自己处理,有两只方式:
- try………catch……..
- throws
4.1 异常可以自己处理—try…catch…
(1)try-catch代码块格式
try{
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}
(2)执行流程:
程序从try里面的代码开始执行,出现异常,会自动生成一个异常类对象,该异常对象被提交给java运行时系统,当java运行时系统接收到异常对象时,会到catch中去找匹配的异常类,找到后进行异常的处理,执行完毕之后,程序还可以继续往下执行。
通过try-catch代码块处理异常,将可能出现异常的java代码使用try{异常可能发生的代码}catch(要抓捕的异常){异常处理方式}块包裹,如果出现异常try{}就会捕获异常,终止代码的运行,将捕获的异常交给catch(){}去处理异常。
(3)try{}--捕获可能发生的异常;
catch(要抓捕的异常){异常处理方式}---抓获处理异常;
catch后面的“()”中一般要定义为具体异常类型的。具体异常类型不明确的时候可以使用Exception/Throwable。
catch的{}--- 具体异常的处理过程。往往都是打印堆栈到控制台,查看具体情况,修改程序去避免。-----变量.printStackTrace();
(4)一个try{}后面可以跟随多个catch(要抓捕的异常){异常处理方式},多个catch时要抓捕的异常类型需要按照有小到大的顺序排列。
(5)【finally{ }】---出现在catch的“{ }”后面,可以写也可以不写。
finally{ }表示有无异常都要执行的动作,当有一定需要执行的代码时可以写进finally中。
例:
public class ExceptionDemo1 {
public static void method(){
//异常处理
try{
int[] arr={1,2,3};
System.out.println(arr[2]);
//没报错,但是运行会报错,因为这里数组存储空间最大为2
System.out.println(arr[3]);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("我真棒");//此处继续被执行,如果没有try..catch,此处就没有被执行
}
}
public class Main {
public static void main(String[] args) {
ExceptionDemo1 ec=new ExceptionDemo1();
ec.method();
}
}
控制台:
3
java.lang.ArrayIndexOutOfBoundsException: 3
我真棒
at lianxi20211106.ExceptionDemo1.method(ExceptionDemo1.java:10)
at lianxi20211106.Main.main(Main.java:6)
问题:try catch中return在finally之前还是之后执行?
public class TestClass {
public static String method(){
String he="你好";
try{
he="hello";
return "swr";
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.println("无论有没有异常都要执行");
he="sds";
}
return he;
}
public static void main(String args[]){
String val=TestClass.method();
System.out.println("返回值=="+val);
}
}
输出:
无论有没有异常都要执行
返回值==swr
结论:finally语句在return语句执行之后return返回之前执行的。
4.2 异常不自己处理---throws
虽然我们通过try…catch..,可以对异常进行处理,但并不是所有的情况我们都有权限进行异常的处理,有些时候可能出现的异常是我们处理不了的,这个时候咋办呢?针对此情况,java提供了throws处理方案。
(1)格式:throws 异常类名;
注意:这个格式是跟在方法的括号后面的
- 编译时异常必须要进行处理,可以try…catch…或者throws,如果采用throws方案,将来谁调用谁处理;
- 运行时异常可以不处理,出现问题后,需要我们回来修改代码。
(2)如果出现异常,java会根据问题所描述的异常类,创建一个对象(实例)具体异常对象,然后将该对象抛给上一级【谁调用谁就是上一级】。
(3)具体步骤:
method具体出异常处 --》main主方法--》jvm虚拟机--》将异常出现的位置和原因打印在控制台上。
throws--声明方法抛出异常给上一级【谁调用谁就是上一级】
例:
public class TestClass {
public int getInt()throws Exception{
int a=10;
int b=0;
int c=a/b;
return c;
}
}
public class Main {
public static void main(String[] args) throws Exception{
TestClass tc=new TestClass();
int res=tc.getInt();
System.out.println("res=="+res);
}
}
控制台:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.wangxing.test2.TestClass.getInt(TestClass.java:8)
at com.wangxing.test2.Main.main(Main.java:7)
5. 自定义异常和throw
简单的自定义异常--编写一个新类,继承Throwable/Exception/RumtimeException,在构造中访问父类的构造方法。
(1)格式:
public class 异常类名 extends Exception{
无参构造
有参构造
}
(2)范例1:数组大小不能为负值的错误例子
public class MyException extends Exception{
public MyException(){
//无参
}
public MyException(String message){
//访问父类有参数时,要super(参数)写出
super(message);
}
}
public class MyArray {
//数组大小不能为负值的错误例子
private int size=0;
public MyArray(int size) throws MyException{
if(size>0){
this.size=size;
}else{
//手动引发一个异常
throw new MyException("数组大小不能为负值!");
}
}
public int[] createIntArray(){
int arr[]=new int[this.size];//创建数组
return arr;
}
}
测试类:
public class ArrayMain {
public static void main(String[] args) throws MyException{
MyArray ma=new MyArray(-5);
int arr[]=ma.createIntArray();
}
}
//或者
/* public static void main(String[] args) throws MyException{
try{
MyArray ma=new MyArray(-5);
int arr[]=ma.createIntArray();
}catch(MyException e){
e.printStackTrace();
}
}
}*/
控制台:
Exception in thread "main" com.weiwei.test3.MyException: 数组大小不能为负值!
at com.weiwei.test3.MyArray.<init>(MyArray.java:11)
at com.weiwei.test3.ArrayMain.main(ArrayMain.java:6)
(3)范例2:分数在0—100之间
public class MyException extends Exception{
public MyException(){
}
public MyException(String message){
super(message);
}
}
public class Teacher {
//检查学生分数的例子
public void checkScore(int score) throws MyException{
if(score<0||score>100){
//当throw出现时,方法括号后就要加throws,不然报错
throw new MyException("你给的分数有误,分数应在0-100之间");
}else{
System.out.println("分数正常");
}
}
}
测试类1:
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws MyException{
System.out.println("请输入分数");
//创建输入
Scanner sc=new Scanner(System.in);
int score=sc.nextInt();
Teacher t=new Teacher();
t.checkScore(score);
}
}
测试类2:
import java.util.Scanner;
public class Main2 {
public static void main(String[] args){
System.out.println("请输入分数");
//创建输入
Scanner sc=new Scanner(System.in);
int score=sc.nextInt();
Teacher t=new Teacher();
try{
t.checkScore(score);
}catch(MyException e){
e.printStackTrace();
}
}
}
总结一下:
(1)如果有异常就try{}catch(){},如果不想try{}catch(){}那么就声明方法throws异常。
(2)没有特殊要求的时候我们都是打印堆栈异常,查看程序的具体异常和位置,方便修改。
(3)我们轻易不会自己定义异常,因为java提供的异常类型已经足够使用。
6. throws和throw的区别
throws | throw |
用在方法声明后面,跟的是异常类名 | 用在方法体内,跟的是异常对象名 |
表示抛出异常,由该方法的调用这来处理 | 表示抛出异常,由方法体内的语句处理 |
表示出现异常的一种可能性,并不一定会发生这些异常 | 执行throw一定抛出了某种异常 |
7. java中的常见运行时异常
- NullPointerException - 空指针引用异常
- ClassCastException - 类型强制转换异常。
- IllegalArgumentException - 传递非法参数异常。
- ArithmeticException - 算术运算异常
- ArrayStoreException - 向数组中存放与声明类型不兼容对象异常
- IndexOutOfBoundsException - 下标越界异常
- NegativeArraySizeException - 创建一个大小为负数的数组错误异常
- NumberFormatException - 数字格式异常
- SecurityException - 安全异常
- UnsupportedOperationException - 不支持的操作异常