Java面向对象——异常

遇到ArithmeticException时,会直接结束。通常可尝试通过使用if-else语句对各种异常情况进行判断。

 

缺点:

会使代码臃肿,加入了大量的异常情况判断和处理代码。

把精力放在了处理异常上也就是”堵漏洞“上,减少了编写业务的时间,必然影响开发效率。(如果堵漏洞的工作由系统进行处理,用户只关注业务编写,那对于异常只需要调用相关的异常处理就好)

很难关注到所有的异常情况,程序仍不完善。

异常处理和业务交织在一起,影响代码的可读性,大大增加了日后的代码维护性。

异常:

就是在程序的运行过程中所产生的不正常的事件,例如所需文件未找到、网络连接异常或中断、算术运算出错【如:被零整除】、数组小标越界、装载不存在的类、对null对象的操作 、类型转换异常等。常一般会中断正在运行的程序。、

异常的处理:

Java处理异常时通过五个关键字来实现的:try、catch、finally、throwthrows。

try-catch块

把可能存在异常的代码放入try中,并使用catch捕获异常

可能出现的三种情况:

  1. try中所有语句正常执行,不会发生异常。那么catch中的所有语句都会被忽略。
  2. try在执行中遇到异常,并且这个异常与catch中的异常类型相匹配。那么try中剩下的代码将会被忽略,而catch中的相应语句将被执行。【匹配值的是catch所处理的异常类型与所产生的异常类型完全一致或是它的父类】
  3. try语句在执行中遇到异常,而抛出的异常在catch里没有被声明,程序将直接退出。

 

常见的异常类型

异常层次结构的跟类:Exception

算术异常类:ArithmeticExecption
空指针异常类:NullPointerException
类型强制转换异常:ClassCastException
数组负下标异常:NegativeArrayException
数组下标越界异常:ArrayIndexOutOfBoundsException

欲得到的数据类型与实际输入的类型不匹配:InputMismatchException

方法接收到非法参数:illegalArgumentException
违背安全原则异常:SecturityException
文件已结束异常:EOFException
文件未找到异常:FileNotFoundException
字符串转换为数字异常:NumberFormatException
操作数据库异常:SQLException
输入输出异常:IOException
方法未找到异常:NoSuchMethodException
java.lang.AbstractMethodError
抽象方法错误。当应用试图调用抽象方法时抛出。
java.lang.AssertionError
断言错。用来指示一个断言失败的情况。
java.lang.ClassCircularityError
类循环依赖错误。在初始化一个类时,若检测到类之间循环依赖则抛出该异常。
java.lang.ClassFormatError
类格式错误。当Java虚拟机试图从一个文件中读取Java类,而检测到该文件的内容不符合类的有效格式时抛出。
java.lang.Error
错误。是所有错误的基类,用于标识严重的程序运行问题。这些问题通常描述一些不应被应用程序捕获的反常情况。
java.lang.ExceptionInInitializerError
初始化程序错误。当执行一个类的静态初始化程序的过程中,发生了异常时抛出。静态初始化程序是指直接包含于类中的static语句段。
java.lang.IllegalAccessError
违法访问错误。当一个应用试图访问、修改某个类的域(Field)或者调用其方法,但是又违反域或方法的可见性声明,则抛出该异常。
java.lang.IncompatibleClassChangeError
不兼容的类变化错误。当正在执行的方法所依赖的类定义发生了不兼容的改变时,抛出该异常。一般在修改了应用中的某些类的声明定义而没有对整个应用重新编译而直接运行的情况下,容易引发该错误。
java.lang.InstantiationError
实例化错误。当一个应用试图通过Java的new操作符构造一个抽象类或者接口时抛出该异常.
java.lang.InternalError
内部错误。用于指示Java虚拟机发生了内部错误。
java.lang.LinkageError
链接错误。该错误及其所有子类指示某个类依赖于另外一些类,在该类编译之后,被依赖的类改变了其类定义而没有重新编译所有的类,进而引发错误的情况。
java.lang.NoClassDefFoundError
未找到类定义错误。当Java虚拟机或者类装载器试图实例化某个类,而找不到该类的定义时抛出该错误。
java.lang.NoSuchFieldError
域不存在错误。当应用试图访问或者修改某类的某个域,而该类的定义中没有该域的定义时抛出该错误。
java.lang.NoSuchMethodError
方法不存在错误。当应用试图调用某类的某个方法,而该类的定义中没有该方法的定义时抛出该错误。
java.lang.OutOfMemoryError
内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。
java.lang.StackOverflowError
堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误。
java.lang.ThreadDeath
线程结束。当调用Thread类的stop方法时抛出该错误,用于指示线程结束。
java.lang.UnknownError
未知错误。用于指示Java虚拟机发生了未知严重错误的情况。
java.lang.UnsatisfiedLinkError
未满足的链接错误。当Java虚拟机未找到某个类的声明为native方法的本机语言定义时抛出。
java.lang.UnsupportedClassVersionError
不支持的类版本错误。当Java虚拟机试图从读取某个类文件,但是发现该文件的主、次版本号不被当前Java虚拟机支持的时候,抛出该错误。
java.lang.VerifyError
验证错误。当验证器检测到某个类文件中存在内部不兼容或者安全问题时抛出该错误。
java.lang.VirtualMachineError
虚拟机错误。用于指示虚拟机被破坏或者继续执行操作所需的资源不足的情况。
java.lang.ArithmeticException
算术条件异常。譬如:整数除零等。
java.lang.ArrayIndexOutOfBoundsException
数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
java.lang.ArrayStoreException
数组存储异常。当向数组中存放非数组声明类型对象时抛出。
java.lang.ClassCastException
类造型异常。假设有类A和B(A不是B的父类或子类),O是A的实例,那么当强制将O构造为类B的实例时抛出该异常。该异常经常被称为强制类型转换异常。
java.lang.ClassNotFoundException
找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。
java.lang.CloneNotSupportedException
不支持克隆异常。当没有实现Cloneable接口或者不支持克隆方法时,调用其clone()方法则抛出该异常。
java.lang.EnumConstantNotPresentException
枚举常量不存在异常。当应用试图通过名称和枚举类型访问一个枚举对象,但该枚举对象并不包含常量时,抛出该异常。
java.lang.Exception
根异常。用以描述应用程序希望捕获的情况。
java.lang.IllegalAccessException
违法的访问异常。当应用试图通过反射方式创建某个类的实例、访问该类属性、调用该类方法,而当时又无法访问类的、属性的、方法的或构造方法的定义时抛出该异常。
java.lang.IllegalMonitorStateException
违法的监控状态异常。当某个线程试图等待一个自己并不拥有的对象(O)的监控器或者通知其他线程等待该对象(O)的监控器时,抛出该异常。
java.lang.IllegalStateException
违法的状态异常。当在Java环境和应用尚未处于某个方法的合法调用状态,而调用了该方法时,抛出该异常。
java.lang.IllegalThreadStateException
违法的线程状态异常。当县城尚未处于某个方法的合法调用状态,而调用了该方法时,抛出异常。
java.lang.IndexOutOfBoundsException
索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时,抛出该异常。
java.lang.InstantiationException
实例化异常。当试图通过newInstance()方法创建某个类的实例,而该类是一个抽象类或接口时,抛出该异常。
java.lang.InterruptedException
被中止异常。当某个线程处于长时间的等待、休眠或其他暂停状态,而此时其他的线程通过Thread的interrupt方法终止该线程时抛出该异常。
java.lang.NegativeArraySizeException
数组大小为负值异常。当使用负数大小值创建数组时抛出该异常。
java.lang.NoSuchFieldException
属性不存在异常。当访问某个类的不存在的属性时抛出该异常。
java.lang.NoSuchMethodException
方法不存在异常。当访问某个类的不存在的方法时抛出该异常。
java.lang.NullPointerException
空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。
java.lang.NumberFormatException
数字格式异常。当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常。
java.lang.RuntimeException
运行时异常。是所有Java虚拟机正常操作期间可以被抛出的异常的父类。
java.lang.SecurityException
安全异常。由安全管理器抛出,用于指示违反安全情况的异常。
java.lang.StringIndexOutOfBoundsException
字符串索引越界异常。当使用索引值访问某个字符串中的字符,而该索引值小于0或大于等于序列大小时,抛出该异常。
java.lang.TypeNotPresentException
类型不存在异常。当应用试图、

try-catch-finally

无论是否存在异常,finally总能被执行。

大致分两种情况:

  1. 所有语句正常执行,finally就会被执行。
  2. 如果执行中遇到异常,无论这种异常是否被catch捕获到,都将执行finally中的代码。

try在代码块中是必须的,catch和finally是可选的,但两者至少必须出现一个。

try和catch中存在return时,finally也会被执行

发生异常时的顺序:try或catch中return之前的语句,finally,执行try或catch中的return退出。

finally中语句不被执行的唯一情况:在异常处理中执行System.exit(1),将退出虚拟机。

java的System.exit(0)和System.exit(1)区别。

System.exit(int  status)这个方法是用来结束当前正在运行中的java虚拟机。

status是非零参数,那么表示是非正常退出。

System.exit(0)是正常退出程序,而System.exit(1)或者说非0表示非正常退出程序。

在一个if-else判断中,如果我们程序是按照我们预想的执行,到最后我们需要停止程序,那么我们使用System.exit(0),而System.exit(1)一般放在catch块中,当捕获到异常,需要停止程序,我们使用System.exit(1)。这个status=1是用来表示这个程序是非正常退出。

多重catch

一段代码的引发的多种类型的异常。可以在try后面添加多个catch。分别处理不同的异常。但顺序必须时从子类到父类。最后一个通常都是Exception类。因为所有子类都是继承Exception,所以将父类异常放到前面,那么所有的异常都将被捕获,后面catch中的子类异常将得不到执行的机会。

代码遇到异常时执行第一个与异常相匹配的catch之后,其余都将被忽略。

try{ 

 // 程序代码

}catch(异常类型1 异常的变量名1){

// 程序代码

}catch(异常类型2 异常的变量名2){

// 程序代码

}finally{

// 程序代码

}

声明异常——throws

可通过throws声明某个方法可能抛出的各种异常。throws可以同时声明多个异常。

抛出异常,可采用的一下两种方式处理:

通过try-catch捕获并处理异常。

通过throws继续声明异常。如果调用者不打算处理该异常,则可通过throws声明异常,让调用者处理异常。

抛出异常——throw

throw是用来自行抛出异常,把问题交给调用者处理。

throw和throws的区别

作用不同:throw用于在程序中抛出异常;throws用于声明在该方法内抛出了异常。

使用的位置不同:throw位于方法体内部,可以作为单独语句使用;throws必须跟在方法参数列表的后面,不能单独使用。

内容不同:throw抛出一个异常对象,而且只能是一个;throws后面跟异常类,而且可以跟多个异常类。

抛出异常有三种形式

  • throw
  • throws
  • 系统自动抛异常

一、系统自动抛异常

当程序语句出现一些逻辑错误、主义错误或类型转换错误时,系统会自动抛出异常:(举个栗子)

public static void main(String[] args) { 
    int a = 5, b =0; 
    System.out.println(5/b);   // 此处系统会自动抛出ArithmeticException异常
    //function(); 
}

二、throw

throw是语句抛出一个异常,一般是在代码块的内部,当程序出现某种逻辑错误时由程序员主动抛出某种特定类型的异常

public static void main(String[] args) { 
    String s = "abc"; 
    if(s.equals("abc")) { 
      throw new NumberFormatException(); 
    } else { 
      System.out.println(s); 
    } 
    //function(); 
}


运行时,系统会抛出如下异常:

Exception in thread "main" java.lang.NumberFormatException at......
1
三、throws

当某个方法可能会抛出某种异常时用于throws 声明可能抛出的异常,然后交给上层调用它的方法程序处理

public class testThrows(){
public static void function() throws NumberFormatException { 
    String s = "abc"; 
    System.out.println(Double.parseDouble(s)); 

 
public static void main(String[] args) { 
    try { 
        function(); 
    } catch (NumberFormatException e) { 
        System.err.println("非数据类型不能强制类型转换。"); 
        //e.printStackTrace(); 
    } 
}


运行结果如下:

非数据类型不能强制类型转换。
1
四、throw与throws的比较

throws出现在方法函数头;而throw出现在函数体。
throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常对象。
两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。
五、编程习惯:

在写程序时,对可能会出现异常的部分通常要用try{…}catch{…}去捕捉它并对它进行处理;
用try{…}catch{…}捕捉了异常之后一定要对在catch{…}中对其进行处理,那怕是最简单的一句输出语句,或栈输入e.printStackTrace();用try{…}catch{…}捕捉了异常之后一定要对在catch{…}中对其进行处理,那怕是最简单的一句输出语句,或栈输入e.printStackTrace();
如果是捕捉IO输入输出流中的异常,一定要在try{…}catch{…}后加finally{…}把输入输出流关闭;如果是捕捉IO输入输出流中的异常,一定要在try{…}catch{…}后加finally{…}把输入输出流关闭;
如果在函数体内用throw抛出了某种异常,最好要在函数名中加throws抛异常声明,然后交给调用它的上层函数进行处理。如果在函数体内用throw抛出了某种异常,最好要在函数名中加throws抛异常声明,然后交给调用它的上层函数进行处理。
 

异常的分类

上图可以简单展示一下异常类实现结构图,当然上图不是所有的异常,用户自己也可以自定义异常实现。上图已经足够帮我们解释和理解异常实现了:

1.所有的异常都是从Throwable继承而来的,是所有异常的共同祖先,而它的祖先时Object。

2.Throwable有两个子类,ErrorException。其中Error是错误,对于所有的编译时期的错误以及系统错误都是通过Error抛出的。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。

3.Exception,是另外一个非常重要的异常子类。它规定的异常是程序本身可以处理的异常。异常和错误的区别是,异常是可以被处理的,而错误是没法处理的。 下分两大类:checked 编译时异常。unchecked 运行时异常。

4.Checked Exception

可检查的异常,这是编码时非常常用的,所有checked exception都是需要在代码中处理的。它们的发生是可以预测的,正常的一种情况,可以合理的处理。比如IOException,或者一些自定义的异常。除了RuntimeException及其子类以外,都是checked exception。IOException会强制进行处理异常。

5.Unchecked Exception

RuntimeException及其子类都是unchecked exception。比如NPE空指针异常,除数为0的算数异常ArithmeticException等等,这种异常是运行时发生,无法预先捕捉处理的。Error也是unchecked exception,也是无法预先处理的。

日志记录工具log4

 

日志记录内容:

  1. SQL日志:记录系统执行的SQL语句。
  2. 异常日志:记录系统运行中发生的异常事件。
  3. 业务日志:记录系统运行过程,如用户登录、操作记录。

log4j配置文件:

输出级别

log4j.rootLogger = debug,stdout,logfile、

debug指的是日志记录器(Loggerr)的输出级别,主要输出级别及含义如下。

  • fatal:指出严重的错误事件将会导致应用程序的退出。
  • error:指出虽然发生错误事件,但仍然不影响系统的继续运行。
  • warn:表明会出现潜在错误的情形。
  • info:在粗粒度级别上指明消息,强调应用程序的运行过程。
  • debug:指出细粒度信息事件,对调试应用程序时非常有帮助的。

log4j各输出级别优先级为debug<info<warn<error<fatal

日志记录器(Logger)将只输出那些级别高于或等于它的信息。

日志输出的目的地Appender

log4j.rootLogger = debug,stdout,logfile

其中stdout,logfile指的是日志输出目的地的名字。

log4j中最常用的Appender有两种:

  1. Console Appender:输出日志事件到控制台。通过Target属性配置输出到System.outSystem.err。默认是System.out
  2. FileAppender:输出日志事件到一个文件。通过File属性配置文件的路径及名称。

日志布局类型Layout

Appender必须使用一个与之相关联的布局类型Layout,用来指定它的输出样式。

最常用的三种:

  1. HTMLLayout:格式化日志输出为HTML表格。
  2. SimpleLayout:以一种非常简单的方式格式化日志输出,它输出的级别Level,然后跟着一个破折号“——”,最后是日志消息。
  3.  PatternLayout:根据指定的转换模式格式化日志输出,从而支持丰富多样的输出格式。需要配置layout.ConversionPattern属性,若没有配置该属性,则使用默认的转换模式。

转换模式ConversionPattern

%d:用来设置输出日志的日期和时间
%m:用来输出代码中指定的消息
%n:用来输出一个回车换行符
%l:用来输出日志事件的发生位置
%p:用来输出优先级
%f:用来输出文件名
%m:用来输出方法名 

%m 输出代码中指定的消息

%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL

%r 输出自应用启动到输出该log信息耗费的毫秒数

%c 输出所属的类目,通常就是所在类的全名

%t 输出产生该日志事件的线程名

%n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”

%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921

%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值