我们写程序,关注的是发生异常后如何处理
所有的异常和错误的父类是Throwble>object
有两个子类:一个是Error(了解) 一个是Exception
Exception中分为两派,一个是检查异常(Runtimelei),一个是运行时异常
检查异常在我们的代码编写阶段必须处理,否则编译不通过
运行时异常不是必须处理
基本语法 重点
try...catch(异常类型 e)...
try括住可能出异常的代码块,catch 捕获异常 使用异常处理可以保证我们的代码正常执行
public class App {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 10;
int b = 0;
/*
* if (b == 0) { System.out.println("除数不能为0"); } else { int v = a / b;
* System.out.println(v); }
*/
try {
int v = a / b;
System.out.println(v);
} catch (ArithmeticException e) {
// 打印异常的跟踪信息
e.printStackTrace();
// 异常信息
// System.out.println(e.getMessage());
System.out.println("除数不能为0");
}
System.out.println("运算正常");
}
}
try-catch-finally 重点
不管是否有异常,finally里的代码都会执行(除非使用System.exit(),非0表示非正常退出,1表示某种情况,2表示某种情况 )
面试题:finally唯一不执行的情况是什么?
finally不执行的情况就是在finally之前退出虚拟机
System.exit() 非0表示非正常退出,1表示某种情况,2表示某种情况
目前来说,没有区别,都是退出
面试题:try-catch-finally中都有return的情况怎么执行?(或者问try-catch-finally中存在return语句,是否还执行finally?如果执行,请说出执行顺序。) 1. finally中不要对返回值做操作
如果做了操作,也依然按照try中的返回值
2.
在catch块中也不推荐对返回值的做操作
但是在报错的情况下,如果在try返回值之前报错,那么就是将遵照最终的返回值,也就是方法最后的返回值
总结:
try catch finally 中如果都存在return,那么将使用最终finally中的return作为返回值
不要在finally和catch中加return,切记
try-catch-finally结构中try语句是必须的,catch和finally语句均可选,但两者至少出现一个
public class App2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Student stu = new Student(10, "zhangsan", 20);
stu.setName(null);
// 进行io操作、数据库的操作,一般在finally里做一些特定操作,比如关闭连接等等
try {
if(stu.getName().equals("zhangsan")) {
System.out.println("欢迎zhangsan");
}
// 退出程序
// System.exit(-1);
return;
}catch(NullPointerException e) {
// NPE
System.out.println("空指针异常");
return;
} finally {
System.out.println("不管怎么执行,都会回到我的怀抱");
}
// System.out.println("hahaha");
}
}
常见异常
Exception的子类:受检异常(必须处理的异常)、运行时异常
Exception 异常层次结构的父类 ArithmeticException算术错误情形,如以零作除数 ArrayIndexOutOfBoundsException数组下标越界 NullPointerException尝试访问 null 对象成员 ClassNotFoundException不能加载所需的类 IllegalArgumentException方法接收到非法参数 ClassCastException对象强制类型转换出错 NumberFormatException数字格式转换异常,如把"abc"转换成数字
多重catch块处理
先子类后父类
异常的匹配的顺序从上到下
一般建议增加catch(Exception e) {}
public class App3 {
public static void main(String[] args) {
try {
int a = 10;
int b = 5;
int v = a / b;
String name = "zhagnsan";
if (name.equals("zhangsan")) {
System.out.println("zhangsan");
} else {
System.out.println("gousheng");
}
Integer.parseInt("abc");
} catch (ArithmeticException e) {
System.out.println("除数不能为0");
} catch(NullPointerException e) {
System.out.println("空指针异常");
} catch(Exception e) {
System.out.println("未知异常,请联系管理员");
}
}
}
声明异常 重点
throws
通过在方法后面声明异常进行抛出
方法后可以声明多个异常,多个异常之前用逗号分隔
main方法后也可以使用throws,抛出的异常交给JVM处理
throws Exception 表示当前方法有可能会出现一个??异常,通知调用者去处理
或者继续抛出
throw | throws |
---|---|
生成并抛出异常 | 声明方法内跑出来异常 |
位于方法的内部 | 必须跟在方法参数列表后面,不能单独使用 |
抛出一个异常对象,且只能是一个 | 声明抛出异常类型,可以跟多个异常 |
public class App5 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// try {
// int v = div(10, 4);
// System.out.println(v);
//
// sub(null);
// } catch (ArithmeticException e) {
// System.out.println("算数异常");
// } catch (Exception e) {
//
// }
sub(null);
}
public static int div(int a, int b) throws ArithmeticException {
int v = a / b;
return v;
}
public static void sub(String str) throws Exception {
String substring = str.substring(2);
System.out.println(substring);
}
public static void oper(String str) throws ArithmeticException, IndexOutOfBoundsException {
String substring = str.substring(2);
System.out.println(substring);
}
}
抛出异常 重点
throw
通过创建异常对象进行抛出,一次只能抛出一个异常
一般可以抛出运行时异常
借助throw,可以中断业务的执行,并不一定抛出的都是官方定义的具体异常
public class App6 {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
login("admin", "123456");
} catch (RuntimeException e) {
// geMessage 获取异常信息
System.out.println(e.getMessage());
}
}
/**
* 登录方法
*
* @param username
* @param password
*/
public static void login(String username, String password) {
if (!username.equals("admin")) {
// 后续的逻辑终止执行, 参数表示具体的异常信息
throw new RuntimeException("用户名错误");
}
if (!password.equals("123456")) {
throw new RuntimeException("密码错误");
}
System.out.println("欢迎登录");
}
}
自定义异常
自定义类继承throwable/Exception/RuntimeException
一般在自定义异常类里,根据业务需要,增加一个额外的属性
jdk中没有给我们提供一些具体的异常类,比如年龄,性别异常
所以我们需要按自己要求来自定义异常
1.继承异常父类
2.调用父类的构造方法,重新给message属性赋值,这个属性用于打印提示信息的
3直接抛出我们定义好的异常对象即可
异常处理原则
异常处理与性能
异常只能用于非正常情况
不要将过于庞大的代码放在try中
在catch中指定具体的异常类型
需要对捕获的异常做处理
总结
•异常分为Checked异常和运行时异常
•Checked异常必须捕获或者声明抛出
•运行时异常不要求必须捕获或者声明抛出
•try-catch-finally中存在return语句的执行顺序(面试题)
•finally块中语句不执行的情况(面试题)
•throw和throws关键字的区别(面试题)