Java 提供了一种健壮且面向对象的方法来处理称为 Java异常处理的异常状况。java
异常是在程序执行期间可能发生的错误事件,它会破坏其正常流程。异常可能源于各类状况,例如用户输入的错误数据,硬件故障,网络链接故障等。程序员
每当执行 Java 语句时发生任何错误,都会建立一个异常对象,而后 JRE尝试查找异常处理程序来处理该异常。若是找到了合适的异常处理程序,则将异常对象传递处处理程序代码以处理异常,称为捕获异常。若是未找处处理程序,则应用程序将异常抛出给运行时环境,而且 JRE 终止程序。面试
Java 异常处理框架仅用于处理运行时错误,异常处理框架不处理编译时错误。算法
java 异常处理中使用了四个关键字。编程
throw:有时咱们明确地想要建立异常对象,而后将其抛出以中止程序的正常处理。throw 关键字用于向运行时抛出异常以进行处理。数组
throws:当咱们在方法中抛出任何已检查的异常而且不对其进行处理时,咱们须要在方法签名时使用 throws 关键字,以使调用方程序知道该方法可能抛出的异常。调用方方法能够处理这些异常,也可使用throws
关键字将其传播到其调用方方法。咱们能够在 throws 子句中提供多个异常,它也能够与 main()方法一块儿使用。网络
try-catch:咱们在代码中使用 try-catch 块进行异常处理。try 是块的开始,catch 是 try 块的末尾,用于处理异常。咱们可使用 try 捕获多个 catch 块,而且 try-catch 块也能够嵌套。catch 块须要一个应为 Exception 类型的参数。框架
finally:finally 块是可选的,只能与 try-catch 块一块儿使用。因为异常会暂停执行过程,所以咱们可能会打开一些不会关闭的资源,所以可使用 finally 块。不管是否发生异常,finally 块都会始终执行。ide
Java 异常是分层的,继承用于对不一样类型的异常进行分类。Throwable
是 Java 异常层次结构的父类,它有两个子对象– Error
和Exception
。异常进一步分为检查异常和运行时异常。函数
Error是超出应用程序范围的特殊状况,没法预见并从中恢复,例如硬件故障,JVM 崩溃或内存不足错误。
Checked Exception 是咱们能够在程序中预期并尝试从程序中恢复的异常状况,例如 FileNotFoundException。咱们应该捕获该异常,并向用户提供有用的消息,并正确记录下来以进行调试。Exception
是全部 “检查的异常” 的父类。
Runtime Exception是由错误的编程引发的,例如,尝试从 Array 中检索元素。在尝试检索元素以前,咱们应该首先检查数组的长度,不然它可能ArrayIndexOutOfBoundException
在运行时抛出。RuntimeException
是全部运行时异常的父类。
Exception及其全部子类均未提供任何特定方法,而且全部方法均在基类 Throwable 中定义。
getMessage()
方法便可返回异常消息。void printStackTrace() –此方法将堆栈跟踪信息打印到标准错误流,此方法已重载,咱们能够传递 PrintStream 或 PrintWriter 做为参数,以将堆栈跟踪信息写入文件或流。
若是您在单个 try 块中捕获了不少异常,则您会注意到 catch 块代码看起来很是丑陋,而且主要由用于记录错误的冗余代码组成,请记住,Java 7 的功能之一就是多捕获块咱们能够在单个 catch 块中捕获多个异常。具备此功能的 catch 块以下所示:
catch(IOException | SQLException | Exception ex){ logger.error(ex); throw new MyException(ex.getMessage()); }
在大多数状况下,咱们使用 finally 块只是为了关闭资源,有时咱们忘记关闭它们并在资源耗尽时获取运行时异常。这些异常很难调试,咱们可能须要调查使用该类型资源的每一个位置,以确保咱们将其关闭。所以,java 7 的改进之一是 try-with-resources,咱们能够在 try 语句自己中建立资源,并在 try-catch 块内使用它。当执行从 try-catch 块执行时,运行时环境会自动关闭这些资源。具备这种改进的 try-catch 块示例为:
try (MyResource mr = new MyResource()) { System.out.println("MyResource created in try-with-resources"); } catch (Exception e) { e.printStackTrace(); }
一、检查异常应在代码中使用 try-catch 块进行处理,不然方法应使用 throws 关键字使调用者知道该方法可能抛出的检查异常。未经检查的异常不须要在程序中处理,也不须要在方法的 throws 子句中说起。
2.、Exception是全部Checked 异常的超类,而RuntimeException
是全部Unchecked 的异常的超类。请注意,RuntimeException 是 Exception 的子类。
三、Checked 异常是须要在代码中处理的错误方案,不然您将得到编译时错误。例如,若是您使用 FileReader 读取文件,则可能会抛出该文件FileNotFoundException
,咱们必须将其在 try-catch 块中捕获,或再次将其抛出给调用方方法。Unchecked 异常一般是由不良的编程引发的,例如,在调用对象引用中的方法而不确保其不为 null 时,会引起 NullPointerException。例如,我能够编写一种方法来删除字符串中的全部元音。确保不传递空字符串对象是调用者的责任。我可能会更改处理这些状况的方法,但理想状况下,调用方应注意这一点。
throws 关键字与方法一块儿使用,以声明该方法可能抛出的异常,而 throw 关键字用于中断程序流,并将异常对象移交给运行时进行处理。
咱们能够扩展Exception
类或它的任何子类来建立咱们的自定义异常类。自定义异常类能够具备本身的变量和方法,可用于将错误代码或其余与异常相关的信息传递给异常处理程序。
自定义异常的一个简单示例以下所示。
package com.journaldev.exceptions; import java.io.IOException; public class MyException extends IOException { private static final long serialVersionUID = 4664456874499611218L; private String errorCode="Unknown_Exception"; public MyException(String message, String errorCode){ super(message); this.errorCode=errorCode; } public String getErrorCode(){ return this.errorCode; } }
Java 中的 OutOfMemoryError 是 java.lang.VirtualMachineError 的子类,当 JVM 堆内存不足时,它会被 JVM 抛出。咱们能够经过修改 java 选项提供更多内存来解决此错误。
$>java MyProgram -Xms1024m -Xmx1024m -XX:PermSize=64M -XX:MaxPermSize=256m
一些常见的主线程异常状况是:
final 和 finally 是 Java 中的关键字,而 finalize 是一种方法。
final 关键字能够与类变量一块儿使用,以使它们不能被从新分配; class 能够避免经过类进行扩展; final
关键字能够与方法避免被子类覆盖;
finally 关键字能够与 try-catch 块一块儿使用,以提供将始终执行的语句即便出现某些异常,一般最终仍是会用来关闭资源。
finalize()方法在对象被销毁以前由垃圾回收器执行,这是确保关闭全部全局资源的好方法。
在这三个中,只有finally 与 Java 异常处理有关。
当 main()方法引起异常时,Java Runtime 将终止程序并在系统控制台中打印异常消息和堆栈跟踪。
咱们能够有一个空的 catch 块,但这是最糟糕的编程示例。咱们永远不该该有空的 catch 块,由于若是异常被该块捕获,咱们将没有有关该异常的信息,调试它将是一场噩梦。至少应该有一条日志记录语句,以将异常详细信息记录在控制台或日志文件中。
与 Java 异常处理有关的一些最佳实践是:
在这里,咱们将研究与 Java 异常相关的一些编程问题。
1). 下面的程序有什么问题?
package com.journaldev.exceptions; import java.io.FileNotFoundException; import java.io.IOException; public class TestException { public static void main(String[] args) { try { testExceptions(); } catch (FileNotFoundException | IOException e) { e.printStackTrace(); } } public static void testExceptions() throws IOException, FileNotFoundException{ } }
上面的程序没法编译,而且您会收到错误消息,“The exception FileNotFoundException is already caught by the alternative IOException”。这是由于 FileNotFoundException 是 IOException 的子类,有两种方法能够解决此问题。
第一种方法是对两个异常都使用单个 catch 块。
try { testExceptions(); }catch(FileNotFoundException e){ e.printStackTrace(); }catch (IOException e) { e.printStackTrace(); }
另外一种方法是从多捕获块中删除 FileNotFoundException。
try { testExceptions(); }catch (IOException e) { e.printStackTrace(); }
您能够根据状况选择任何一种方法。
2). 下面的程序有什么问题?
package com.journaldev.exceptions; import java.io.FileNotFoundException; import java.io.IOException; import javax.xml.bind.JAXBException; public class TestException1 { public static void main(String[] args) { try { go(); } catch (IOException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); } } public static void go() throws IOException, JAXBException, FileNotFoundException{ } }
该程序将编译错误,由于 FileNotFoundException 是 IOException 的子类,所以 FileNotFoundException 的 catch 块不可访问,而且您将收到错误消息 “ Unreachable catch block for FileNotFoundException. It is already handled by the catch block for IOException”。
您须要修复 catch 块顺序才能解决此问题。
try { go(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JAXBException e) { e.printStackTrace(); }
请注意,JAXBException 与 IOException 或 FileNotFoundException 不相关,能够放置在以上 catch 块层次结构中的任何位置。
3). 下面的程序有什么问题?
package com.journaldev.exceptions; import java.io.IOException; import javax.xml.bind.JAXBException; public class TestException2 { public static void main(String[] args) { try { foo(); } catch (IOException e) { e.printStackTrace(); }catch(JAXBException e){ e.printStackTrace(); }catch(NullPointerException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } } public static void foo() throws IOException{ } }
该程序将没法编译,由于 JAXBException 是一个已检查的异常,而且 foo()方法应抛出此异常以捕获调用方法。您将收到错误消息 “ JAXBException 没法访问的捕获块。不会从 try 语句主体中引起此异常。
要解决此问题,您将必须删除 JAXBException 的 catch 块。
注意,捕获 NullPointerException 是有效的,由于它是未经检查的异常。
4). 下面的程序有什么问题?
package com.journaldev.exceptions; public class TestException3 { public static void main(String[] args) { try{ bar(); }catch(NullPointerException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } foo(); } public static void bar(){ } public static void foo() throws NullPointerException{ } }
这是一个技巧性的问题,代码没有问题,它将成功编译。咱们老是能够捕获 Exception 或任何未经检查的异常,即便它不在方法的 throws 子句中也是如此。
一样,若是方法(foo)在 throws 子句中声明未经检查的异常,则在程序中处理该异常不是强制性的。
5). 下面的程序有什么问题?
package com.journaldev.exceptions; import java.io.IOException; public class TestException4 { public void start() throws IOException{ } public void foo() throws NullPointerException{ } } class TestException5 extends TestException4{ public void start() throws Exception{ } public void foo() throws RuntimeException{ } }
上面的程序没法编译,由于子类中的start()方法签名不一样。要解决此问题,咱们能够将子类中的方法特性更改成与超类彻底相同,也能够从子类方法中删除throws子句,以下所示。
@Override public void start(){ }
6). 下面的程序有什么问题?
package com.journaldev.exceptions; import java.io.IOException; import javax.xml.bind.JAXBException; public class TestException6 { public static void main(String[] args) { try { foo(); } catch (IOException | JAXBException e) { e = new Exception(""); e.printStackTrace(); }catch(Exception e){ e = new Exception(""); e.printStackTrace(); } } public static void foo() throws IOException, JAXBException{ } }
上面的程序没法编译,由于多捕获块中的异常对象是最终对象,咱们没法更改其值。因为“没法分配多捕获块的参数e”,将致使编译时错误。
咱们必须删除对新异常对象的“ e”分配以解决此错误。
“不积跬步,无以致千里”,但愿将来的你能:有梦为马 随处可栖!加油,少年!
关注公众号:「Java 知己」,天天更新Java知识哦,期待你的到来!