java 基础异常使用总结

我们在写代码时,不可能没有不发生错误或者异常情况,因为有的异常不是由于程序员引起的,因此必须对这些异常进行处理,否则程序会挂掉,而java是面向对象的语言,在java中异常也被封装成对象了,在java中异常用Throwable表示,这个类位于java.lang包下,现在看下面文档对这个类的描述,我这是中文文档

Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。

两个子类的实例,ErrorException,通常用于指示发生了异常情况。通常,这些实例是在异常情况的上下文中新近创建的,因此包含了相关的信息(比如堆栈跟踪数据)。

Throwable 包含了其线程创建时线程执行堆栈的快照。它还包含了给出有关错误更多信息的消息字符串。最后,它还可以包含 cause(原因):另一个导致此 throwable 抛出的 throwable。此 cause 设施在 1.4 版本中首次出现。它也称为异常链 设施,因为 cause 自身也会有 cause,依此类推,就形成了异常链,每个异常都是由另一个异常引起的。

导致 throwable cause 的一个理由是,抛出它的类构建在低层抽象之中,而高层操作由于低层操作的失败而失败。让低层抛出的 throwable 向外传播是一种糟糕的设计方法,因为它通常与高层提供的抽象不相关。此外,这样做将高层 API 与其实现细节关联起来,假定低层异常是经过检查的异常。抛出“经过包装的异常”(即包含 cause 的异常)允许高层与其调用方交流失败详细信息,而不会招致上述任何一个缺点。这种方式保留了改变高层实现而不改变其 API 的灵活性(尤其是,异常集合通过其方法抛出)。

导致 throwable cause 的另一个 cause 是,抛出它的方法必须符合通用接口,而通用接口不允许方法直接抛出 cause。例如,假定持久集合符合 Collection 接口,而其持久性在 java.io 的基础上实现。假定 put 方法的内部可以抛出 IOException。实现可以与其调用方交流 IOException 的详细消息,同时通过以一种合适的未检查的异常来包装 IOException,使其符合 Collection 接口。(持久集合的规范应该指示它能够抛出这种异常。)

Cause 可以通过两种方式与 throwable 关联起来:通过一个将 cause 看作参数的构造方法;或者通过 initCause(Throwable) 方法。对于那些希望将 cause 与其关联起来的新 throwable 类,应该提供带有 cause 的构造方法,并委托(可能间接)给一个带有 cause 的 Throwable 构造方法。例如:

     try {
         lowLevelOp();
     } catch (LowLevelException le) {
         throw new HighLevelException(le);  // Chaining-aware constructor
     }
 
因为 initCause 方法是公共的,它允许 cause 与任何 throwable 相关联,甚至包括“遗留 throwable”,它的实现提前将异常链机制的附件应用到 Throwable。例如:
     try {
         lowLevelOp();
     } catch (LowLevelException le) {
         throw (HighLevelException)
                 new HighLevelException().initCause(le);  // Legacy constructor
     }
 

在版本 1.4 之前,许多 throwable 有自己的非标准异常链机制( ExceptionInInitializerError ClassNotFoundException UndeclaredThrowableException InvocationTargetException WriteAbortedException PrivilegedActionException PrinterIOException RemoteException NamingException)。所有这些 throwable 都已经更新过,可以使用标准异常链机制,同时继续实现其“遗留”链机制,以保持兼容性。

此外,从版本 1.4 开始,许多通用的 Throwable 类(例如,ExceptionRuntimeExceptionError)都已经更新,具有带 cause 的构造方法。由于有 initCause 方法存在,这不是严格要求的,但它更方便,也更形象地委托给一个带有 cause 的构造方法。

根据惯例,Throwable 类及其子类有两个构造方法,一个不带参数,另一个带有 String 参数,此参数可用于生成详细消息。此外,这些子类很可能有与其相关联的 cause,因此也应有两个构造方法,一个带 Throwable (cause),一个带 String(详细消息)和 Throwable (cause)。

在版本 1.4 中还引入了 getStackTrace() 方法,它允许通过各种形式的 printStackTrace() 方法编程访问堆栈跟踪信息,这些信息以前只能以文本形式使用。此信息已经添加到该类的序列化表示形式,因此 getStackTraceprintStackTrace 将可在反序列化时获得的 throwable 上正确操作。 


Throwable有2个子类 是Error,Exception,所有的异常都是可抛出的,但是Error和Exception是有区别的

Error:java程序中如果出现了错误,错误不能被处理,只能退出JVM,例如:OutOfMemoryError,StackOverflowError

Exception:Exception是可以处理的如果没有处理异常,程序则退出JVM,而Exception又分编译时异期常和运行时异常,

编译时异期常:所有编译时期异常,要求程序员在编译程序阶段,必须对它进行处理,如果不处理编译则无法通过,处理异常有二种方式,try{}catch(Exception e){} 另一种就是在方法上声明throws抛出异常,如果一直不处理,则抛到了JVM上,那么程序就直接挂掉,导致后面的代码不能执行,

运行时期异常:所有运行时期的异常都是直接继承RuntimeException,运行时期异常在编译时期不需要对它进行处理,运行时期异常比编译时期异常发生的概率要小点,


下面我们看看常发生的编译时期异常:

IOException 当发生某种 I/O 异常时,抛出此异常。此类为异常的通用类,它是由失败的或中断的 I/O 操作生成的XMLParseException 当将某个 XML 格式的字符串解析为 ModelMBean 对象,或从 ModelMBean 对象创建 XML 格式的字符串时,抛出此异常。 它还用于来自可能被使用的 XML 解析器的包装器异常

FileNotFoundException 试图打开指定路径名表示的文件失败时,抛出此异常

DataFormatException 当数据格式发生错误时,抛出此异常

常发生的运行时期异常有:

ArithmeticException 当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例

ArrayStoreException 试图将错误类型的对象存储到一个对象数组时抛出的异常。例如,以下代码可生成一个ArrayStoreException

ClassCastException 当试图将对象强制转换为不是实例的子类时,抛出该异常。例如,以下代码将生成一个ClassCastException

IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数IndexOutOfBoundsException 

指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。

应用程序可以为这个类创建子类,以指示类似的异常NullPointerException 当应用程序试图在需要对象的地方使用 null 时,抛出该异常。这种情况包括调用 null 对象的实例方法。

访问或修改 null 对象的字段。

  • null 作为一个数组,获得其长度。
  • null 作为一个数组,访问或修改其时间片。
  • null 作为 Throwable 值抛出。应用程序应该抛出该类的实例,指示其他对 null 对象的非法使用

下面我写几个例子演示下异常的发生以及解决

package com.exception;
public class ExceptionDemo {
public static void main(String[] args) {
 int a = 1;
 int b = 0;
 int  c = a/b;
 System.out.println(c);
}
}

一运行起来就报错:

Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.exception.ExceptionDemo.main(ExceptionDemo.java:7)

这明显是一个运行时期异常,表示除数不能为0,发生这个异常我们能用try{}catch(){} 或者throws抛么,那我们试下就知道,

try处理

package com.exception;
public class ExceptionDemo {
public static void main(String[] args) {
 int a = 1;
 int b = 0;
 try{
 int  c = a/b;
 System.out.println(c);
 }catch(Exception e){
 e.getStackTrace();
 }
 System.out.println("我要执行");
}
}

throws 抛出

package com.exception;
public class ExceptionDemo {
public static void main(String[] args) throws Exception {
 int a = 1;
 int b = 0;
 int  c = a/b;
 System.out.println(c);
 System.out.println("我要执行");
}
}

我们运行发现你如果使用了throws抛出的话,后面的System.out.println("我要执行");就不能执行,而且程序会挂掉,使用try{}的话后面的话能执行,但是没有日记错误出来,到时候程序员去改bug就不好改,这就是为什么运行时期异常要我们程序员自己处理,怎么处理啊,无非就是加判断,

package com.exception;
public class ExceptionDemo {
public static void main(String[] args) {
 int a = 1;
 int b = 0;
 if(b==0){
 System.out.println("除数不能为0");
 }else{
 int c = a/b;
 System.out.println(c);
 }
 System.out.println("我要执行");
}
}

现在看一个编译时期的异常:


发现他直接有红色的下划线,表示你要对这段代码进行处理,如果不进行处理的话编译就不让你通过,而且他还会帮你选择处理的方式是try...catch...还是throws,还有一种情况就是会连续的出现异常,

package com.exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionDemo {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("H://a.txt");
fis.read();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("hha");
}
}
上面的二句话都会出现编译时期异常,这个时候就要出现多catch请求去捕获异常了,这要注意点,从上到下,捕获的是从小到大,我们知道 FileNotFoundException 是IOException的子类,你不能把IOException放在前面,这样会导致编译不通过,

除了jdk给我们提供的异常类,我们也可以自定义异常,如果是编译时期异常直接继承Exception,运行时期异常直接继承RuntimeException,我们先来看看

Throwable类的构造函数和常用的方法:

构造方法摘要
Throwable()
          构造一个将 null 作为其详细消息的新 throwable。
Throwable(String message)
          构造带指定详细消息的新 throwable。
Throwable(String message, Throwable cause)
          构造一个带指定详细消息和 cause 的新 throwable。
Throwable(Throwable cause)
          构造一个带指定 cause 和 (cause==null ? null :cause.toString())(它通常包含类和 cause 的详细消息)的详细消息的新 throwable。

fillInStackTrace() 在异常堆栈跟踪中填充。

getCause() 返回此 throwable 的 cause;如果 cause 不存在或未知,则返回 null
getLocalizedMessage() 创建此 throwable 的本地化描述
getMessage() 返回此 throwable 的详细消息字符串
getStackTrace() 提供编程访问由 printStackTrace() 输出的堆栈跟踪信息
initCause(Throwable cause) 将此 throwable 的 cause 初始化为指定值
printStackTrace() 将此 throwable 及其追踪输出至标准错误流
printStackTrace(PrintStream s) 将此 throwable 及其追踪输出到指定的输出流
printStackTrace(PrintWriter s) 将此 throwable 及其追踪输出到指定的 PrintWriter
setStackTrace(StackTraceElement[] stackTrace) 设置将由 getStackTrace() 返回,并由 printStackTrace() 和相关方法出的堆栈跟踪元素

package com.exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ExceptionDemo {
public static void main(String[] args) throws MyException {
try {
FileInputStream fis = new FileInputStream("H://a.txt");
} catch (FileNotFoundException e) {
throw new MyException("没有这个盘符或者文件不 存在");
}
}
}
MyException 就是自定义异常
package com.exception;
public class MyException extends Exception {
private static final long serialVersionUID = 1L;
public MyException(String msg){
super(msg);
}
public MyException(){

}
}
现在看一下finally语句块,表示一定会执行的意思,除非在这之前你调用了System.exit(0);表示jvm退出,一般用于释放资源,比如流的关闭等操作,

现在讲一个面试题:
package com.exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ExceptionDemo2 {
public static void main(String[] args) {
System.out.println("结果是:"+m1());
}


private static int m1() {
int i=10;
try{
return i;
}finally{
i++;
System.out.println(i);
}
}
}
问这个 return值是多少,结果是10,而不是11,他的原理相当于是在用一个临时变量保存了i的值然后返回的:
package com.exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ExceptionDemo2 {
public static void main(String[] args) {
System.out.println("结果是:"+m1());
}


private static int m1() {
int i=10;
int temp =0 ;//模拟底层使用
try{
temp = i;
return temp;
}finally{
i++;
System.out.println(i);
}
}
}
后面的i++其实和return返回的值没毛关系了,好了就讲到这里了!




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值