一、了解异常
1. 异常的体系结构
异常类:java.lang.Throwable,它有两个子类,分别是:
1.1、java.lang.Error :Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError和OOM。一般不编写针对性 的代码进行处理。
1.2、java.lang.Exception :其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。常见异常举例:
1.2.1、编译时异常(check):
①java.io.IOException
java.io.FileNotFoundException
@Test
public void test7(){
// File file = new File("hello.txt");
// FileInputStream fis = new FileInputStream(file);
//
// int date = fis.read();
// while(date != -1){
// System.out.println((char)date);
// date = fis.read();
// }
//
// fis.close();
}
②java.lang.ClassNotFoundException
1.2.2、运行时异常(uncheck):
①java.lang.NullPointerException
@Test
public void test1(){
//NullPointerException
int[] i = null;
System.out.println(i[1]);
String str = new String("abc");
str = null;
System.out.println(str.charAt(0));
}
②java.lang.ArrayIndexOutOfBoundsException
@Test
public void test2(){
//ArrayIndexOutOfBoundsException
int[] i = new int[3];
System.out.println(i[3]);
//StringIndexOutOfBoundsException
String str = "123";
System.out.println(str.charAt(3));
}
③java.lang.ClassCastException
@Test
public void test3(){
//ClassCastException
class Person{
}
class Man extends Person{
}
class Woman extends Person{
}
Person p = new Man();
Woman w = (Woman)p;
}
④java.lang.NumberFormatException
@Test
public void test4(){
String str = "123";
str = "abc";
int num = Integer.parseInt(str);
System.out.println(num);
}
⑤java.util.InputMismatchException
@Test
public void test5(){
Scanner scan = new Scanner(System.in);
int score = scan.nextInt();
System.out.println(score);
scan.close();
}
⑥java.lang.ArithmeticException
@Test
public void test6(){
int m = 10;
int n = 0;
System.out.println(m/n);
}
二、异常的处理
1、java异常处理的抓抛模型
1.1、过程1.抛:程序运行过程中,当代码运行到异常代码时,就会生成一个对应异常类的对象,并将此对象抛出。抛出异常对象后,其后面的代码将不在运行。
1.1.1、异常对象的产生:①代码自动生成的异常对象
②手动生成一个异常对象 并抛出(throw)
1.2、过程2.抓:可以理解为处理异常的方式:①try—catch—finally ②throws
①try—catch—finally
2.1、使用说明:
格式:try—catch—finally
try{
//可能会出现异常的语句
}catch(异常类1 异常对象1){
//处理语句1
}catch(异常类2 异常对象2){
//处理语句2
}catch(异常类3 异常对象3){
//处理语句3
}
...
finally{
//一定会运行的语句
}
@Test
public void test1(){
String str = "123";
str = "abc";
int num = 0;
try{
num = Integer.parseInt(str);
System.out.println("hello--1");
}catch(NullPointerException e){
System.out.println("出现空指针异常,别着急.....");
}catch(NumberFormatException e){
// System.out.println("出现数值转换异常,别着急.....");
//For input string: "abc"
// System.out.println(e.getMessage());
e.printStackTrace();
}catch(Exception e){
System.out.println("出现异常,别着急.....");
System.out.println("hello--3");
}
System.out.println("hello--2");
System.out.println(num);
}
2.2、总结说明:
1.finally结构是可的。
2.使用try结构将可能会出现异常的代码包起来,当运行到异常代码时,会生成对应的异常类的对象,与catch结构中的异常类进行匹配。
3.如果try结构中产生的异常对象匹配到某一个catch时,就会进入该catch结构中进行异常处理,一旦完成异常处理,就不会进入其他catch结构中。直接跳出try-catch结构(没finally结构的情况)
4.catch结构中的异常类如果没子父类关系,那么谁声明在上无所谓。catch结构中的异常类如果子父类关系,那么子类异常一定要声明在父类异常的上面,否则报错!
5.catch结构中常使用的两种方法:①getMessage() ②printStackTrace()
6.在try结构中声明的变量,出了try就不能再调用。
7.try—catch—finally可以进行嵌套操作。
总结:如何看待代码中的编译时异常和运行时异常?
体会1:使用try-catch-finally结构,可以将程序在编译时不在报错,但运行时仍可能报错。可以理解为我们使用try-catch-finally结构,将编译时异常延迟到运行时异常。
体会2:在开发中,遇到运行时异常,我们一般不使用try-catch-finally结构进行异常处理。但是遇到编译时异常时,一定要进行异常处理。
2.3、finally的再说明:
①finally结构是可的
②finally结构中的代码一定会被执行,即使try、catch结构中return了语句或者catch结构中又异常。
③对于数据库连接、输入流输出流、Socket连接,JVM也无能为力,这时候就要将这些操作放进finally结构中,保证这些操作会被执行。
②throws
3.1、"throws+异常类型"写在类的声明处,指明这个方法运行时,可能出现的异常。一旦方法体被运行到异常代码处,就会生成相对应的异常对象,此对象满足throws之后的异常类型,就会被抛出。异常代码后续的代码,不会再继续执行。
public static void main(String[] args) {
try {
method2();
} catch (IOException e) {
e.printStackTrace();
}
method3();
}
public static void method3(){
try {
method2();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void method2() throws IOException{
method1();
}
public static void method1() throws FileNotFoundException,IOException{
File file = new File("hello1.txt");
FileInputStream fis = new FileInputStream(file);
// System.out.println("**************");
int date = fis.read();
while(date != -1){
System.out.println((char)date);
date = fis.read();
}
fis.close();
}
4、对比两种处理方式
1、try-catch-finally结构:真正的将异常处理掉了。
2、throws+异常类型结构:并没真正的处理异常,将可能出现的异常抛给此方法的调用者。
5、体会开发中应该如何选择两种处理方式?
5.1、如果父类中被重写的方法没使用throws抛出异常,那么子类中重写的方法一定不能使用throws来抛出异常。子类重写的方法中如果异常,一定要使用try-catch-finally结构进行处理。
5.2、如果一个执行方法a,先后又执行了其他几个方法,这些方法时递进关系,那么这几个方法可以先用throws。这个执行方法a,在使用try-catch-finally结构进行异常处理。
补充:子类中重写的方法抛出的异常不大于父类中被重写的方法跑出的异常。
三、手动抛出异常对象
1、使用说明
Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要使用人工创建并抛出。
2、面试题
throw和throws的区别:
①throw表示抛出一个异常类的对象,生成异常对象的过程,声明在方法体内。
②throws表示处理异常的一种方式,写在方法声明处
3、举例
class Student{
private int id;
public void registe(int id) throws Exception{
if(id>0){
this.id = id;
}else{
// System.out.println("输入的id不合法");
// throw new RuntimeException("输入的id不合法");
// throw new Exception("输入的id不合法");
throw new MyException("不能输入负数");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
四、自定义异常类
1、如何自定义异常类?
1.1、继承于现的异常类:RuntimeException、Exception
1.2、定义全局常量:serialVersionUID
1.3、创建重载的构造器
2、代码实现
public class MyException extends Exception {
static final long serialVersionUID = -7034897195766939L;
public MyException(){
}
public MyException(String msg){
super(msg);
}
}