黑马程序员 异常

  ----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

Uncheck类型的异常包括RuntimeException 以及他的子类。

  Check类型的异常包括exception这个类,以及exception除了RuntimeException的子类。如果抛出的是check异常,则必须进行try,catch处理。
  try ,catch,finally. 如果try里边的内容无异常,则不执行catch,否则则执行,最后执行finally一定执行,相当于异常的出口。

  如果对于一个函数 throws 异常,那么调用这个函数的地方要对其进行处理。

先编写一个User类

 class User {
	 private int age;
	 public void SetAge(int age) throws Exception{
		 if(age<0){
			 Exception e = new Exception("年龄不能为负数");
			 throw e;
		 }
		 this.age=age;
		
	 }

}
.......................................................................................
再编写一个test类
 class test {
     public static void main(String args[]) {      	
    		 User tony = new User();        	
        	 try {
				tony.SetAge(-20);
			} catch (Exception e) {
				
				e.printStackTrace();
			}    		    		 
    	 }   	    	 
     }


异常详解

异常是什么呢?异常就是程序在运行时出现不正常情况。

异常怎么由来的呢?问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述,并封装成对象。其实就是java对不正常情况描述后的对象体现。

对于问题的划分,总共两种:

a)  严重的问题:java通过Error类进行描述,对于Error一般不编写针对性的代码对其处理

b)  非严重的问题,java通过Exception类进行描述,对于Exception可以使用针对性的处理方式进行处理

无论Error或者Exception都具有一些共性内容,比如不正常情况的信息,引发原因等。这些共性的内容就Throwable,它是Error和Exception的父类

 

异常的处理

try-catch语句

对于异常我们怎么处理呢?java提供了特有的语句(try-catch)进行处理。格式如下:

try{

  需要被检测的代码

}catch(异常类变量)

处理异常的代码;(处理方式)

finally

  一定会执行语句;

蓝色部分可以省略不写

 

例如我们对以下代码除零抛出算数异常进行处理;

处理前:

class  ExceptionTest

{

         public static void main(String[] args)

         {

                   Demo d=new Demo();

                   int x=d.div(3,0);

                   System.out.println(x);//抛出ArithmeticException异常

         }

}

class Demo

{

    public int div(int a,int b){

            return a/b;

         }

处理后(使用try-catch):

class  ExceptionTest

{

         public static void main(String[] args)

         {

                   Demo d=new Demo();

                   try{

                   int x=d.div(3,0);

                   System.out.println(x);//异常后,这段代码不执行

                   }catch(Exception e){   //Exception e =new ArithmeticException();

              System.out.println("嗨,除零了");

           }

         }

}

class Demo

{

    public int div(int a,int b){

            return a/b;

         }

}

对于这个以上Exception e其实是吧new ArithmeticException();对象传给了形参e,就形成了多态。Exception e =new ArithmeticException();对于catch捕获到的异常对象常见的方法操作是什么呢?

a)  获取异常信息:public String getMessage():返回此 throwable 的详细消息字符串

b)  public String toString():返回此 throwable 的简短描述

c)  public void printStackTrace():将此 throwable 及其追踪输出至标准错误流。

对于这三种常见方法我们来看看如下代码:

class  ExceptionTest

{

public static voidmain(String[] args)

{

           Demo d=new Demo();

 

           try{

           int x=d.div(3,0);

           System.out.println(x);

           }catch(Exception e){

              System.out.println(e.getMessage()); // /byzero

              System.out.println(e.toString());//异常名称:异常信息

              e.printStackTrace();//异常名称,异常信息,异常所出现的位置

                                  //其实jvm默认的异常处理机制,就是在调用printStackTrace()方法,打印异常的堆栈的跟踪信息

              }

}

}

class Demo

{

    public int div(int a,intb){

    return a/b;

}

}

异常声明throws关键字

throws关键字在功能上通过throws的关键字声明了该功能有可能出现问题。会提示你去如何让解决该功能如何解决?不解决编译错误。如以下代码:

classThrowsExceptionTest

{

         public static void main(String[] args)

         {

                  

                   Demo d=new Demo();

                   int x=d.div(3,0);

                   System.out.println(x);

         }

}

class Demo

{

    public int div(int a,int b)throwsException{   //编译抛出异常

            return a/b;

         }

 

怎么解决编译错误呢?我们在main方法后面再加上)throws Exception{  编译没错,如果运行出错,最终虚拟机会处理,程序结束。

我们还是使用try-catch来处理这种异常,记住throws什么名称的异常,try-catch语句里就处理什么异常,如以下代码:

class Demo

{

    public int div(int a,int b)throws ArithmeticException{   //抛出什么异常

            return a/b;

         }

}

classThrowsExceptionTest

{

         public static void main(String[] args)

         {

                   try{

                   Demo d=new Demo();

                   int x=d.div(3,0);

                   System.out.println(x);

                   }catch(ArithmeticExceptione){   //处理什么异常

                      System.out.println(e.toString());

                   }

         }

}

 

多异常处理

我们在处理异常时,我们有如下建议:

a)      声明异常时,建议声明更为具体的异常。这样处理的可以更具体

b)      catch里面应该有针对性的异常处理,不要把一切交给父异常Exception处理。甚至不使用,出错了就停止程序,我们去处理程序。为了代码的严谨性。

c)      对方声明几个异常,就对应有几个catch块,如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面,不要定义多余的catch块。

d)      建议在进行catch处理时,catch中一定要定义具体处理方式。不要简单定义一句e.printSrackTrace(),也不要简单的就书写一条输出语句。在实际开发中我们要对异常进行处理。

我们看看多异常处理的代码:

class Demo

{

    public int div(int a,intb)throws ArithmeticException,ArrayIndexOutOfBoundsException{  

       /*

   数组越界异常

   */

           int[] array=newint[a];

           System.out.println(array[2]);

       /*

   除零异常

   */

    return a/b;

}

}

class ThrowsExceptionTest

{

public static voidmain(String[] args)

{

           try{

           Demo d=new Demo();

           int x=d.div(3,0);

           System.out.println(x);

           }catch(ArithmeticExceptione){  

              System.out.println(e.toString());  //处理除零异常

              System.out.println("除零了");

           }catch(ArrayIndexOutOfBoundsExceptione){  //处理数组越界异常

            System.out.println(e.toString());

               System.out.println("数组越界异常");

           }catch(Exception e){

               System.out.println("otherException");  //实际不建议使用,且不能放在catch块第一行

           }

}

}

自定义异常

什么是自定义异常?因为项目中会出现特有的问题,而这些问题并未被java所描述并封装对象。所以对于这些特有的问题可以按照java的对问题封装的思想,将特有的问题,进行自定义的异常封装。

我们如何去自定义异常呢?

 

我们看一下以下程序的需求,在这段程序中,对与除数是-1,也视为是错误的是无法进行运算的。那么就需要对这个问题进行自定义的描述。

classCustomException

{

         public static void main(String[] args)

         {

                   Divisor d=new Divisor();

                   try{

                   int num=d.divisor(4,-1);

                   System.out.println(num);

                   }catch(NegativeException e){

                        System.out.println(e.toString());

                             System.out.println("不能除以负数");

                   }

         }

}

class Divisor

{

 

    public int divisor(int a,int b) throws  NegativeException{ //必须要抛出异常,否则编译错误

                   if(b<0){

                      throw new NegativeException();  //抛出自定义异常,使用throw

                   }

           return a/b;

         }

   

}

class NegativeException extends Exception  //自定义除以负数异常

{

}

 

以上代码中,当在函数内部出现了throw关键字常对象,那么就必须要给对应的处理动作。要么在函数上声明让调用者处理。

一般情况下,函数内出现异常,函数上需要声明。

 

我们发现打印的结果中没有只有异常的名称,却没有异常的信息,因为自定义的异常并未自定义信息。

如何自定义异常信息呢?我们先看看如下代码?

classCustomException

{

         public static void main(String[] args)

         {

                   Divisor d=new Divisor();

                   try{

                   int num=d.divisor(4,-9);

                   System.out.println(num);

                   }catch(NegativeException e){

                        System.out.println(e.toString());

                             System.out.println("不能除以负数");

                             System.out.println("this is negative"+e.getValue());  //调用自定义方法

                   }

         }

}

class Divisor

{

 

    public int divisor(int a,int b) throws  NegativeException{ //必须要抛出异常,否则编译错误

                   if(b<0){

                      throw new NegativeException("/by nagative",b);  //抛出自定义异常,使用throw,

                   }

           return a/b;

         }

   

}

classNegativeException extends Exception  //自定义除以负数异常

{

         int value;  //自定义一个值

        

         NegativeException(String msg, intvalue){    //自定义构造方法

          super(msg);//super调用父类中的构造方法

      this.value=value;

         }

 

         public int getValue(){  //子类自定义一个获取方法

          return value; 

         }

}

通过以上代码我们知道了如何自定义信息?因为父类中已经把异常信息的操作都完成了,所以子类只要在构造时,将异常信息传递给父类,是通过super语句,那么就可以直接通过getMessage方法获取自定义的异常信息。

 

总结:当我们自定义异常,必须是自定义类去继承Exception或者Throwable,Error。为什么要继承Exception呢,异常体系中有一个特点,因为异常类和异常对象都需要被抛出,他们都具备可抛性这个可抛性是Throwable这个体系中独有的特点,只有这个体系中的类和对象才可以被throwthrows操作。

 

 

throws和throw的区别:

a)      throws是使用方法上,throws后面跟的是异常类,可以跟多个,用逗号隔开

b)      throw是使用在方法内,throw后跟的是异常对象。

 

RuntimeException

Exception中有一个特殊的子类异常RuntimeException运行时异常。它和别的异常有种特殊的意义在里面。

a)  如果在方法内容抛出该异常,方法上可以不用声明,编译也一样通过。

b)  如果在方法上声明了该异常,调用者可以不用进行处理。编译一样通过。

如以下例子:

classRuntimeExceptionTest

{

         public static void main(String[] args)

         {

                   Divisor2 d=new Divisor2();

                   int num=d.divisor(3,0);

                   System.out.println(num);

         }

}

class Divisor2

{

                   public int divisor(int a,intb) {

                            if(b==0){

                      throw new ArithmeticException("除零了");//ArithmeticException是RuntiemException的子类,如果是new Exception程序出错

                   }

           return a/b;

         }

}

注意:我们之所以不用在方法上声明,是因为不需要让调用者处理。当该异常发生,我们希望该程序去停止?为什么呢?因为在运行时,出现了无法继续运算的情况,希望停止程序后,让我们程序员对代码进行修正。

 

我们来看看自定义异常去继承RuntimeException是什么情况?

class RuntimeExceptionTest

{

public static voidmain(String[] args)

{

           Divisor2 d=newDivisor2();

           intnum=d.divisor(3,-9);

           System.out.println(num);

}

}

class Divisor2

{

           public intdivisor(int a,int b) {    //这里不用写throws CustomsException2

                    if(b<0){

                      throw new CustomsException2("除以负数啦");

                    }

                    if(b==0){

              throw new ArithmeticException("除零了");//ArithmeticException是RuntiemException的子类

           }

   return a/b;

}

}

class CustomsException2 extends RuntimeException{  //自定义异常去继承RuntimeException

String msg;

CustomsException2(String msg){

  this.msg=msg;    

}

}

从以上代码可以总结:当我们自定义异常时,如果该异常的一旦发生,无法再继续进行运算,就让该自定义异常继承RuntimeException。

 

 

总结:对于异常我们分为两种:

a)   编译时被检测的异常

b)   编译时不被检测的异常(运行时异常,RuntimeException以及其子类)

 

finally代码块

finally代码块是用来定义一个一定执行的代码块,通常用于关闭资源。finally是一定会执行的

如以下例子:

classFinallyTest

{

         public static void main(String[] args)

         {

                   Demo d=new Demo();

                   try{

                   int num=d.method(4,0);

          System.out.println(num);

                   }catch(Exception e){

                      System.out.println(e.getMessage());

                   }finally{   //这段代码一定会被执行

                     System.out.println("这段代码一定会被执行");

                   }

                   System.out.println("over");

         }

}

class Demo

{

         public int  method(int a,int b){

      return a/b;

         }

 

}

 

关于异常处理的格式总共有三种:

第一个格式:

try{

}catch(){

}

第二个格式:

try{

}catch(){

}finally{

}

第三个格式:

try{

}finally{

}

记住一点:catch是用于处理异常,如果没有catch就代表异常没有被处理过,如果该异常是检测时异常,那么必须声明。

 

 

异常-覆盖

异常在子父类覆盖中的体现:

1.      子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类

 如以下代码:

class Father  //父类

{

   public void method() throwsFatherException{

  

   }

}

class child extends Father //子类

{

    public void method()throws ChildException{  //如果子类复写父类方法,必须抛父类已抛的异常

           //或者是这个异常的子异常,不能抛其他异常。也可以不抛异常

}

}

 

class FatherException extends Exception   //父异常

{

 

}

class ChildException extends FatherException  //子异常

{

 

}

2.      如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集或者不抛异常

3.      如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类发生异常,就必须进行try处理,绝对不能抛。

异常的总结

异常是什么?异常是对问题的描述。将问题进行对象的封装

异常体系:

      Throwable

            |--Error

           |--Exception

              |--RuntimeException

 

异常体系中的特点:异常体系中的所有类以及建立的对象都具备可抛性。也就是说可以被throw和throws关键字所操作。只有异常体系具备这个特点。

 

 

 

throw和throws的用法:

a)   throw定义在方法内,用于抛出异常对象,当方法内容有throw抛出异常对象,并未被进行try处理,必须要在方法上声明,否则都是编译失败,注意,RuntimeException除外,也就是说,方法内如果抛出的RuntimeException异常,方法上可以不用声明。如果方法声明了异常,调用者需要进行处理,处理方法可以throws可以try。

b)   throws定义在方法上,用于抛出异常类,可以抛出多个,它们用逗号分隔开。

 

异常有两种:

a)  编译是被检测异常。该异常在编译时,如果没有处理(没有抛没有try),编译失败该异常被标识,代表这可以被处理

b)  运行时异常(编译时不检测)。在编译时,不需要处理,编译器不检查。该异常的发生,建议不处理,让程序停止,需要对代码进行修正

 

 

异常处理语句:

第一个格式:

try{

}catch(){

}

第二个格式:

try{

}catch(){

}finally{

}

第三个格式:

try{

}finally{

}

注意:1. Finally中定义的通常是关闭资源代码,因为资源必须释放

 2. finally只有一种情况不会执行。当执行到Syetem.exit(0);finally不会执行。

 

自定义异常

定义类继承Exception或者RuntimeException

1.      为了让该自定义类具备可抛性

2.      让该类具备操作异常的共性方法

当药定义自定义异常的信息时,可以使用父类已经定义好的功能。

异常异常信息传递给父类的构造方法:

classMyException extends Exception

   MyException(String message){

super(message);

自定义异常:按照java的面向对象思想,将程序中出现的特有问题进行封装

 

 

异常的好处:

a)  将问题进行封装

b)  将正常流程代码和问题处理代码相分离,方便与阅读

 

异常的处理原则:

a)  处理方式有两种:try和throws

b)  调用到抛出异常的功能是,抛出几个,就处理几个。

一个try对应多个catch。

c)  多个catch,父类的catch放到最下面。

d)  catch内,需要定义针对性的处理方式,不要简单的定义printStackTrace,输出语句。也不要不写

当捕获到的异常,本功能处理不了时,可以继续在catch中抛出

try{

 throw new AException

}catch(){

 throw e

如果该异常处理不了,但并属于该功能出现的异常可以将异常转换后,在抛出和该功能相关的异常。

或者异常可以处理,当需要将异常产生的和本功能的相关的问题提供出去,当调用者知道,并处理,也可以将捕获异常处理后,转换新的异常

try{

throw new AException();

}catch(AException){

//对AException先处理

throw new BException();

比如说汇款的例子。

 

异常的注意事项:

在子父类覆盖时:

1.      子类抛出的异常必须是父类的异常的子类或者子集

2.      如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try不能抛。

 

 

 

练习1:毕老师上课:

class  ExceptionTest2

{

         public static void main(String[] args)

         {

                   Teacher t=new Teacher("毕老师");

                   try{

                   t.teach();

                   }catch(NoPlanException e){

                       System.out.println("换老师或者换电脑,放假");

                   }

         }

}

classTeacher   //老师

{

         public static String name;   //老师姓名

         private Computer c;

 

   Teacher(){  

  

   }

 

         Teacher(String name){

         this.name=name;

 

         c=new Computer();

 

         }

 

         public void teach() throwsNoPlanException{

 

                   try{

                            c.run();

                   }catch(ComputerSmokingExceptione){

                            System.out.println(e.getMessage());

                            doTest();

                       throw new NoPlanException("课时无法继续");

                   }catch(ComputerBlueScreenExceptione){

                            System.out.println(e.getMessage());

                           c.reset();

                   }

 

          System.out.println(name+"讲课");

         }

 

    public void doTest(){

           System.out.println(Teacher.name+"让学生去做练习");

         }

}

/*

变量state代表了电脑状态

0数字:电脑状态正常

1数字:电脑状态蓝屏

2数字:电脑状态冒烟

*/

 

classComputer  //电脑

{

         int state=2; 

         Teacher t=new Teacher();  

         public void run() throwsComputerBlueScreenException,ComputerSmokingException{  

                   if (state==1)   //电脑状态为1,蓝屏

                   {

            throw newComputerBlueScreenException("电脑蓝屏了");

                   }else if(state==2){   //电脑状态为2,冒烟了

                         throw new ComputerSmokingException("电脑冒烟了");

                   }else if(state==0){

                                     System.out.println("电脑正常运行");

                   }

         }

 

         public void reset(){

          System.out.println(t.name+"重启电脑");

          }

 

}

 

/*

 

自定义异常:

1.电脑冒烟异常

2.电脑蓝屏异常

3.课时无法继续异常

*/

 

class ComputerSmokingExceptionextends Exception   //电脑冒烟异常

{

         ComputerSmokingException(String msg){

            super(msg);

         }

 

}

 

classComputerBlueScreenException extends Exception//电脑蓝屏异常

{

 

                   ComputerBlueScreenException(Stringmsg){

                      super(msg);

                   }

 

}

 

class NoPlanExceptionextends Exception  //课时无法继续异常

{

    NoPlanException(String msg){

           super(msg);

         }

}

 

练习二:计算圆和长方形的面积

class  Test2

{

         public static void main(String[] args)

         {

                   Rec r=new Rec(1,4);

                   r.area();

 

                   Circle c=new Circle(0);

                   c.area();

         }

}

 

 

 

interface Shape{

   public void area();

}

/*

长方形面积

*/

class Recimplements Shape

{

         int wid,hei;//长方形的长和高

         Rec(int wid,int hei){

                   if(wid<=0||hei<=0){

                   throw newIllegalValueException("非法字符");

                   }

           this.wid=wid;

           this.hei=hei;

         }

   public void area(){

      System.out.println("长方形的面积area=="+wid*hei);

   }

 

}

 

class Circleimplements Shape

{

         int r;

         private final static double PI=3.14;

         Circle(int r){

         if(r<=0){

          throw new IllegalValueException("非法字符");

         }

         this.r=r;

         }

         public void area(){

            System.out.println("三角形的面积是=="+r*PI);

         }

}

 

 

 

 

classIllegalValueException extends RuntimeException  //非法字符异常

{

       IllegalValueException(String msg){

                super(msg);

           }

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值