目录
2.3、开发中如何选择try-catch-finally 还是 throws?
四、工作情况下,有问题就改代码,这个异常的处理这解决了表面的问题
一、异常的体系结构
1、java.lang.Error
Java虚拟机无法解决的严重问题。
如:JVM系统内部错误、资源毛尽等严重情况。
比如:StackOverflowError和OOM。。
这种的一般不编写针对性的代码进行处理
举例:
public class ErrorTest {
public static void main(String[] args) {
// 1.栈溢出:java.lang.StackOverflowError
main(args);
// 2.堆溢出:java.lang.OutOfMemoryError
integer[] arr = new integer[1024*1024*1024];
}
}
2、java.lang.exception
2.1、编译时异常(checked)
举例:IOException
FileNotFoundException
2.2、运行时异常(unchecked)
举例:NullPointerException 空指针
ArrayIndexNotOfBoundsException 数组角标越界
ClassCastException 类转换异常
NumberForMatException 数字格式异常
InputMismatchException 输入不匹配
ArithmeticException 算术异常
举例:
public class ExceptionTest {
public static void main(String[] args) {
// NullPointerException
int[] arr = null;
System.out.println(arr[3]);
String s1 = null;
System.out.println(s1.charAt(4));
// ArrayIndexNotOfBoundsException
int[] arr1 = new int[3];
System.out.println(arr1[5]);
// StringIndexNotOfBoundsException
String s2 = "abc";
System.out.println(s2.charAt(5));
// ClassCastException
Object obj = new String();
int i = (int) obj;
// NumberForMatException
String str = "abc";
int num = Integer.parseInt(str);
// InputMismatchException
Scanner scanner = new Scanner(System.in);
int score = scanner.nextInt();// 如果输入int型的就没问题。但是如果输入别的类型就不行了
System.out.println(score);
// ArithmeticException
int a = 10;
int b = 0;
System.out.println(a / b);
}
}
二、异常的处理:
1、异常的处理方式一:try-catch-finally
1.1、try-catch-finally使用方法
try{
可能出现异常的代码
}catch(异常类型1 变量名1){
//处理异常的方式
}catch(异常类型2 变量名2){
//处理异常的方式
}catch(异常类型3 变量名3){
//处理异常的方式
}
finally{
//一定会执行的代码
}
1.2、 说明:
1. finally是可有可无的。
2.使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对的类型,
去catch中进行匹配
3. 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成
就跳出当前的try-catch结构(在没有写finally的情况)。继续执行其后的代码
4. catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错
5. 常用的异常对象处理的方式:① String getmessage() ② printStackTrace()
6.在try结构中声明的变量,再出了try结构以后,就不能再被调用
7. try-catch-finally结构是可以嵌套的
1.3、体会
1、使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。
2、开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。针对于编译时异常,我们说一定要考虑异常的处理
try-catch-finally举例:
public class ExceptionTest1 {
public static void main(String[] args) {
String str = "abc";
try {
int num = Integer.parseInt(str);
System.out.println(num);
} catch (NumberFormatException e) {
//方式一:
// System.out.println("输入的数据不是int型的哦,我们正在处理,请稍后再试。。。");
//方式二:
System.out.println(e.getMessage());//For input string: "abc"
//方式三:
// e.printStackTrace();
}
}
}
1.4、finally的{}中是:一定会执行的代码
1.finally是可有可无的
2.为什么说是finally中是一定会执行的代码呢:因为即使catch中又出现异常了,或者try中有return语句,catch中有return语句等情况,finally业一定会执行
3.像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动回收的。我们需要自己手动的进行资源的释放。此时资源的释放操作就放在finally之中
public class FinallyTest {
public static void main(String[] args) {
try {
int a = 0;
int b = 10;
System.out.println(b / a);
} catch (ArithmeticException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("我一定会被执行");
}
}
}
2、异常处理的方式二:throws + 异常类型
2.1、在代码中的位置
“throws + 异常类型”写在方法的声明处,指明此方法执行时,可能会抛出异常类型。一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后面的异常类型时,就会被抛出。异常代码后续的代码就不会被执行了
2.2、父类中有抛出异常
方法的重写规则之一:
子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
代码解释:调用的子类的new的对象,会抛一个异常FileNotFoundException,而异常在display()
中已经处理过了,处理的是IOException,如果子类的异常更大,那try-catch-finally就白写了,处理就白处理的。
public class OverRideTest {
public static void main(String[] args) {
OverRideTest over = new OverRideTest();
over.disPlay(new Subclass());//new了一个子类的对象
}
public void disPlay(Superclass s) {//形参是父类类型的
try {
s.method();//对method()进行了处理
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Superclass{//父类中有一个名为method()的方法,并且抛出异常类型为IOException
public void method() throws IOException{
}
}
class Subclass extends Superclass{//子类中重写了method()方法,抛出异常类型为FileNotFoundException,ctrl+t可以知道是IOException的子类
public void method() throws FileNotFoundException {
}
}
2.3、开发中如何选择try-catch-finally 还是 throws?
①try-catch-finally真正的将异常处理掉了
throws只是将异常抛给了方法的调用者,并没有将异常真正的处理掉
②父类被重写的方法没有throws异常,那子类重写的方法也不能throws异常,只能使用try-catch-finally
③执行的方法a中调用了几个别的方法,而这几个方法可能会抛出异常,那么建议这几个方法用throws抛出异常,而把整个方法a用try-catch-finally来处理
代码举例
public class ExceptionTest2 {
public static void main(String[] args) throws FileNotFoundException, IOException {
File file = new File("hello.txt");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while (data != -1) {
System.out.println((char) data);
data = fis.read();
}
fis.close();
}
}
三、自定义异常类
1、如何自定义一个异常
1.继承与现有的异常类:RuntimeException、Exception
2.提供全局常量:serialVersionUID
3.提供重载的构造器
public class MyException extends RuntimeException {
static final long serialVersionUID = -7642316356023L;
public MyException() {
}
public MyException(String message) {
super(message);
}
}
测式代码:
public class StudentsTest {
public static void main(String[] args) {
try {// 全包起来
Student s = new Student();
s.regist(-1001);// 这个异常,下一行没有执行,直接蹦到catch中的处理方法
System.out.println(s.toString());
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
class Student {
private int id;
public void regist(int id) {// 如果throw的异常类是运行时的,那这里不用throws,不会报错;
// 如果throw的异常类是Exception,那这里就要throwsException,
// 不然会报错,这样调用这个方法的类会处理
// 也可以自己try-catch-finally处理了,就不用throws了
if (id > 0) {
this.id = id;
} else {
// System.out.println("输入的数据非法!");
// 这里我们要手动抛出异常
// throw new RuntimeException("输入的数据非法");
// throw new Exception("输入的数不行!");
throw new MyException("自己定义的异常类");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}