一、异常:
指的是程序运行过程中,因为用户的误操作、代码的BUG、
等等一系列原因,引起的程序崩溃的现象,被称为异常
崩溃:程序无法正常继续执行,在这行代码抛错,抛错操作系统解决不了,也抛了出去最终软 件退出(因为解决不了问题,无法正常运行)
例:
package com.openlab.day14;
import java.util.Scanner;
public class TestException01 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入第一个数:");
int num1 = input.nextInt();
System.out.print("请输入第二个数:");
int num2 = input.nextInt();
int res = divide(num1, num2);
System.out.println(String.format("%s ÷ %s = %s", num1, num2, res));
input.close();
}
private static int divide(int num1, int num2) {
int result = num1 / num2;
return result;
}
}
二、异常处理:
解决掉异常的现象,让程序继续运行(不要崩溃退出)下去。
程序容错能力提升!!!!程序就会越稳定!!!
java进行异常处理,有两种解决方案:
|-- 抓捕异常【重点掌握】
|-- 抛出异常
异常分类:
1). 编译型异常:
在源码编译阶段,直接抛出异常,这种异常必须要处理。
不处理,则无法正常运行代码。
例:
异常原因:路径可能不存在
2). 运行时异常:
在代码运行时,有可能出现的异常,被称为运行时异常
一、异常 例就是运行时异常(除零异常)
1. 抓捕异常:
针对于可能出现异常的代码,进行抓捕
try {
// 可能发生异常的代码
} catch (Exception e) {
// 如果出现了一次,代码会立刻进入catch中
// 在这儿解决抓捕到的异常
} finally {
// 必须要执行的代码
}
try {
} catch(XxxException e) {
// 异常处理
} catch(XxxxException e) {
// 异常处理
} catch(Exception e) {
// 异常处理
} finally {
// 必须要执行的代码
}
如果使用抓捕异常,通过这种处理,程序即便是遇到了,也不崩溃!!!
package com.openlab.day14;
import java.io.File;
import java.util.Scanner;
public class TestException01 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入第一个数:");
int num1 = input.nextInt();
System.out.print("请输入第二个数:");
int num2 = input.nextInt();
int res = divide(num1, num2);
System.out.println(String.format("%s ÷ %s = %s", num1, num2, res));
input.close();
}
private static int divide(int num1, int num2) {
int result = 0;//局部变量必须初始化,无默认值。成员变量有默认值
try {
// 如果出现了错误,则立刻进入catch块
result = num1 / num2;
}catch(Exception e){
//只有出现了异常,catch块中的代码才会执行
System.out.println("出现了异常");
}
return result;
}
}
1)try catch运行流程:
出现异常的流程:try中出现异常代码之后的代码都不执行,立即跳入catch块,执行完之后再执行后继代码
不出现异常的流程:只有catch块中的代码不执行。try执行完之后,跳过catch块,直接执行后继代码
package com.openlab.day14;
import java.io.File;
import java.util.Scanner;
public class TestException2 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入第一个数:");
int num1 = input.nextInt();
System.out.print("请输入第二个数:");
int num2 = input.nextInt();
int res = divide(num1, num2);
System.out.println(String.format("%s ÷ %s = %s", num1, num2, res));
input.close();
}
private static int divide(int num1, int num2) {
int result = 0;
System.out.println(1);
try {
// 如果出现了错误,则立刻进入catch块
System.out.println(2);
result = num1 / num2;
System.out.println(3);
}catch(Exception e){
System.out.println(4);
//只有出现了异常,catch块中的代码才会执行
System.out.println("出现了异常");
}
System.out.println(5);
return result;
}
}
不出现异常:
出现异常:
2)java中异常的继承关系:
Throwable 异常的顶级类
|-- Error 致命性的错误
|-- Exception 常见的异常的父类
|-- RuntimeException 运行时异常,只有运行时,才有可能出现异常
其他的Exception的子类都是编译型异常,必须处理
3)多个异常的处理方案:
最后其他异常可以用Exception e 来抓捕,运用了多态原理。所有异常都是Exception的子类,直接或者间接继承了Exception,根据多态原理,根据父类引用代指所有子类
try {
} catch(XxxException e) {
// 异常处理
} catch(XxxxException e) {
// 异常处理
} catch(Exception e) {
// 异常处理
}
private static int divide(int num1, int num2, Scanner input) {
int result = 0;
try {
result = num1 / num2;
input.nextInt();
}catch(ArithmeticException e){
e.printStackTrace();
System.out.println("除数不能为零!!!");
}catch(InputMismatchException e){
e.printStackTrace();
System.out.println("请输入整数!!!");
}catch(Exception e){//
e.printStackTrace();
System.out.println("其他异常");
}
return result;
}
4). finally关键字
若都在try块中,关键代码在可能触发异常的代码之后,那么一旦触发异常,关键代码将不能被执行。因为异常,程序会直接跳到catch块中。所以java设计finally关键字。
try {
// 可能存在异常的代码
} catch(XxxException e) {
// 异常处理代码
} [finally {
}] // [ ] 表示可以有,可以没有
1). 把什么样的代码写在finally中?
回收垃圾
关闭IO流
关闭数据库连接
……
核心必须要执行代码
2)finally块
上断代码的关注点不是catch块,只是想执行try后执行finally
在开发过程中,希望有的代码必须执行,但是不能保证一定执行,可能有异常等跳过代码,所以有这样一种结构。利用finally关键字的作用。
try {
} finally {
// 将必须要执行的代码写在finally中!!!
}
3). 注意:在开发过程中请注意,return关键字和finally关键字同时出现的情况,认真分析
仔细考虑
finally 是在jvm层次执行的,不是在原码层次执行的。代码遇到return,,尤其是函数中,遇到return就会立即返回到调用的位置,在返回前,发现后面有finally,会将返回的状态保存在那里,之后开始执行finally,执行完返回。
package com.openlab.day14;
import java.io.IOException;
public class TestException4 {
public static void main(String[] args) throws IOException {
int res = say();
System.out.println(res);
}
public static int say() {
try {
int a = 10;
return a;
} catch (Exception e) {
} finally {
System.out.println("这儿还会执行吗?");
}
return 0;
}
}
面试题:下面代码的运行结果?
package com.openlab.day14;
import java.io.IOException;
public class TestException5 {
public static void main(String[] args) throws IOException {
int res = say();
System.out.println(res);
}
public static int say() {
int a = 10;
int b = 20;
try {
b += a++;// b = 30 a = 11
return b;
} catch (Exception e) {
} finally {
a += 10;// a = 21
b += 20;// b = 50
}
return a;
}
}
finally在return之后执行,但是return的趋势已经形成,一旦return的趋势形成,会将要返回的值临时存储下来,等待后面执行finally之后再将它返回。虽然b = 50,a = 21,但是不影响将30return
2. 抛出异常:
将异常交给调用者处理
编程型异常,如果我们不想处理,可以直接抛给调用者,由调用者完成处理,调用者也不处理,会继续上抛,直到抛给main函数,main函数抛给jvm,jvm尝试处理,发现解决不了,就挂了
由此看出,抛出异常并不是永久解决问题的方案,我们抛出异常原因:
异常不一定会触发,尤其是编译型异常出现,懒得处理(如刚刚的文件例子,有路径异常就出现不了,出现不了就没有问题)
例:
package com.openlab.day14;
import java.io.File;
import java.io.IOException;
public class TestException4 {
public static void main(String[] args) throws IOException {
String path = "c:/a.txt";
creatFile02(path);
}
private static void creatFile02(String path) throws IOException {
File file = new File(path);
file.createNewFile();
}
private static void creatFile(String path) {
try {
File file = new File(path);
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
System.out.println("创建失败");
}
}
}
三、自定义异常类:
接触到的都是属于java官方提供的异常类,
有时候自己设计异常类
自定义异常类:定义一个普通的类,让该类成为成为Exception的子类或Exception类的孙子类
异常抛出:
可以通过创建异常(系统或者自定义),来给调用者一个确切的错误信息
调用者就可以通过抛出的信息做成对应的判断。
在自定义异常时,若继承Exception,做的是编译型异常,在编译阶段必须得处理,不建议使用编译型异常。建议使用运行时异常,简化写法
编译型异常例:
package com.openlab.day14;
public class MyException extends Exception{
private static final long serialVersionUID = -5723348118187732441L;
public MyException() {
super();
}
public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
public MyException(String message) {
super(message);
}
public MyException(Throwable cause) {
super(cause);
}
}
package com.openlab.day14;
public class Test02 {
public static void main(String[] args) {
}
//登录功能
//需要写 throws MyException 。抛出的是编译型异常,往出去抛还得在当前声明,所以不建议使用
public void login(String username, String password) throws MyException {
if(username.equals("admin") && password.equals("123456")) {
System.out.println("登录成功");
}else {
//throws是放在方法上的,用来抛出不处理的异常,处理异常
//throw是人为在底层向调用者抛出异常对象的,制造异常
throw new MyException("对不起,用户名或者密码错误,请重新登录");
}
}
}
throws和throw区别:
throws是放在方法上的,用来抛出不处理的异常,处理异常
throw是人为在底层向调用者抛出异常对象的,制造异常
运行时异常例:
package com.openlab.day14;
/*
* 在自定义异常时,建议使用运行时异常
*/
public class MyException extends RuntimeException{
private static final long serialVersionUID = -5723348118187732441L;
public MyException() {
super();
}
public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
public MyException(String message) {
super(message);
}
public MyException(Throwable cause) {
super(cause);
}
}
package com.openlab.day14;
public class Test02 {
public static void main(String[] args) {
try {
new Test02().login("admin", "admin");
}catch(MyException e) {
//e.printStackTrace();
System.out.println(e.getMessage());
}
}
//登录功能
//编译型需要写 throws MyException 。抛出的是编译型异常,往出去抛还得在当前声明,所以不建议使用
public void login(String username, String password) {
if(username.equals("admin") && password.equals("123456")) {
System.out.println("登录成功");
}else {
//throws是放在方法上的,用来抛出不处理的异常,处理异常
//throw是人为在底层向调用者抛出异常对象的,制造异常
//自定义异常,可以向调用者传递需要的信息
throw new MyException("对不起,用户名或者密码错误,请重新登录");
}
}
}