黑马程序员_Java基础_面向对象(五)_09

时间:2023-02-13 23:49:30
                                       ------- android培训java培训、期待与您交流! ----------

 

导读:异常概述,处理(try-catch常见方法操作,多异常的处理,异常声明throws, 自定义异常,throwthrows的区别,RuntimeException,异常练习(电脑让课),异常finally

 

1、异常概述

l  异常:就是程序在运行时出现不正常情况,并且在不正常处程序结束了。

l  异常由来:问题也(一个问题产生后,它即有问题的原因,又有问题的现象,还有问题的信息)是现实生活中一个具体的事物,也可以通过java的类的形式进行描述。异常就是用面向对象的方法,把产生的问题进行描述,并对其进行对象的封装成。其实就是java对不正常情况进行描述后的对象体现。

l  对于问题的划分:两种:一种是严重的问题,一种非严重的问题。

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

Ø  对与非严重的,java通过Exception类进行描述(对于Exception可以使用针对性的处理方式进行处理)。

l  无论Error或者Exception都具有一些共性内容。比如:不正常情况的信息,引发原因等。(向上抽取,形成体系)

l  Throwable  (它是java中所有错误或异常的超类,定义了体系的共性内容)

       |--Error  通常出现重大问题如:运行的类不存在或者内存溢出等。不编写针对代码对其处理

       |--Exception   java为了便于阅读性,将父类的名字做为子类的后缀名

方法:

getCause()   //获取原因

getMessage() //获取异常或者错误的信息

printStackTrace()//打印这些信息。获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void

     printStackTrace(PrintStream s)通常用该方法将异常内容保存在日志文件中,以便查阅。       toString()//将内容变为字符串(复写自Object),获取异常类名和异常信息,返回字符串    OutOfMemoryError内存溢出(虚拟机启动的时候会有一个默认大小的内存的空间)

NoClassFoundErrorr找不到对应的class或者java文件

ArithmeticException  (4/0)

 

2、异常的处理(try-catch

l  java 提供了特有的语句进行处理。

try   //由三部分代码块组成,这三部分是一个整体。

{

       需要被检测的代码;(检测到异常把它丢给了catchnew ArithmeticException()

}

catch(异常类变量)//catch接收到异常对象。Exception e = newArithmeticException(); 代码跳到catch中去执行。

{

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

}

finally

{

       一定会执行的语句;

}

l  class Demo

{

       int div(int a,int b)  //产生了ArithmeticException并把它封装成了一个对象:newArichmeticException(); ,再把这个问题抛给调用它的主函数。如果主函数中没有try-catch,主函数没办法处理问题,会把这个问题给JVM,JVM调用默认处理机制,导致程序停止。

       {

              return a/b;

       }

}

l  Java虚拟机认识异常,因为这是它定义的。当引发了它所熟悉的状况,就给你处理这是因为Java虚拟机内部有一个异常的处理机制。只要程序出现问题,就不再运行了。

 

3、对捕获到的异常对象进行常见方法操作。

l  String getMessage():获取异常信息[System.out.println(e.getMessage());]

l  System.out.println(e.getMessage());打印的更全面一点即带有打印的信息,也带有打印的名字。(异常信息:异常名字)

l  e.printStackTrace();无返回值,不要放在打钱语句中输出。它最全面(异常信息,异常名字,异常出现的位置)。其实jvm默认的异常处理机制,就是在调用printStackTrace方法。打印异常的堆栈的跟踪信息。

 

4、异常声明throws

l  某功能是别人编写的,一定要做try-catch处理吗?不一定,因为你不知道在哪里会出现异常。

l  对方在用某功能,可是他要传什么是不确定的,那么a/bb==0就有可能会发生。编写功能的人在功能上加上一个throws关键字的标识,说这个程序在运行的时候可能会出现问题

l  声明与不声明有什么不同?

声明了的话,再把异常抛给主函数的时候,主函数必须做出处理,不处理的编译不通过,不让你用。主函数要么将其抛出去,要么进行捕获,才能编译通过。声明的话,传对了就没有事了,传错了就出问题了,运行不过去。

逐级的往上给,传多层都无所为,最后是主函数调用再给虚拟机,到虚拟机这里到头了,虚拟机用默认的方式给解决掉。

l  catch中的处理方式有很多,for循环,调用函数,内部类都没有问题。

l  例:去商店买面包,上面写着,已过三天,可能过期。降价处理,原来三块,现在三毛,你买了。你不吃,给别人吃(throws)。你打开袋子,一会没有长毛,你就把它给吃了(程序正常)。一看面包长毛了,放在微波炉里加热了一下,又给吃了(try-catch)。

 

5、多异常的处理

l  throws Exception的方式声明异常其实不好,如果你知道抛出的异常是算术异常的话,声明的具体一些(声明为ArithmeticException),VM处理的话,会处理的更具体一些。这才是声明的一般的特点。声明多个具体呢,我就会处理多个具体。(如,声明多个异常:throwsArithmeticExceptionArrayIndexOutOfException),声明了几个就要有几个针对性的处理(对应另外几个catch();)。函数当中一有异常发生,这个函数就已经结束了,不可能同时捕获到了多个异常。当如果只用一个catch捕获所有的异常的时候,用catch(Exceptione){},利用的多态性,但是它处理的没有针对性(try-catch的时候里面要写针对性的处理,要有与之对应的catch,看throws中有有几个catch)。

l  在捕获了有针对性的异常后,再写上catch(Exceptione){}好不好?

不好。第一,你都不知道会抛出什么异常,你抛出了之后,相当与把问题隐藏,而程序还在继续运行(出果出现了声明之外的异常,这时应该做的是把程序停掉,我们得知道,到底是在哪里卡住了,到底哪里出问题了,哪个功能是我们要进行修正的)。

l  对多异常的处理。

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

Ø  对方声明几个异常,就对应有几个catch块。不要定义多余的catch块。

如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面(如果父类异常放在最上面的话,其他的catch都是多余的)。

l  建立在进行catch处理时,catch中一定要定义具体处理方式。

Ø  不要简单定义一句e.printStackTrace(),也不要简单的就书写一条输出语句。

Ø  真的发生问题了,我们是不打印的,我们会用一个硬盘文件给它记录下来,这个我们称之为异常日志文件,记录着我们程序每天的一些运行状况(几点几分出现了什么问题代码的维护人员经常看这些日志,进而解决一些bug)。

Ø  我们学习为了方便,我们打印一是看到代码的运行流程,二是能看到代码的运行结果。

 

6、自定义异常

l  Java对特有的异常进行了封装,我们能不能对自己的项目中的对象也进行特有的封装呢?

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

l  当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。要么在内部try catch处理。要么在函数上声明让调用者处理。主函数在调用一个声明异常的方法的话,主函数也有两个方式,要么try-catch要么抛。

l  System.out.prinltn(“e.toString()”);发现打印的结果中只有异常的名称,却没有异常的信息。因为自定义的异常并未定义信息。

l  继承Exception原因:(当然也可以继承自Error

异常体系有一个特点:因为异常类和异常对象都被抛出(因为他们会倒导致程序的跳转),他们都具备可抛性。这个可抛性是Throwable这个体系中独有特点。只有这个体系中的类和对象才可以被throwsthrow操作。

l  自定义异常,需求:

在本程序中,对于除数是-1,也视为是错误的是无法进行运算的。

那么就需要对这个问题进行自定义的描述。

//要继承自Exception去这个体系中就有了异常的特性,有了异常中的那些方法。定义的目的就是为了生成对象。我们自定义的异常Java不认识,这时就要求我们手动的建立对象,并进行抛出。Java的异常可以手动抛出,也可以由Java自动的抛出。

class FuShuExceptionextends Exceptio//自定义异常:必须是自定义类继承Exception

{

       private int value;

       FuShuException()

       {

              super();

       }

/*

如何定义异常信息呢?

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

*/

       FuShuException(String msg,int value)

       {

              super(msg);

              this.value = value;

       }

       public int getValue()   //获取负数异常的负数的值。

       {

              return value;

       }

}

class Demo

{

       int div(int a,int b)throws FuShuException

       {

              if(b<0)

                     throw newFuShuException("出现了除数是负数的情况------ / by fushu",b);//手动通过throw关键字抛出一个自定义异常对象。

              return a/b;

       }

}

小技巧:在编译的时候,但凡出现:“未报告的异常FuShuException;必须对其进行捕获或抛出”,这个错误的提示话,恭喜你,你已经进入到了语法错误的最后的环节了。

class  ExceptionDemo3

{

       public static void main(String[] args)

       {

              Demo d = new Demo();

              try

              {

                     int x = d.div(4,-9);

                     System.out.println("x="+x);           

              }

              catch (FuShuException e)

              {

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

                     System.out.println("错误的负数是:"+e.getValue());//e.getValue()这是自定义异常中所特有的方法

              }

              System.out.println("over");

       }

}

/*

class Throwable  //Throwable的子类Error中有一个构造方法Error(Stringmsg);

{

       private String message;

       Throwable(String message)

       {

              this.message = message;

       }

       public String getMessage()

       {

              return message;

       }

}

class Exceptionextends Throwable  //Exception继承自父类Throwable,当传入msg后,就要利用父类中的getMessage()方法获得字符串信息。

{

       Exception(String message)

       {

              super(message);

       }

}

*/

 

7throwthrows的区别

l  位置不同:throws使用在函数上[写在“{”之间] throw使用在函数内。

l  跟班不同:throws后面跟的异常类(可以跟多个用逗号隔开)。throw后跟的是异常对象。

 

8RuntimeException

l  ArithmeticExceptionextends RuntimeException,算术异常有两个构造方法,一个是空参数的(ArithmeticException()),一个是带参数的(ArithmeticException(Strings),可自定义).

l  int div(int a,int b)

{

if(b<0)

              thrownew ArithmeticException(“被零除了”);

       return a/b;

}

Ø  throw new ArithmeticException(“被零除了”);这条语句为什么不声明,也能编译能过,而写成throw newException(“被零除了”);不能编译通过呢?

ArithmeticExceptionextends RuntimeException,只有这个异常的子类是非常特殊的RuntimException及它的子类,如果在函数内抛出了,函数上不用声明。

l  int div(int a,int b)throws ArithmeticException

{

Return a/b;  //主函数什么也没做,也没有问题。

}

Ø  Exceptoin中有一个特殊的子类异常RuntimeException 运行时异常。如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过。如果在函数上声明了该异常。调用者可以不用进行处理。编译一样通过;

Ø  之所以不用在函数声明,是因为不需要让调用者处理。当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。

l  对于异常分两种:

Ø  编译时被检测的异常。(在javac编译时期,如果方法中抛出了非runtime异常或者其子类,可是上面没用有throws标识,它就识为有安全隐患的。这些异常是可处理的,要标识出去让调用者处理。如果函数上标识了某些异常的话,调用者必须也要有对应的处理方式,要么抛,要么try。如果没有标识的话,若出现了异常对象,会判断一下是不是RuntimeException,如果是,你标不标识我都不管,程序停下来就好了)

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

l  自定义异常的另一个选择:自定义异常时,如果该异常的发生,无法再继续进行运算,就让自定义异常继承RuntimeException

l  RuntimeException的一个子类NullPointException

固定值和空比没有问题,因为空没有调用方法。

不能throws抛,异常隐藏。我必须让你停掉,看看到底发生什么事情了。

l  RuntimeException的一个子类IndexOutOfBoudsException角标越界。

如果访问到了不存在的角标程序一定要停掉,你要访问的元素都不存在你怎么拿角标去运算。这时候就有必要想下代码。

Ø  角标越界里还有两个小弟:ArrayIndexOutOfBoundsExceptionStringIndexOutOfBoundsException

l  Object类中的一个方法,wait(longtimeout):要等待的最长的时间(ms为单位)。它在函数声明的时候声明了一个InterruputedException(异常发生,可以处理,不会完全影响运算,还可以执行),在抛出的时候却却抛出了三个。还有两个没有声明,IllegalArgumentException()IllegalMonitorStateException,因为它们两个是RuntimeException的小弟(不需要去标识,你只要做了某件事情,我就让程序停下来,因为影响了运算,必须先修正了代码后,再让你运行)

 

9、异常练习

/*

毕老师用电脑上课。开始思考上课中出现的问题。

比如问题是:1.电脑蓝屏      2.电脑冒烟。

要对问题进行描述,封装成对象。可是当冒烟发生后,出现讲课进度无法继续。出现了讲师的问题:课时计划无法完成。

*/

classLanPingException extends Exception

{

       LanPingException(String message)

       {

              super(message);

       }

}

classMaoYanException extends Exception

{

       MaoYanException(String message)

       {

              super(message);

       }

}

classNoPlanException extends Exception

{

       NoPlanException(String msg)

       {

              super(msg);

       }

}

class Computer

{

       private int state = 3;  //设置一具特殊的状态位,表示电脑的状态,很好

       public void run()throwsLanPingException,MaoYanException

       {

              if(state==2)

                     throw newLanPingException("蓝屏了");

              if(state==3)

                     throw newMaoYanException("冒烟了");

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

       }

       public void reset()

       {

              state = 1;

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

       }

}

class Teacher

{

       private String name;

       private Computer cmpt;

       Teacher(String name)

       {

              this.name = name;

              cmpt = new Computer();

       }

       public void prelect()throwsNoPlanException

       {

              try

              {

                     cmpt.run();                

              }

              catch (LanPingException e)

              {

                     cmpt.reset();

              }

              catch (MaoYanException e)  //不能把e抛给张老师,张老师不是电脑维修师,他处理不了。要将冒烟异常转换成我的异常[讲课不能继续],再把它抛给张老师,能被处理。

              {

                     test();  //这句话要先写,若把下面的写在前面的话,test()执行不到。

                     throw newNoPlanException("课时无法继续"+e.getMessage());

                     //throw单独存在的时候页面千万不要写语句因为它就是函数的结束标识了,除了它之外,还有return

              }

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

       }

       public void test()

       {

              System.out.println("练习");

       }

}

classExceptionTest

{

       public static void main(String[] args)

       {

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

              try

              {

                     t.prelect();

              }

              catch (NoPlanException e)

              {

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

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

              }

       }

}

 

10、异常-finally

l  finally代码块:定义一定执行的代码,通常用于关闭资源。(其他功能,某些代码一定要执行一下,可以往这里面放)

l  调用方法的时候要看方法是否抛出了了异常,如果抛出了异常,你可以处理的话,要写try-catch

l  连接数据库,不断开的话,一:你占着服务器的资源,二:你占着服务器的连接。为了让大家都能连接上数据库,在访问数据库后要断开。无论是否在数据库中取到要访问的数据,最后的断开一定要执行。

public voidmethod()throws NoException

{

       try

       {

              连接数据库;

              数据操作;//throw new SQLException();数据库异常

       }

       catch (SQLException e)

       {//数据库异常发生后,这里面可以有特定的数据库异常处理方式(不抛出去,你把我给你的数据往数据库里放,发生了异常,你把数据库异常抛给我。这不合适,我只是拿数据而已,往哪里去存,我不知道,这是你的事。你暴露了你那个程序的封装性)。负责处理数据库层的哥们最清楚要怎么做。

数据库异常捕获到后,可以做什么样的动作?可以做两种动作:

1)会对数据库进行异常处理;

2throw newNoException();

//把问题暴露出去,但不暴露本层的问题,只暴露一个对方能够识别的问题就可以了。这叫做问题的封装(有些问题是要内部处理的,处理完成后,告诉对方结果就可以了)。(2)不可以省。人家要货呢,你把漏水的地方给解决了,可以销售员什么都不知道,而且还没有拿到货。这里有关联性,你没有把关联性的问题给提供出去。

例:销售员告诉仓库管理员说,我要一批货,可以仓库漏水了,货长毛了。仓库管理员要做的就是把漏水的地方修好,之后对销售说,说货没了。

       }

       finally

       {

              关闭数据库;  //该动作,无论数据操作是否成功,一定要关闭资源。

       }

}

l  上机面试的时候,如果涉及到异常的问题,没有做finally的问题,没有做异常的处理,没有进行资源的关闭,程序是有问题,面试官会认为你没有编程经验。

l  JVM可以创建文件,它调的是windowsLinux底层的资源,无论资源有不有创建成功,都要将资源给释放了。


                                     ------- 
android培训java培训、期待与您交流! ----------