java异常详解

Thorwable类:

Throwable是所有异常和错误的老祖。他有两大分支:Error、Exception

 

异常类:

         异常用来处理程序中出现异常的代码,异常可以使程序中的异常处理与正常业务代码分离,保证程序更加健壮。

         异常体系中,又区分运行期异常和编译期异常。

java的异常处理关键字:try、catch、finally、throw、throws五个关键字。

在编写代码中出现的问题,可以用代码进行控制。

         如最常见的,空指针异常NullPointerException。

class TestException{
        static Person person;
        public static void main(String[] args){
            //空指针异常
            person.method();
        }
 
}
class Person{
    void method(){
       
    }
   
}
 

算数异常:ArithmeticException

class TestException{
        public static void main(String[] args){
            //算数异常
            int i = 1 / 0;
        }
 
}


数组角标越界:ArrayIndexOutOfBoundsException

class TestException{
        public static void main(String[] args){
            int[]arr = new int[5];
            //数组角标越界.ArrayIndexOutOfBoundsException
            arr[6]= 1;
        }
 
}


类型转换错误:ClassCastException

class TestException{
        public static void main(String[] args){
            Person person = new Person();
            //将父类对象,转为子类引用类型,报错,类型转换错误:ClassCastException
            Childchild = (Child)person;
        }
 
}
class Person{}
class Child extends Person{}
 


错误

Error:

针对程序来说,是一个致命性,不可挽回的一个错误。无法用代码阻止或者处理该错误的发生。

内存溢出错误:OutOfMemoryError

class TestException{
        public static void main(String[] args){
            //错误,内存溢出.OutOfMemoryError
            Person[] persons = new Person[1008611000];
            for(inti = 0 ; i < persons.length ; i++){
                persons[i]= new Person(i+ "岁","名字" + i,"地址" + i);
               
            }
        }
 
}
class Person{
    String age;
    String name ;
    String address;
    public Person(String age,String name ,String address){
        this.age= age;
        this.name= name;
        this.address= address;
       
    }
}
 


错误处理:

错误是无法用代码控制的,所以我们这里就不研究错误了,主要研究异常体系。

异常处理:

两种方式,一种是直接内部处理try{}catch(){},第二种是抛出,谁调用出现异常的方法,谁去处理。

第一种方式

try{

         //可能出现异常的代码块

}catch(异常类型 参数名){

         //当异常发生,处理异常的代码

}finally{

         //该代码块为可选项

         //不管发生不发生异常,一定会执行的代码块

}

 在catch中捕获的异常,其实也是一个对象,是异常类型的对象,我们可以通过该异常的参数名调用一些异常对象的方法,因为Exception中并没有定义方法,所以我们可以使用它的父类,Throwable类中的方法来获取关于异常信息的方法。

 

class TestException{
        static Person person;
        public static void main(String[] args){
            excetionMethod();
        }
        //异常方法
        static void excetionMethod(){
            //空指针异常
            try{//将可能会出现异常的代码包括起来
            person.method();
            }catch(Exceptione){
                //如果try代码块中的代码真的发生了异常,那么就执行这个代码块中的代码。
                System.out.println("发生了空指针异常,这里进行了异常处理的代码");
            }finally{
                //不管异常是否发生,该代码块一定会执行
                System.out.println("finally代码块中的代码执行了");
               
            }
            System.out.println("***********");
        }
 
}
class Person{
    void method(){
        System.out.println("正常执行的代码");
    }
   
}
 

第二种方式:抛出

方法() throws Exception{}

注意:

1、  使用该方式,将异常抛出,让调用该方法者去处理异常。

2、  调用异常方法,未处理,一直向上抛出,最终抛给虚拟机去处理。虚拟机打印异常信息并终止程序。

3、  抛出的异常必须大于或等于该类型异常。

 

 

class TestException{
        static Person person;
        public static void main(String[] args) throws Exception{
            //此处处理抛出的异常
                excetionMethod();
            }
        }
        //异常方法
        static void excetionMethod()throws Exception{
            //空指针异常
            person.method();
        }
 
}
class Person{
    void method(){
        System.out.println("正常执行的代码");
    }
   
}
 

 java异常详解_第1张图片

我们会发现,如果不对异常进行处理,那么,发生异常,默认是虚拟机执行。终止程序,打印异常信息。

虚拟机处理异常的方式就是:打印异常信息,结束程序。而打印异常信息,就相当于调用了异常对象的printStackTrace()方法


 

异常类型处理:

         发生异常,抛出的异常类型必须是发生异常类型的本身异常或其父类异常。try…catch处理,catch括号中接收的异常对象必须是try代码块代码发生异常类型的本身或父类异常对象,否则就无法处理try代码块中的异常。

java异常详解_第2张图片

 

try…catch……方式处理,以下案例异常处理是错误的,因为try…catch捕获的ArithmeticException异常并不是方法抛出的NullPointerException类型。

class TestException{
        static Person person;
        public static void main(String[] args) {
            //此处处理抛出的异常
                try{
                excetionMethod();
                }catch(ArithmeticExceptione){ 
                }
            }
       
        //异常方法
        static void excetionMethod()throws NullPointerException{
            //空指针异常
            person.method();
        }
 
}
class Person{
    void method(){
        System.out.println("正常执行的代码");
    }
   
}


thorws抛出异常,必须是发生的异常类型本身或父类类型异常。

	//错误的异常抛出方式,因为该方法发生异常类型是空指针异常,结果抛出了类型强制转换异常。
        static void excetionMethod()throws ClassCastException{
            //空指针异常
            person.method();
        }


必须抛出其类型本身异常或者父类异常,如下是正确的

   

 //发生空指针异常,抛出空指针异常的父类异常,正确
    static void excetionMethod()throws Exception{
            //空指针异常
            person.method();
        }
 

异常的嵌套:

class TestException2{
public static void main(String[] args){
    //处理异常
    try{
        method();
    }catch(Exceptione){
        try{
            anmethod();
            System.out.println("第一异常执行了");
        }catch(Exceptione2){
            System.out.println("这是另一个异常执行了");
        }
    }
}
//抛出异常
public static void method() throws Exception{
    int i =1/0;
    }
    public static void anmethod()throws Exception{
    int i =1/0;
    }
}


多异常处理及异常的短路:

多个异常的抛出:当执行的代码遇到多个异常时,可以抛出多个类型的异常,然后,调用者通过捕获该类型异常,来执行处理对应异常的代码。

格式:

   

      try{
}catch(异常类型A ea){
         //这里做针对发生A异常的操作
}catch(异常类型B eb){
         //这里做针对发生B异常的操作
 
}
class TestException2{
    static Person person;
public static void main(String[] args){
        //多个异常的捕获
        try{
            method();
        }catch(ArithmeticExceptione){
            System.out.println("算数异常");
        }catch(NullPointerExceptione2){
            System.out.println("空指针异常");
        }
        //外部的正常代码
        System.out.println("外部最后一条语句");
    }
   
     static void method()throwsNullPointerException,ArithmeticException{
        //空指针异常
        person.method();
        //算数异常
        int i= 1/0;
 
    }
}
class Person{
    void method(){};
}

异常的接收

         catch(Exceptione),catch代码块之后,需要捕获一个异常对象,通过该异常对象,就可以操作获取该类型异常信息,所以说,抛出了什么异常,就应该在对应的catch处理代码块中接收什么类型的异常,否则就无法捕获。

如:抛出一个空指针异常,但是catch代码块只接收一个算数异常,那么发生的异常,就无法被捕获处理。

class TestException2{
    static Person person;
public static void main(String[] args){
        //多个异常的捕获
        try{
            method();
        }
        //抛出空指针异常,结果这里只有算数异常,所以该method方法抛出的空指针异常无法手动捕获处理,默认交给虚拟机处理,打印异常信息并结束程序。
        catch(ArithmeticExceptione){
            System.out.println("算数异常");
    }
   
     static void method()throwsArithmeticException{
        //空指针异常
        person.method();
 
    }
}
class Person{
    void method(){};
}


异常的短路

  

  classTestException2{
    static Person person;
    public static void main(String[] args){
        //多个异常的捕获
        try{
            method();
        }
        //父类异常短路了子类异常,无法执行到子类异常,编译期报错
        catch(Exceptionexception){
            System.out.println("父类异常");
        }catch(NullPointerExceptione){
            System.out.println("空指针异常执行");
        }
    }
     static void method()throwsNullPointerException{
        //空指针异常
        person.method();
 
    }
}
class Person{
    void method(){};
}
 
 

 

正确的操作:

class TestException2{
    static Person person;
public static void main(String[] args){
        //多个异常的捕获
        try{
            method();
        }catch(NullPointerExceptione){
            System.out.println("空指针异常");
        }
        catch(Exceptione){
            System.out.println("其他异常");
        }
    }  
     static void method()throwsNullPointerException,ArithmeticException{
        //空指针异常
        int i= 1/0;
 
    }
}
class Person{
    void method(){};
}
 


 

异常对象:

异常对象的常用方法:

printStackTrace():打印异常信息

   

     try{
            method();
        }catch(NullPointerExceptione){
            e.printStackTrace();
        }

编译期(Checked)异常和Runtime异常体系

Java的异常别分为两大类:编译期异常和Runtime异常(运行时异常),所有的类及子类的实例都被称为RuntimeExceptionRuntime异常,不是Runtime异常的其他都是编译期异常。

编译期异常:

         遇到编译期异常时,必须显式的处理该类型异常,try..catch或向上throws抛出,如果没有处理,程序就无法通过编译。

 

import java.io.IOException;
class TestException2{
    static Person person;
public static void main(String[] args){
        //该方法抛出一个编译期异常,但是并没有进行捕获或者抛出,所以编译期报错
        method();
    }  
     static void method()throws IOException{
        //空指针异常
        person.method();
 
    }
}

运行期异常:

Runtime异常则更加灵活,Runtime异常不需要显式的处理,当然,如果程序需要捕获Runtime异常,也可以使用try…catch块来实现。

1、  即便不处理运行期异常,也不会在编译期报错。

import java.io.IOException;
class TestException2{
    static Person person;
public static void main(String[] args){
        //
        method();
    }  
     static void method()throwsNullPointerException{
        //编译期不会报错(编译不报错)
        person.method();
 
    }
}
class Person{
    void method(){};
}


2、  运行期异常只会在运行期报错。

import java.io.IOException;
class TestException2{
    staticPerson person;
public static void main(String[] args){
        //
        method();
    }  
     static void method()throwsNullPointerException{
        //编译期不会报错(编译不报错)
        //会在程序运行的时候,执行到这行代码,就会报错
        person.method();
 
    }
}
class Person{
    voidmethod(){};
}
 


 

 

3、  运行期异常也可以进行手动try…catch捕获处理,处理完毕以后,还会正常执行程序。

import java.io.IOException;
class TestException2{
    static Person person;
public static void main(String[] args){
        //运行期异常也可以手动捕获
        try{
        method();
        }catch(NullPointerExceptione){
            System.out.println("运行期异常也可以手动捕获,发生了:" + e);
        }
        System.out.println("try..catch处理完异常以后,其他代码继续正常执行!");
    }  
     static void method()throwsNullPointerException{
        //编译期不会报错(编译不报错)
        //会在程序运行的时候,执行到这行代码,就会报错
        person.method();
 
    }
}
class Person{
    void method(){};
}


throws与throw

之前,产生异常,就是代码发生了异常,或者手动在方法上抛出一个异常。

         1、代码本身就会发生异常

   

 	staticvoid method(){
        //1、代码本身就会发生异常
        int i= 1 / 0;
        }

         2、手动抛出一个异常

     

   //2、在方法上声明抛出异常
        static void method() throws Exception{
 
        }

        

java也允许自行抛出异常,使用throw抛出,虽然使用throw抛出异常,但是,遇到抛出的是编译期异常,也要必须在方法上声明,thorws抛出该编译期异常。反之,运行期异常则不需要显示的处理,当然,也可以try catch进行手动捕获处理运行期异常。

import java.io.IOException;
import javax.print.PrintException;
class TestException2{
    static Person person;
public static void main(String[] args) throwsIOException,PrintException{
        //自行抛出异常
        int i= 3;
        if(i== 1){
            throw new IOException();
        }elseif(i == 2){
            throw new NullPointerException();
        }elseif(i == 3){
            throw new PrintException();
        }
   
    }  
}
 


自定义异常:

处理异常时,选择合适的异常处理对应的问题,但如果系统提供的异常无法满足我们的需要,我们就可以自己定义异常。

格式:

         1 继承Exception类

         2  提供无参构造器和带字符串参数构造器

自定义异常的使用:

class TestException2{
public static void main(String[] args){
        try{
        method();
        }catch(MyExceptionmy Exception){
            String str = myException.getMessage();
            System.out.println(str);
        }
    }  
    public static void method()throws MyException{
        throw new MyException("自定义的异常");
    }
}
 
class MyException extends Exception{
    public MyException(String message){
        super(message);
    }
    public MyException(){};
}
 


自定义运行期异常:

class TestException2{
public static void main(String[] args){
        try{
        method();
        }catch(MyException myException){
            String str = myException.getMessage();
            System.out.println(str);
        }
    }  
    public static void method(){
        thrownew MyException("自定义的运行期异常");
    }
}
 
class MyException extends RuntimeException{
    public MyException(String message){
        super(message);
    }
    public MyException(){};
}


 

为什么自定义异常要有无参构造器和传一个字符串的构造器?

1、  因为Throwable有一个无参构造器

java异常详解_第3张图片

2、  throwable有一个有参构造器

java异常详解_第4张图片

3、为什么还需要定义一个无参构造器,默认就有无参构造器的!

因为,定义了构造器以后,默认的无参构造器就消失了,所以还需要自定义一个无参构造器。

 

Sring getMessage();为什么返回的是构造器传入的字符串?

源码如下:

java异常详解_第5张图片java异常详解_第6张图片

我们发现,在执行有参构造器创建异常对象的时候,就发现,throwable构造器将该字符串赋值给了detailMessage变量,所以,当再次获取该变量,就是我们之前传入的message信息。

你可能感兴趣的:(java基础,java异常体系,java异常,javaException,Excepiton,自定义异常)