异常
一、什么是异常?
异常:在程序运行时,发生了不正常的情况,java把该异常信息打印输出到控制台,异常在java中以类存在,每一个异常类都可以创建异常对象
异常的作用:使程序更加健壮
栗子
public class text1 {
public static void main(String[] args) {
int c = 10/0;
//ArithmeticException,JVM在运行到此处时,会new一个异常对象
//并且抛出了异常对象,在控制台输出
}
}
输出结果:
Exception in thread “main” java.lang.ArithmeticException: / by zero
at text1.main(text1.java:9)
二、编译时异常与运行时异常:
编译时异常:Expect类的直接子类(必须在编写阶段预先处理,若不处理,会报错)
运行时异常:RuntimeExpection类型:编写程序时可以不处理
像刚刚那个例子中:10/0,属于ArithmeticException是运行时异常,在编写程序的时候不需要处理
三、为什么要处理异常?
在java中,有一些类中的方法抛出了编译时异常,当我们在调用该方法的时候,要对其抛出的异常进行处理,否则编译会报错!
四、处理异常的两种方式
1.抛出
处理异常的第一种方法:在声明处抛出异常,抛给调用者
不建议在main方法上throws,不然会直接抛给JVM,在main中建议下面的第二种方法
只要采用抛出的方式,出了异常的代码后面的代码不会执行!
栗子
//抛出文件没有找到异常,也可以直接抛出Expection这个父类
static void m3() throws FileNotFoundException {
//不处理异常编译报错原因:这里调用了一个构造方法
//这个构造方法的声明上有一个异常,父类是expection,是编译时异常,要求程序员编写阶段必须处理!
new FileInputStream("D:\\");
System.out.println("这里会执行吗??????不会!出异常就不会执行了!");
}
2.捕捉
处理异常的第二种方法:try catch语句,不再上抛
try catch注意事项
1.catch后面可以是具体的异常类型,也可以是该异常的父类型。
2.catch可以写多个,建议写catch的时候一个一个写,精确的处理。这样有利于程序的测试
3.catch写多个的时候,从上到下,必须遵守异常类型从小到大!
栗子
//try中的代码块发生异常后,会去与catch中的异常类型匹配,找到对应的后会执行catch中的语句
public static void main(String[] args) {
try {
//这里我们读一个不存在的文件
FileInputStream str = new FileInputStream("E:\\java进阶\\异常\\src");
str.read();
System.out.println("以上出现异常,这里无法执行!");
//catch的括号中也可以写FileNotFoundException的父类型引用
} catch (FileNotFoundException e) {
System.out.println("文件不存在!");
} catch (IOException e) {
System.out.println("读文件失败!");
}
System.out.println("hello world");
}
输出结果:
文件不存在!
hello world
3.抛出和捕捉同时使用
public class text2 {
//不建议在main方法上throws,不然会直接抛给JVM,在main中建议第二种方法
public static void main(String[] args) {
System.out.println("main begin!");
try {
//try尝试
m1();
//以上代码出现异常直接进入catch分支
System.out.println("这里不执行!");
} catch (Exception e) {
//catch捕捉异常之后走的分支
System.out.println("文件不存在!");
}
//把异常抓住后这里可以执行
System.out.println("main over");
}
private static void m1() throws Exception {
System.out.println("m1 begin");
m2();
//以上代码出异常所以下面的代码不会执行
System.out.println("m1 over");
}
//抛出了FileNotFoundException的父类也可以,直接抛出expection也行!
//throws后可以用逗号隔开,继续抛出异常
private static void m2() throws IOException,Exception {
System.out.println("m2 begin");
//m3方法声明位置上抛出了异常,我们没有处理,要么捕捉要么继续上抛
m3();
//以上代码出异常,所以下面的代码不会执行
System.out.println("m2 over");
}
//第一种处理方式,继续上抛
private static void m3() throws FileNotFoundException {
//不处理异常报错原因:这里调用了一个构造方法
//这个构造方法的声明上有一个异常,父类是expection,是编译时异常,要求程序员编写阶段必须处理!
new FileInputStream("D:\\");
System.out.println("这里会执行吗??????不会!出异常就不会执行了!");
}
}
输出结果:
main begin!
m1 begin
m2 begin
文件不存在!
main over
五、异常类的常用方法
一、获取异常简单的描述信息:getMessage(),实际上就是构造方法上面的String参数
二、打印异常追踪的堆栈信息:printStackTrace()
栗子
public class text3 {
public static void main(String[] args) {
//新建一个空指针异常对象
NullPointerException e = new NullPointerException("空指针异常");
e.printStackTrace();
String msg = e.getMessage();
System.out.println(msg);
}
}
输出结果:
java.lang.NullPointerException: 空指针异常
at text3.main(text3.java:11)
空指针异常
六、finally语句
- 关于try catch中的finally字句:
1.finally字句中的代码是最后执行的,并且一定会执行的,即使try语句块中的代码出现了异常
finally必须和try一起出现!
2.通常在finally中完成资源的释放/关闭
栗子
public class finally字句的使用 {
public static void main(String[] args) {
FileInputStream fis=null;//声明位置放在try外面,这样在finally中才能用,不然会变成局部变量
try {
fis = new FileInputStream("D:\\");
String s = null;
s.toString();
//这里一定会出现空指针异常,因为s是null
//流用完需要关闭,流是占用资源的,但放在这里上面程序出现了异常,所以流可能没有关闭
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {//源的关闭最好放在这里
System.out.println("hello");
try {
fis.close();
} catch (IOException e) {//close有异常,在这里捕捉
e.printStackTrace();
}
}
}
}
七、自定义异常类
定义异常:
第一步:编写一个类继承Expection或RuntimeExpection
第二步:提供两个构造方法,一个无参一个String参数
自定义异常:IllegalArgsExpection
自定义用户名不合法异常
public class IllegalArgsExpection extends Exception {
public IllegalArgsExpection() {
}
public IllegalArgsExpection(String message) {
super(message);
}
}
应用类:UserService
用户业务类,处理用户相关的业务:例如登录、注册等
注意自定义异常在此处的作用!
public class UserService {
//这里选择抛出,自己定义的异常没必要catch
public void register (String name,String password) throws IllegalArgsExpection {
//限制用户名的长度,不在这个范围内就抛出上面自定义的异常
if (name == null||name.length()<6||name.length()>14){
throw new IllegalArgsExpection("用户名不合法!");//抛出异常
}
System.out.println("注册成功!");
}
}
text
public class text {
public static void main(String[] args) {
UserService u = new UserService();
try {
u.register("jack","123");
} catch (IllegalArgsExpection e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
输出结果:
用户名不合法!
IllegalArgsExpection: 用户名不合法!
at UserService.register(UserService.java:8)
at text.main(text.java:5)