异常中的编译时异常
编译时异常
除了RuntimeException 以外其它的异常称为checked exception(检测异常、受检异常) ,必须捕获的异常,进行处理;不捕获程序会报错。
为什么会产生异常?下图数产生异常的缘由
**
Java中常见异常处理:所用到的五大关键字分别是 try catch finally throws throw
**
try :捕获异常的第一步是用try{…}语句块选定捕获异常的范围,将可能出现异常的代码放在try语句块中。
catch (Exceptiontype e):在catch语句块中是对异常对象进行处理的代码。每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。
与其它对象一样,可以访问一个异常对象的成员变量或调用它的方法。
getMessage()方法,用来得到有关异常事件的信息
printStackTrace()用来跟踪异常事件发生时执行堆栈的内容。
finally:不论在try、catch代码块中是否发生了异常事件,finally块中的语句都会被执行。finally语句是可选的
**注意事项!!!
第一点:try、catch、finally三个语句块均不能单独使用,三者可以组成 try…catch…finally、try…catch、try…finally三种结构,catch语句可以有一个或多个,finally语句最多一个;
第二点:try、catch、finally三个代码块中变量的作用域为代码块内部,分别独立而不能相互访问。如果要在三个块中都可以访问,则需要将变量定义到这些块的外面;
多个catch块时候,只会匹配其中一个异常类并执行catch块代码,而不会再执行别的catch块,并且匹配catch语句的顺序是由上到下;**
一个Catch语句块的时候
多个catch语句块的时候
当try语句有多个异常语句,只会执行先到的异常语句,后面的不执行。只会匹配其中一个异常类并执行catch块代码,而不会再执行别的catch块,并且匹配catch语句的顺序是由上到下;
用图片对比:
getMessage()方法,用来得到有关异常事件的信息
printStackTrace()用来跟踪异常事件发生时执行堆栈的内容。
有finally语句块执行结果
没有finnal语句块执行结果
好奇的同学们会不会觉得有没有finally语句块最后还是执行,要finally语句块干什么,会显得多次一举对吧。那你在思考的这个问题的时候有没有想过如果没有finally语句块后面会出现不能执行的情况吗?如果有是什么情况?
第一种情况是当我们catch里面还有异常的时候就会出现try…catch 外面的system输出语句不执行
第二种是system.exit()释放资源语句,也可以称为断电。
体现有finally语句的好处。
**
基类异常的捕获语句不能写在子类捕获语句的前面;
**
@Test
public void test1() {
int a = 100;
int b = 0;
try {
int[] i = new int[] {1,2,3,4,5,6};
// java.lang.ArrayIndexOutOfBoundsException: 9
System.out.println(i[1]); // 抛出了一个异常对象(实例)
// java.lang.ArithmeticException: / by zero
System.out.println(a/b);
System.out.println("方法没有异常,结束调用了...");
// Exception
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("出现了数组下标越界异常:"+e.getMessage());
// 在控制台打印异常信息:栈结构,表现的就是方法的调用关系
e.printStackTrace();
System.out.println(a);
}catch(NullPointerException e) {
System.out.println("出现了空指针异常:"+e.getMessage());
}catch(ArithmeticException e) {
System.out.println("出现了算术异常:"+e.getMessage());
/*try {
String s = null;
System.out.println(s.lastIndexOf(11));
}catch(NullPointerException e1) {
}*/
}finally {
// finally中的代码是一定要执行的
System.out.println("finally ... ");
}
// 写在最后的代码和finally中的情况,是不同的,有可能不执行
//System.out.println("最后要执行的代码 ... ");
}
try/catch/finally中return
当我在finally代码里面添加return 3结果会输出什么?是finally代码 然后3 然后 1?
正确答案是是finally代码 然后3 当我return 3 的时候已经返回了,就不需要再到return 1 那里。那么接下来你自己动手写一下代码
package yichangchuli;
public class Yichang4 {
public int test() {
//这是正常运行
try {
int a =10;
int b= 1;
int c=a/b;
return 1;// 方法在这里要结束了,查找有没有finally,如果有,马上执行finally,再return
} catch (ArithmeticException e) {
e.printStackTrace();
return 2;
}finally {
System.out.println("finall代码");
return 3;
}
}
public static void main(String[] args) {
Yichang4 tc1 =new Yichang4();
int num =tc1.test();
System.out.println(num);
}
}
异常里面也可以重载:规则:重写方法需要抛出与原方法所抛出异常类型一致或不抛出,(此规则不包括非检测异常)
package yichangchuli;
import java.io.IOException;
public class Yichang5 {
//重写方法声明抛出异常规则不包括非检测异常
public void m() throws IOException{}
class B extends Yichang5{
//重写方法与原方法一致
public void m() throws IOException{}
}
class c extends Yichang5{
//错误的写法
// public void m() throws Exception{}
}
class D extends Yichang5{
//或者不抛出
public void m() {};
}
}
声明抛出异常:处理异常的第二种方式
如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显式地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
在方法声明中用 throws 子句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
声明抛出异常举例:
public void readFile(String file) throws FileNotFoundException {
......
// 读文件的操作可能产生FileNotFoundException类型的异常
FileInputStream fis = new FileInputStream(file);
......
}
package yichangchuli;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
public class Yichang6 {
// throws关键字,在方法的声明处,显示的告知方法的调用者,该方法可能会抛出什么异常。
//多个异常可以用逗号分隔开
public Connection getConn() throws ClassNotFoundException,SQLException{
// Connection conn = DriverManager .getConnection("jdbc:mysql://localhost:3306/test","root","123456");
//其实上面那段话相当于等价的意思
return DriverManager .getConnection("jdbc:mysql://localhost:3306/test","root","123456");
}
}
**
如何理解手动抛出异常呢?其实手动抛出异常也就是比如相当于你去电信营业厅换手机卡,客服说对不起,我们这里不能给你解决,这时候客服会推荐去更高级的营业厅去办理,其实手动抛出异常就像这样。
**
自定义异常:当JDK中的异常类型不能满足程序的需求的时候,可以自定义异常类。使用自定义异常类的步骤:
定义异常类,并继承Exception或者RuntimeException;
编写异常类的构造方法,并继承父类的实现;
首先我们得先写一个类,自定义异常的类去继承我们的父类Exception
如果你能联想的话就会想明白那些什么数组下标越界异常、还有转换类型异常里面的源代码也是继承我们的父类。但是为什么要写那么多子类异常呢,其实就是想自定义遇到不同异常具体报告,方便我们好查找。
package com.zidingyi;
public class ZidingyiException extends Exception{
/**
*
*/
private static final long serialVersionUID = 1L;
public ZidingyiException() {
super();
}
public ZidingyiException(String message) {
super(message);
}
}
然后我们新建一个类是我们设置匹配,就比如我们从那边登录输入了信息,就传到我这个类去判断一下,判断输入和我们的账号密码不匹配就给你报错,爆我们自定义的异常
package com.zidingyi;
public class LoginException {
//使用自定义异常 登录失败的话就抛出一个自定义异常
public String login(String username,String password) throws ZidingyiException {
if(username ==null ||password==null ||username==""||password=="") {
//如果名字为空或者密码为空或者输入空格
throw new ZidingyiException("用户名或密码都不能为空");
}//如果等于我们的账号admin 密码123456 则登录成功
if(username.equals("admin") && password.equals("123456")) {
return "登录成功";
}else {
throw new ZidingyiException("登录失败");
}
}
}
最后就是我们用户输入的账号和密码了
package com.zidingyi;
public class Loginusername {
public void login(String username,String password) {
LoginException t1 =new LoginException();
String msg;
try {
msg = t1.login(username, password);
System.out.println("恭喜你!"+msg);
} catch (ZidingyiException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Loginusername um =new Loginusername();
um.login("admin", "123456"); //登录成功
//um.login("abc", "123456");
}
}