当前位置: 首页 > 科技观察

Java程序员必备:异常的十大关键知识点

时间:2023-03-14 11:26:14 科技观察

前言总结了Java异常的十大关键知识点,在面试或者工作中很有用,加油。1、什么是异常?异常是指导致当前方法或作用域无法继续执行的问题。比如读取的文件不存在,数组越界,除法时被除数为0等都会引发异常。找不到文件异常:publicclassTestException{publicstaticvoidmain(String[]args)throwsIOException{InputStreamis=newFileInputStream("jaywei.txt");intb;while((b=is.read())!=-1){}}}运行结果:Exceptioninthread"main"java.io.FileNotFoundException:jaywei.txt(系统找不到指定的文件。)atjava.io.FileInputStream.open0(NativeMethod)atjava.io.FileInputStream.open(FileInputStream.java:195)atjava.io.FileInputStream.(FileInputStream.java:138)atjava.io.FileInputStream.(FileInputStream.java:93)atexception.TestException.main(TestException.java:10)2.异常层次结构曾几何时,有一位名叫Throwable的老人,他有两个儿子,大儿子Error,二儿子Exception。Error表示编译时或系统错误,如虚拟机相关错误、OutOfMemoryError等,错误无法处理。异常代码是异常的,Java程序员关心的基类型通常是Exception。可以由程序自己处理,这是它和Error的区别。可以分为RuntimeException(运行时异常)和CheckedException(可检查异常)。CommonRuntimeException:-NullPointerException空指针异常-ArithmeticException出现异常操作条件时抛出此异常-IndexOutOfBoundsException数组索引越界异常-ClassNotFoundException找不到类异常-IllegalArgumentException(非法参数异常)CommonCheckedException异常:-IOException(异常)操作输入流和输出流时可能出现的)-ClassCastException(类型转换异常类)CheckedException是编译器要求你处理的异常。相比之下,UncheckedExceptions是指编译器不需要强制处理的异常,包括Error和RuntimeException及其子类。3.异常处理当异常发生时,会在堆上创建一个异常对象。当前执行路径终止,并且从当前环境中弹出对异常对象的引用。这时,异常处理程序使程序从错误状态中恢复过来,让程序继续运行。异常处理主要包括抛出异常、捕获异常和声明异常。如图:catchexceptiontry{//程序代码}catch(Exceptione){//Catch块}finally{//无论如何都会执行的代码块}我们可以通过try...catch捕获异常代码。..,然后通过finaly进行最后的操作,比如关闭stream等。声明抛出异常除了try...catch...捕获异常,我们还可以通过throws语句抛出异常。当你定义一个方法时,它可以用throws关键字声明。使用throws关键字表明该方法不处理异常,而是将异常留给其调用者。你觉得TA不负责任吗?哈哈,看看demo//这个方法是通过throws来声明IO异常的。privatevoidreadFile()throwsIOException{InputStreamis=newFileInputStream("jaywei.txt");intb;while((b=is.read())!=-1){}}方法语句抛出的任何异常都必须使用throws子句。抛出异常throw关键字的作用是抛出Throwable类型的异常,一般出现在函数体中。在异常处理中,try语句需要捕获的是一个异常对象。其实这个异常对象本身也是可以抛出的。例如抛出一个RuntimeException类的异常对象:thrownewRuntimeException(e);任何Java代码都可以通过Javathrow语句抛出异常。注意事项Unchecked异常(Error、RuntimeException或其子类)不能使用throws关键字来声明要抛出的异常。当一个方法出现编译期异常时,需要try-catch/throws处理,否则会导致编译错误。4、try-catch-finally-return执行顺序try-catch-finally-return执行说明如果没有异常发生,catch部分不会执行。不管是否发生异常,finally都会被执行。即使try和catch中有return,finally还是会被执行。finally在return后面的表达式计算完成后执行。(此时不返回计算后的值,而是先保存要返回的值,如果finally中没有return,不管finally中的代码,返回值都不会改变,还是保存before.value),此时函数的返回值是在finally执行之前确定的)finally部分不要返回,否则无法返回try或catch的返回值。看一个例子publicstaticvoidmain(String[]args)throwsIOException{System.out.println("result:"+test());}privatestaticinttest(){inttemp=1;try{System.out.println("startexecutetry,tempis:"+temp);return++temp;}catch(Exceptione){System.out.println("startexecutecatchtempis:"+temp);return++temp;}finally{System.out.println("startexecutefinally,tempis:"+temp);++temp;}}运行结果:startexecutetry,tempis:1startexecutefinally,tempis:2result:2分析先执行try部分,输出日志,执行++temp表达式,temp变为2,这个值被保存。因为没有发生异常,所以跳过了catch代码块。执行finally代码块,输出日志,执行++temp表达式。返回try部分保存的值返回Throwable的detailMessage属性,detailMessage表示异常的详细消息描述。例如,当发生FileNotFoundException时,detailMessage包含无法找到的文件的名称。getLocalizedMessage创建此throwable的本地化描述。子类可以覆盖此方法以生成特定于语言环境的消息。对于不覆盖此方法的子类,默认实现返回与getMessage()throwable相同结果的本地化描述。子类可以覆盖此方法以生成特定于语言环境的消息。对于不覆盖此方法的子类,默认实现返回与getMessage()相同的结果。getCause如果原因不存在或未知,则返回此throwable或nullable的原因。返回此throwable或nullifthecauseisnonexistenttounknown的原因。如果原因不存在或未知,则返回null。printStackTrace将此throwable及其回溯打印到标准错误流。输出的第一行包含此对象的toString()方法的结果。剩余的行表示先前由方法fillInStackTrace()记录的数据。此方法将堆栈跟踪信息打印到标准错误流。输出的第一行,包含此对象的toString()方法的结果。剩余的行表示先前由方法fillInStackTrace()记录的数据。下面的例子:java.lang.NullPointerExceptionatMyClass.mash(MyClass.java:9)atMyClass.crunch(MyClass.java:6)atMyClass.main(MyClass.java:3)6.自定义异常自定义异常通常定义一个继承的子类来自异常类。那么,为什么需要自定义异常?Java提供的异常系统并不能预见所有的错误。在业务开发中,使用自定义异常可以让项目代码更加规范,便于管理。下面是一个简单的demopublicclassBizExceptionextendsException{//错误信息privateStringmessage;//错误码privateStringerrorCode;publicBizException(){}publicBizException(Stringmessage,StringerrorCode){this.message=message;this.errorCode=errorCode;}@OverridepublicStringgetMessage(){returnmessage;}publicvoidsetMessage(Stringmessage){this.message=message;}publicStringgetErrorCode(){returnerrorCode;}publicvoidsetErrorCode(StringerrorCode){this.errorCode=errorCode;}}运行一个主要方来测试publicclassTestBizException{(Bvotest)throwsBizException{System.out.println("throwingBizExceptionfromtestBizException()");thrownewBizException("100","兄弟,我错了");}publicstaticvoidmain(String[]args){try{testBizException();}catch(BizExceptione){System.out.println("自定义异常");e.printStackTrace();}}}运行结果:exception.BizException:100throwingBizExceptionfromtestBizException()自定义异常atexception.TestBizException.testBizException(TestBizException(TestBizExceptionn.java:7)atexception.TestBizException.main(TestBizException.java:12)七、Java7新的try-with-resources语句try-with-resources是Java7提供的一个新函数,用于资源自动管理参考程序结束后必须关闭的对象。try-with-resources保证每个声明的资源都将在语句结束时关闭。什么样的对象可以作为资源?只要对象实现了java.lang.AutoCloseable接口或者java.io.Closeable接口,就OK了。在try-with-resources出现之前try{//openresourceslikeFile,Databaseconnection,Socketsetc}catch(FileNotFoundExceptione){//ExceptionhandlinglikeFileNotFoundException,IOExceptionetc}finally{//closeresources}Java7,在try-with-resources出现之后,使用resources实现try(//openresourceshere){//useresources}catch(FileNotFoundExceptione){//异常处理}//resourcesareclosedassoonastry-catchblockisexecuted.Java7使用资源.txt"))){System.out.println(br.readLine());}catch(IOExceptione){e.printStackTrace();}}}使用try-with-resources代码的好处是更优雅,行数更少。资源是自动管理的,所以你不必担心内存泄漏。八、异常链我们常常想在捕捉到一个异常后抛出另一个异常,并希望保存原来异常的信息,这就是异常链。Throw抛出一个新的异常信息,会导致原来的异常信息丢失。在JDk1.4之前,程序员必须自己编写代码来保存原始的异常信息。所有Throwable子类现在都可以接受一个原因(异常原因)对象作为构造函数中的参数。这个cause用来表示原来的异常,这样通过把原来的异常传递给新的异常,即使在当前位置创建并抛出新的异常,也可以通过这个异常链追溯异常的原始位置。用法如下:next());}}catch(FileNotFoundExceptione){//e保存异常信息thrownewMyException("文件在哪里",e);}}publicvoidinvokeReadFile()throwsMyException{try{readFile();}catch(MyExceptione){//e保存异常信息thrownewMyException("Filenotfound",e);}}publicstaticvoidmain(String[]args){TestChainException=newTestChainException();try{t.invokeReadFile();}catch(MyExceptione){e.printStackTrace();}}}//MyException构造函数publicMyException(Stringmessage,Throwablecause){super(message,cause);}运行结果:我们可以看到异常信息已经被保存了,如果是什么原因(也就是FileNotFoundException)的e去掉,看运行结果:可以发现没有Throwable的原因,原来的异常信息是missinG。9.异常匹配当抛出异常时,异常处理系统会根据代码编写的顺序寻找“最近”的handler。当它找到一个匹配的处理程序时,它假定异常将被处理并且不再寻找。查找时,并不要求抛出的异常与处理程序的异常完全匹配。派生类的对象也可以配备其基类的处理程序。参见demopackageexceptions;//:exceptions/Human。thrownewSneeze();}catch(Sneezes){System.out.println("CaughtSneeze");}catch(Annoyancea){System.out.println("CaughtAnnoyance");}//Catchthebasetype:try{thrownewSneeze();}catch(Annoyancea){System.out.println("CaughtAnnoyance");}}}运行结果:catch(Annoyancea)将捕获Annoyance及其派生的所有异常。如果捕获基类的异常,可以匹配所有派生类的异常try{thrownewSneeze();}catch(Annoyancea){}catch(Sneezes){//编译器会报错,因为异常已经由前面的catch子句处理}10、Java中的常见异常NullPointerException空指针异常,最常见的异常类。简而言之,当调用未初始化的对象或不存在的对象时,会发生此异常。ArithmeticException算术异常类,如果程序中有被0除之类的操作,就会出现这样的异常。ClassCastException是类型转换异常,是JVM检测到两种类型之间的转换不兼容时抛出的运行时异常。ArrayIndexOutOfBoundsException数组下标越界异常,在处理数组时需要注意该异常。FileNotFoundException找不到文件。一般是找不到要读写的文件,导致异常。SQLException操作数据库异常,是CheckedException(检查异常);IOExceptionIO异常,一般与读写文件密切相关,也就是CheckedException(检查异常)。平时读写文件,切记IO流是关闭的!NoSuchMethodException未找到方法异常NumberFormatException字符串转换为数字异常