一、 什么是异常
生活中:在事情发展过程中出现意外情况
程序中:在代码编译或运行过程中,程序出现错误,导致程序不能正常执行。
二、为什么要处理异常
程序一旦发生异常,会导致程序中途退出(程序崩溃),所以需要进行处理。处理之后,让程序正常执行。
三、 异常分类
Throwable中的方法:
- printStackTrace():打印异常的堆栈信息,追根溯源。
- getMessage():获取异常的详细信息。
Error:表示严重的问题,合理的应用程序不应该试图去捕获,通过代码无法处理。 Error异常一般是jvm发生的错误
Exception:异常
编译时异常:可以预测的,检查异常,需要进行强制的异常处理或者抛出。
运行时异常:在运行过程中发生的异常,不作强制处理要求。非检查异常。
InputMismatchException(输入不匹配异常)
ArithmeticException(数学运算异常)
ArrayIndexOutOfBoundsException(数组下标越界异常)
NullPointerException(空指针异常)
NumberFormatException(数据转换格式错误)
四、 如何进行异常处理
关键字:try:监视、catch:捕获、finally:最终、throw:抛出、throws:声明
如何做异常处理:
1.在代码上加try..catch
2.在代码所在的方法上添加异常抛出声明
4.1 捕获异常
结构1: try..catch
应用场景: 可能发生异常的代码
try{
//可能发生异常的代码
}
catch(异常类型 对象){
//处理异常
}
结构2: try..catch..finally
finally应用场景:存在必须执行的代码(释放资源的代码)
finally块中的代码:无论代码是否出现异常,一定会执行,并且会在return之前运行。
public class Test2 {
public static void main(String[] args) {
try{
int num1 = 10;
int num2 = 0;
System.out.println(num1/num2);
}
catch (Exception ex){
System.out.println("出错了");
return; //在方法中,遇到return,代码执行到此结束,不再往下走
}finally {
// 代码1
System.out.println("无论上面的代码是否出错,finally中的代码一定会执行...");
}
// 代码2
System.out.println("=========================");
}
}
结构3: 多重catch
应用场景:如果需要精确的把控各种异常的处理的话。
注意:先捕获细的异常,再捕获粗的异常
多分枝捕获,按从上到下的次序依次匹配,所以细粒度的异常要发放到上面,粗粒度的异常要放到下边
try{
...
}
catch(异常1){
...
}catch(异常2){
...
}catch(异常3){
...
}
public static void main(String[] args) {
try {
Scanner sc = new Scanner(System.in);
System.out.println("请输入第一个数字:");
int num1 = sc.nextInt();
System.out.println("请输入第二个数字:");
int num2 = sc.nextInt();
// 进行两个数字的除法运算
int res = num1 / num2;
// 输出结果
System.out.println("结果:" + res);
String str = null;
System.out.println(str.length());
}catch (ArithmeticException ex){
// 细粒度异常
System.out.println("发生了数学运算异常:"+ex.getMessage());
}catch (InputMismatchException ex){
// 细粒度异常
System.out.println("发生了输入不匹配异常");
}catch (Exception ex){
// 粗粒度异常
System.out.println("出错了:"+ex.getMessage());
}
//多分枝捕获,按从上到下的次序依次匹配
//所以细粒度的异常要发放到上面,粗粒度的异常要放到下边
System.out.println("=========================");}
结构4: try..finally
发生异常时finally的代码会被执行,但是因为没有catch处理异常,所以程序会崩溃
public class Test3 {
public static void main(String[] args) {
try{
System.out.println("这是try代码");
System.out.println(1/0);
}finally {
System.out.println("这是finally");
}
System.out.println("=======================");
}
}
4.1 手动抛出异常
用于个性化(特定的业务需求)的异常处理
比如:学生的性别,年龄输入错误
方法1:throw
//在方法中使用:
if(条件)
throw new Exception("错误消息");
方法2:throws
在方法签名后面使用,声明方法可能抛出的异常,一般会配合检查异常(编译时异常)使用
public class Student {
// 属性
private String name;
private int age;
// getter,setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
// 设置年龄
// throws Exception:方法的异常抛出声明
public void setAge(int age) throws Exception {
if(age<0 || age>100){
// 手动抛出错误,中断程序执行
throw new Exception("年龄设置错误");
}
this.age = age;
}
}
public class Test {
public static void main(String[] args) {
try {
Student student = new Student();
student.setName("张三");
student.setAge(-18);
System.out.println("姓名:"+student.getName());
System.out.println("年龄:"+student.getAge());
}catch (Exception ex){
System.out.println("设置对象出错:"+ex.getMessage());
}
}
}
public class Test2 {
// throws: 异常抛出声明,表示当前这个方法可能会出错,以此提示方法的调用者要进行异常处理
//测试方法
public static void aaa() throws Exception{
}
// main方法是jvm运行程序的入口,有了错误,有jvm直接处理(中断程序执行)
public static void main(String[] args) throws Exception {
System.out.println("程序开始执行");
// main方法中如何调用aaa方法
// 1.让aaa也变成静态的,可以直接调用
// 2.当aaa是实例方法的时候,如何调用
// 先创建实例方法对应类的对象,通过对象调用实例方法
//Test2 t = new Test2();
//t.aaa();
// 实例方法只能通过对象调用
// 如何做异常处理:
// 1.在代码上加try..catch
// 2.在代码所在的方法上也添加异常抛出声明
// try {
// aaa();
// }catch (Exception ex){
//
// }
aaa();
}
}
五、自定义异常
java中给我们提供的异常很多,但是有些满足不了我们的需求,所以此时需要我们自己去定义异常。
// 自定义异常
public class SexException extends Exception {
// 自定义异常类的构造
public SexException(String errorMsg){
// 调用父类异常的有参构造,让父类维护异常信息
super(errorMsg);
}
}
public class AgeException extends Exception{
// 有参构造
public AgeException(String errorMsg){
// 调用父类构造,让父类维护异常信息
super(errorMsg);
}
}
public class Student {
// 属性
private String name;
private String sex; // 加校验
private int age; // 加校验
// getter,setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) throws SexException {
if(sex.equals("男") || sex.equals("女")) {
this.sex = sex;
}else{
throw new SexException("性别设置错误");
}
}
public int getAge() {
return age;
}
public void setAge(int age) throws AgeException {
if(age>=0 && age<=100) {
this.age = age;
}else{
throw new AgeException("年龄设置错误");
}
}
// toString()
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
public class Test {
public static void main(String[] args) {
try {
Student student = new Student();
student.setName("张三");
student.setSex("x"); //爆出性别异常
student.setAge(180); // 爆出年龄异常
System.out.println(student);
}catch (SexException ex){
System.out.println("设置学生出错:"+ex.getMessage());
}catch (AgeException ex){
System.out.println("设置学生出错:"+ex.getMessage());
}catch (Exception ex){
System.out.println("出错了:"+ex.getMessage());
}
// Student student = new Student();
// student.setName("张三");
//
//
try {
// student.setSex("x");//爆出性别异常
// } catch (SexException e) {
// e.printStackTrace();
// }
//
// try {
// student.setAge(180); // 爆出年龄异常
// } catch (AgeException e) {
// e.printStackTrace();
// }
//
// System.out.println(student);
}
}
六、 debug调式测试
java中如何调试代码
1) 在代码的指定位置设置断点
2) 用debug方式启动程序,当程序执行到断点处时,会自动停下,此时需要通过手动控制程序的执行
3) 手动控制程序执行的主要方式:
stepover(步过) : 遇到单行代码,逐行执行,遇到方法不进入
stepinto(步入): 遇到单行代码,逐行执行,遇到方法会进入方法内部执行