一、异常机制
异常的发生场景:用户输入不一定符合程序的要求、程序要打开某个文件但是这个文件却不存在或格式不对、读取数据库但数据库是空的、程序运行的时候内存或硬盘满了等Exception,为了让程序作出合理的处理而不至于程序崩溃,我们要处理异常
1.类型
1)检查型异常:代码逻辑没有错误,但可能会引起的异常,例如打开一个文件,但这个文件不存在的异常,Java编译器和虚拟机都会进行检查,编译器一般会给出错误提示,提醒你去处理这个可能发现的异常。
2)运行时异常(RuntimeException):是代码逻辑的的问题,是可以避免的,在编译时可以被忽略,程序运行会报的异常,是不检查异常,程序中可以选择捕获也可以不处理
3)错误Error:由JVM虚拟机生成并抛出,与代码编写无关。例如在JVM试图执行应用时,产生Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。
在java中,异常被当做对象来处理,java.lang.Throwable是所有异常的超类
2.处理异常的方式
1)抛出
int a=0; public void test(int a){ if (a==0){ throw new ArithmeticException(); } }
throw抛出: 表示主动抛出了一个异常实例,需要在调用方法时捕获处理。
public void test(int a,int b) throws ArithmeticException { System.out.println(a/b); }
throws抛出:在方法声明后面,可以写多个异常,告诉方法的调用者,方法中可能会出现这些异常,需要调用者调用方法时处理(捕获/继续抛出)
//throw、throws使用
public class Demo08 {
public static void main(String[] args) {
test1();
try {
test2(); //这里test()方法会抛出异常,所以这里也要处理一下这个异常
} catch (Exception e) {
e.printStackTrace();
}
test3();
}
//主动抛出运行时异常
public static void test1() {
int a =0;
if (a==0){
//主动抛出一个运行时异常
throw new RuntimeException();
}
}
//主动抛出运检查异常并用throws解决
public static void test2() throws Exception {
int a =0;
if (a==0){
//主动抛出一个检查异常,这里会报红提示你解决这个检查异常。
//throw new Exception();Alt+Enter,选择第一个Add exception to method signatrue
throw new Exception();
}
}
//主动抛出运检查异常并用trycatch解决
public static void test3(){
int a =0;
if (a==0){
//主动抛出一个检查异常,这里会报红提示你解决这个检查异常。
//throw new Exception();Alt+Enter,选择第二个Surround with try/catch
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
throw和throws区别:throw写在方法内部,throws写在方法第一行
异常抛出后需要进行捕获。
2)捕获
try {//监控的区域,这里面的代码运行发生的异常 }catch (要捕获的异常 异常名 ){//捕获异常 //如果捕获到了异常,就执行下面的语句 }finally {//可选,无论是否捕获到异常,都会执 }
finally用于处理一些善后工作,比如IO流、资源的关闭
自动生成快捷键:Ctrl+Alt+t,自动生成捕获异常语句,我们也可以在语句中加入退出程序语句等
try {
System.out.println(a/b);
} catch (Exception e) {
System.exit(0); //程序结束
e.printStackTrace(); //打印错误的栈信息,就是程序报的异常
} finally {
}
3.异常编写实例
1)创建两个变量,a=1,b=0,输出a/b
public class demo01 {
public static void main(String[] args) {
int a=1;
int b=0;
System.out.println(a/b); //报错java.lang.ArithmeticException: / by zero
}
}
程序运行结果为
2)可以看到报了一个异常java.lang.ArithmeticException,于是写代码捕获这个异常
public class demo01 {
public static void main(String[] args) {
int a=1;
int b=0;
//System.out.println(a/b); //报错java.lang.ArithmeticException: / by zero
//捕获这个异常
try {//监控的区域,这里面的代码运行发生的异常
System.out.println(a/b);
}catch (ArithmeticException e){//catch(要捕获的异常 异常名):捕获异常
//如果捕获到了异常,就执行下面的语句
System.out.println("除数不能为0");
}finally {//可选,无论是否捕获到异常,都会执行
System.out.println("finally");
}
}
}
程序运行结果为
异常消失。
如果将代码中的b改成合法数字1,运行结果为
3)捕获多个异常
可以写多条catch来捕获多个异常,异常的顺序必须是从小到大,否则会报错。
try {
System.out.println(a/b);
}catch (Error error){
System.out.println("Error");
}catch (Exception e){
System.out.println("Exception");
}catch (Throwable t){
System.out.println("Throwable");
}finally {
System.out.println("finally");
}
4)主动抛出异常
public static void main(String[] args) {
int a=1;
int b=0;
new demo01().test(a,b);
}
//主动抛出异常,一般在方法中使用,用于该方法无法处理这个异常时
public void test(int a,int b){
if (b==0){
throw new ArithmeticException();
}
}
运行结果为:
可以看到程序没有运行a/b,但是主动抛出了这个异常
5)使用较多的方式:输出异常信息
try {//监控的区域,这里面的代码运行发生的异常
System.out.println(a/b);
}catch (ArithmeticException e){//catch(要捕获的异常 异常名):捕获异常
// 如果捕获到了异常,就执行下面的语句
e.printStackTrace();//显示异常的堆栈信息
}finally {//可选,无论是否捕获到异常,都会执行
System.out.println("finally");
}
多重catch可以用 | 连接
catch (ArithmeticException |NumberFormatException|ArrayStoreException exception)
4.重载和重写中的异常使用(ArithmeticException < Exception)
1)重载:重载的方法之间的异常没有关系
2)重写:子类异常 < 父类异常,否则会报错
5.自定义异常(用到时再学)
用户自定义异常类,可以继承RuntimeException(运行时异常)或Exception(检查异常)
1)自定义异常继承运行时异常
public class MyException extends RuntimeException{
//定义一个无参构造器
public MyException(){
}
//定义一个有参构造器
public MyException(String msg){
//调用父类有参构造
super(msg);
}
}
编写Test类
public class Test {
public static void main(String[] args) {
sex("aaa");
}
public static void sex(String sex){
if(sex.equals("男")||sex.equals("女")){
System.out.println(sex);
}else{
throw new MyException("性别错误!");
}
}
}
可以看到运行Test类时,抛出了异常
2)自定义异常继承检查异常
public class MyException extends Exception{
//定义一个无参构造器
public MyException(){
}
//定义一个有参构造器
public MyException(String msg){
//调用父类有参构造
super(msg);
}
}
在Test里中必须要处理,这里使用try/catch处理
public class Test {
public static void main(String[] args) {
sex("aaa");
}
public static void sex(String sex){
if(sex.equals("男")||sex.equals("女")){
System.out.println(sex);
}else{
try {
throw new MyException("性别错误!");
} catch (MyException e) {
e.printStackTrace();
}
}
}