《THING IN JAVA》 12章通过异常处理错误-读书笔记

1、RunTimeException的子类

RunTimeException及其子类被称为”不被检查异常“,不用关键字throws声明抛出的异常
RunTimeException及其子类包括:

NullPointerException - 空指针引用异常

ClassCastException - 类型强制转换异常。
IllegalArgumentException - 传递非法参数异常。
ArithmeticException - 算术运算异常
ArrayStoreException - 向数组中存放与声明类型不兼容对象异常
IndexOutOfBoundsException - 下标越界异常
NegativeArraySizeException - 创建一个大小为负数的数组错误异常
NumberFormatException - 数字格式异常
SecurityException - 安全异常

UnsupportedOperationException - 不支持的操作异常


2、关于throw、throws的几种用法

(1)在方法后面抛出异常throws关键字,除了RunTimeException及其子类不用声明外,抛出其他异常要声明

(2)抛出异常

(3)重新抛出异常


3、try-catch{}块、与用throw关键字抛出的异常区别

(1)try-catch捕获异常,被捕获的”被检查异常“不用方法后不用throws关键抛出,并且这中短当前代码,交给相应的catch块处理,然后继续处理catch块后面的内容

(2)JAVA的”吞食“现象,try-catch块中catch块不做任何处理

(3)throw关键字抛出的异常直接结束方法,抛出异常交由上一级异常处理


public class MyTest2 {
public static void main(String[] args){
System.out.println("come into 1");
int i = 0;
while(i<=100){
if(i == 66){
throw new NullPointerException();
}
try{
if(i%3 == 1){
throw new MyException();
}
if(i%13 == 1 ){
String s = null;
s.length();
}
}catch(MyException e){
e.printStackTrace(System.out);
}catch(Exception e){
e.printStackTrace(System.out);
}
System.out.println("i="+i);
i++;
}
System.out.println("end");
}
}


部分运行结果:

i=61
i=62
i=63
come to MyException1
com.zeng.test.MyException
at com.zeng.test.MyTest2.main(MyTest2.java:14)
i=64
i=65
Exception in thread "main" java.lang.NullPointerException
at com.zeng.test.MyTest2.main(MyTest2.java:10)


4、异常栈的输出是由异常发生的地方一层一层往上输出的


public class MyTest4 {
static void f(){
try{
throw new Exception();
}catch(Exception e){
for(StackTraceElement ste:e.getStackTrace()){
System.out.println(ste.getMethodName());
}
}
}
static void g(){
f();
}
static void h(){
g();
}
public static void main(String[] args){
f();
System.out.println("------------------------------------------");
g();
System.out.println("------------------------------------------");
h();
}
}


输出结果:

f
main
------------------------------------------
f
g
main
------------------------------------------
f
g
h
main


5、异常链

当try-catch块里面的catch块抛出与捕获不一样的异常时,原来抛出的异常会丢失


public class MyTest5 {
static void f()throws MyException{
g();
}
static void g() throws MyException{
throw new MyException();
}
public static void main(String[] args){
try{
try{
f();
}catch(MyException e){
e.printStackTrace(System.out);
// throw new TestException();
throw new TestException(e);
}
}catch(TestException e){
System.out.println("catch TestException");
e.printStackTrace(System.out);
}
}
}


可以试运行以下不带cause因子和带cause因子的效果,TestException是有接受因子的构造方法,并执行了父类的构造方法

不带cause因子的方法会忽略掉异常产生的地方如不能知道发生异常的地方是f();


如果调用e的fillInStackTrace方法也会有丢失异常发生的方的情况出现


6、finally块

(1)try-finally块finally块的内容是一定会执行的,包括throw new Exception、break、continue 等都会执行的

(2)但是有缺陷,在finally块return值,或者里面抛出新的异常会覆盖原来的内容


public class MyTest6 {
public static void main(String[] args){
try{
for(int i=0;i<3;i++){
f();
if(i == 1){
break;
}
}
throw new RuntimeException();
}finally{
System.out.println("finally always run");
return;
}
// System.out.println("main");
}

private static String f()throws MyException{
try{
throw new MyException();
}finally{
return "";
}
}
}


运行结果:

come to MyException1
come to MyException1
finally always run


可以看到运行结果不会报任何的错


7、方法重写的异常限制

(1)构造方法不受异常限制,如果调用基类的构造器,抛出的异常范围必须是异常类的基类(抛出的异常范围比基类要大)

(2)派生类的构造方法不能捕获基类的异常(由于一始就要行super(),不写会默认执行)

(3)派生类的重写方法声明抛出的异常必须在基类方法声明的异常范围内(比基类小),甚至可以不抛出异常在范围内即可,这样限制了派生类必须处理一些基类没有的异常,如基类throws NullPointerExcepiton,派生类就必须try-catch处理不为NullPointerException之外的异常


public class MyTest7 {
public static void main(String[] args){
try{
B b = new B();
}catch(Exception e){
System.out.println(e.getStackTrace());
}
}
}


class A{
public A()throws MyException{
throw new MyException();
}
public A(String s){

}
public void g() throws NullPointerException{

}
}


class B extends A{


public B() throws Exception{
super();  //默认调用
}

public B(String s){
super(s);
}

public void g()throws NullPointerException{
try{       //必须处理掉Exception,这里只能抛出NullPointerException、
throw new Exception();
}catch(Exception e){
System.out.println("This is Exception");
}
}

}


8、关于方便异常代码维护的一种代码风格


public class MyTest8 {
public static void main(String[] args){
for(int i=0;i<5;i++){
try{
if(i == 3){
throw new Exception();
}else{
f(i);
}
}catch(RuntimeException e1){
if(i == 4){
throw new NullPointerException();
}
try{
throw e1.getCause();
}catch(MyException e3){
System.out.println("This is MyException");
e3.printStackTrace(System.out);
}catch(TestException e4){
System.out.println("This is TestException");
e4.printStackTrace(System.out);
}catch(Throwable e){   //取casue的保底
System.out.println("This is ThrowableException");
e.printStackTrace(System.out);
}
}catch(Exception e2){
System.out.println("This is Exception");
e2.printStackTrace(System.out);
}
}

}

public static void f(int i){   //这层处理不了自定义的Exception,需要抛给上一层处理,但又不想写throws关键字增加程序的可读性与维护性
try{
switch(i){
case 1: 
throw new MyException();
case 2:
throw new TestException();
default : 
throw new Exception();
}
}catch(Exception e){
throw new RuntimeException(e);
}

}
}


方法f()把所有捕获到的异常封装成RuntimeException往上抛出

main()方法获取到捕获到RuntimeException,用方法e.getCause()取得异常因子重新抛出

重新获取后的cause异常,mian()方法会提供处理方法,同时不会丢失异常的信息-保持完整的异常链


附上MyException和TestException类的代码


public class MyException extends Exception{
public MyException(){
System.out.println("come to MyException1");
}
public MyException(String message){
super(message);
System.out.println("come to MyExcepiton2");
}
}

public class TestException extends Exception{
public TestException(){
System.out.println("come into TestException");
}
public TestException(Exception e){
super(e);
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值