1、java标准异常概述
Throwable表示任何可以作为异常被抛出的类,有两个子类Error和Exception。从这两个类的源代码中可以看出,这两个类并没有添加新的方法,Throwable提供了所以方法的实现。Error表示编译时和系统错误。Exception是可以被抛出的异常类。RuntimeException继承自Exception(如NullPointerException),表示运行时异常,JVM会自动抛出.
2、自定义异常类
自定义异常类方法: 通过继承Throwable或Exception。异常类的所有实现都是基类Throwable实现的,所以构造自定义异常类完全可以参考Exception和Error类。我们只要添加上自定义异常类的构造方法就可以了
<span style="font-size:16px;">package demo.others; /** * 自定义异常类方法 * 1、通过继承Throwable * 2、通过继承Exception * * @author Touch */ public class MyExceptionDemo extends Exception { private static final long serialVersionUID = 1L; public MyExceptionDemo() { super(); } public MyExceptionDemo(String message) { super(message); } public MyExceptionDemo(String message, Throwable cause) { super(message, cause); } public MyExceptionDemo(Throwable cause) { super(cause); } } </span>
3、异常栈及异常处理方式
可以通过try、catch来捕获异常。捕获到的异常。下面的示例演示了几种常用异常处理方式
<span style="font-size:16px;">package demo.others; import mine.util.exception.MyException; public class ExceptionDemo1 { public void f() throws MyException { throw new MyException("自定义异常"); } public void g() throws MyException { f(); } public void h() throws MyException { try { g(); } catch (MyException e) { //1、通过获取栈轨迹中的元素数组来显示异常抛出的轨迹 for (StackTraceElement ste : e.getStackTrace()) System.out.println(ste.getMethodName()); //2、直接将异常栈信息输出至标准错误流或标准输出流 e.printStackTrace();//输出到标准错误流 e.printStackTrace(System.err); e.printStackTrace(System.out); //3、将异常信息输出到文件中 //e.printStackTrace(new PrintStream("file/exception.txt")); //4、重新抛出异常,如果直接抛出那么栈路径是完整的,如果用fillInStackTrace() //那么将会从这个方法(当前是h()方法)作为异常发生的原点。 //throw e; throw (MyException)e.fillInStackTrace(); } } public static void main(String[] args) { try { new ExceptionDemo1().h(); } catch (MyException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } </span>
运行结果:
f g h main mine.util.exception.MyException: 自定义异常 at demo.others.ExceptionDemo1.f(ExceptionDemo1.Java:7) at demo.others.ExceptionDemo1.g(ExceptionDemo1.Java:11) at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:16) at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35) mine.util.exception.MyException: 自定义异常 at demo.others.ExceptionDemo1.f(ExceptionDemo1.java:7) at demo.others.ExceptionDemo1.g(ExceptionDemo1.java:11) at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:16) at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35) mine.util.exception.MyException: 自定义异常 at demo.others.ExceptionDemo1.f(ExceptionDemo1.java:7) at demo.others.ExceptionDemo1.g(ExceptionDemo1.java:11) at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:16) at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35) mine.util.exception.MyException: 自定义异常 at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:30) at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35)
分析上面的程序,首先main函数被调用,然后是调用h函数,再g函数、f函数,f函数抛出异常,并在h函数捕获,这时将依次从栈顶到栈底输出异常栈路径。
4、异常链
有时候我们会捕获一个异常后在抛出另一个异常,如下代码所示:
<span style="font-size:16px;">package demo.others; import java.io.IOException; import mine.util.exception.MyException; public class ExceptionDemo2 { public void f() throws MyException { throw new MyException("自定义异常"); } public void g() throws Exception { try { f(); } catch (MyException e) { e.printStackTrace(); throw new Exception("重新抛出的异常1"); } } public void h() throws IOException { try { g(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); throw new IOException("重新抛出异常2"); } } public static void main(String[] args) { try { new ExceptionDemo2().h(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } </span>
运行结果:
mine.util.exception.MyException: 自定义异常 at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9) at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14) at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23) at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:32) java.lang.Exception: 重新抛出的异常1 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:17) at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23) at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:32) java.io.IOException: 重新抛出异常2 at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:27) at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:32)
从结果中我们可以看出,异常栈变小了。也就是说丢失了最原始的异常信息。怎样保存最原始的异常信息呢?Throwable类中有个Throwable cause属性,表示原始异常。通过接收cause参数的构造器可以把原始异常传递给新异常,或者通过initCause()方法。如下示例:
<span style="font-size:16px;">package demo.others; import java.io.IOException; import mine.util.exception.MyException; public class ExceptionDemo2 { public void f() throws MyException { throw new MyException("自定义异常"); } public void g() throws Exception { try { f(); } catch (MyException e) { e.printStackTrace(); throw new Exception("重新抛出的异常1",e); } } public void h() throws IOException { try { g(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); IOException io=new IOException("重新抛出异常2"); io.initCause(e); throw io; } } public static void main(String[] args) { try { new ExceptionDemo2().h(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } </span>
结果:
mine.util.exception.MyException: 自定义异常 at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9) at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14) at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23) at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:34) java.lang.Exception: 重新抛出的异常1 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:17) at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23) at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:34) Caused by: mine.util.exception.MyException: 自定义异常 at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9) at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14) ... 2 more java.io.IOException: 重新抛出异常2 at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:27) at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:34) Caused by: java.lang.Exception: 重新抛出的异常1 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:17) at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23) ... 1 more Caused by: mine.util.exception.MyException: 自定义异常 at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9) at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14) ... 2 more
从结果中看出当获取到“重新抛出异常2的时候,同时可以输出原始异常“重新抛出的异常1“和原始异常”自定义异常,这就是异常链。
5、finally的使用
finally子句总是执行的,通常用来做一些清理工作,如关闭文件,关闭连接等
下面举几个finally的例子:
<span style="font-size:16px;">// 读取指定路径文本文件 public static String read(String filePath) { StringBuilder str = new StringBuilder(); BufferedReader in = null; try { in = new BufferedReader(new FileReader(filePath)); String s; try { while ((s = in.readLine()) != null) str.append(s + '\n'); } finally { in.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return str.toString(); }</span>
分析:如果调用in = new BufferedReader(new FileReader(filePath));时发生异常,这时是一个文件路径不存在的异常,也就是说并没有打开文件,这时将会直接跳到catch块,而不会执行try...finally块(并不是finally子句)里面的语句in.close();此时不需要关闭文件。
再看一个例子,会导致异常的丢失
<span style="font-size:16px;">package demo.others; import mine.util.exception.MyException; public class ExceptionDemo3 { public void f() throws MyException { throw new MyException("异常1"); } public void g() throws MyException { throw new MyException("异常2"); } public static void main(String[] args) { try { ExceptionDemo3 ex = new ExceptionDemo3(); try { ex.f(); } finally { ex.g();//此时捕获g方法抛出的异常,f方法抛出的异常丢失了 } } catch (MyException e) { System.out.println(e); } } } </span>
结果:mine.util.exception.MyException: 异常2
此时异常1就丢失了
或者这样写:
<span style="font-size:16px;">package demo.others; import mine.util.exception.MyException; public class ExceptionDemo3 { public void g() throws MyException { throw new MyException("异常2"); } public static void main(String[] args) { ExceptionDemo3 ex = new ExceptionDemo3(); try { ex.g(); } finally { //直接return会丢失所以抛出的异常 return; } } } </span>
6、异常的限制
(1)当覆盖方法时,只能抛出在基类方法的异常说明里列出的那些异常,有些基类的方法声明抛出异常其实并没有抛出异常,这是因为可能在其子类的覆盖方法中会抛出异常
(2)构造器可以抛出任何异常而不必理会基类构造器所抛出的异常,派生类构造器异常说明必须包含基类构造器异常说明,因为构造派生类对象时会调用基类构造器。此外,派生类构造器不能捕获基类构造器抛出的异常。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
应用程序通常会通过抛出另一个异常来响应异常。 实际上,第一个异常引起第二个异常。 它可以是非常有助于用户知道什么时候一个异常导致另一个异常。 “异常链(Chained Exceptions)”帮助程序员做到这一点。 以下是Throwable中支持异常链的方法和构造函数。 Throwable getCause() Throwable initCause(Throwable) Throwable(St
前面介绍了异常的产生是不可避免的,那么为了保证程序有效地执行,需要对发生的异常进行相应的处理。 Java 的异常处理通过 5 个关键字来实现: try、 catch、 throw、 throws 和 finally。 try catch 语句用于捕获并处理异常,finally 语句用于在任何情况下(除特殊情况外)都必须执行的代码,throw 语句用于拋出异常,throws 语句用于声明可能会出现的
问题内容: 异常存储在哪里?堆,堆。如何为异常分配和释放内存?现在,如果您有多个需要处理的异常,是否创建了所有这些异常的对象? 问题答案: 我假设为异常分配的内存分配方式与所有其他对象(在堆上)分配方式相同。 这曾经是个问题,因为您不能为OutOfMemoryError分配内存,这就是直到Java 1.6之前 才没有堆栈跟踪的原因。现在,它们也为stacktrace预分配了空间。 如果您想知道在抛
主要内容:异常简介,异常类型很多事件并非总是按照人们自己设计意愿顺利发展的,经常出现这样那样的异常情况。例如: 你计划周末郊游,计划从家里出发→到达目的→游泳→烧烤→回家。但天有不测风云,当你准备烧烤时候突然天降大雨,只能终止郊游提前回家。“天降大雨”是一种异常情况,你的计划应该考虑到这样的情况,并且应该有处理这种异常的预案。 计算机程序的编写也需要考虑处理这些异常情况。 异常(exception)是在运行程序时产生的一种异
我期望第1行捕获从第0行抛出的NullPointerException,但它没有发生。 但为什么呢?。 当定义了另一个catch块时,为什么第1行的NPE处理程序不能捕获它? 是因为“投掷”直接进入main()方法吗?
Java 的异常处理是 Java 语言的一大重要特性,也是提高代码健壮性的最强大方法之一。当我们编写了错误的代码时,编译器在编译期间可能会抛出异常,有时候即使编译正常,在运行代码的时候也可能会抛出异常。本小节我们将介绍什么是异常、Java 中异常类的架构、如何进行异常处理、如何自定义异常、什么是异常链、如何使用异常链等内容。 1. 什么是异常 异常就是程序上的错误,我们在编写程序的时候经常会产生错