Java学习笔记:异常处理

try块和catch块

1:try块中我们可以放入我们觉得可能抛出异常的代码

2:catch中,我们可以中后面的括号中加入我们想要的异常类型,可以是库里的,也可以是自定义的,只要抛出的异常能转为catch中的异常,那么就会执行其中的代码了;

import java.util.*;


public class exception{
    int a=1;
    static void ArrayIndexOutOfBoundException() throws myException{
        throw new myException("index out bound");
    }
    public static void main(String[] None){
        try{
            ArrayIndexOutOfBoundException();
        }catch(Exception e){
            System.out.print(e);
        }
    }
}

创建自定义异常

我们不必拘泥与java库中的异常,我们可以自定义匹配我们程序的一个异常,只要我们实现对应的接口,我们就可以像使用库中的异常那样使用我们自己自定义的异常了;

在上面的代码中,我们就实现了对应的Exception接口,该接口是所有exception类的父类,其实现了Throwable接口;

我们可以创建一个接受String类型的异常:

class myException extends Exception{
    public myException(String message){
        super(message);
    }
    public String toString(){
        return super.getMessage();
    }
}

这边当我们new出一个myException的的时候我们就可以输入错误信息了,当我们想要知道知道错误信息是什么的时候就可以知道是啥了;

当然,输出错误信息还有一个方法:printStackTrace(),这个函数很有意思,他会在输出super.getMessage()函数的同时,输出调用栈的轨迹,就如同他的名字一样,看下面的代码:

public class exception{
    static void ArrayIndexOutOfBoundException() throws myException{
        throw new myException("index out bound");
    }
    public static void main(String[] None){
        try{
            ArrayIndexOutOfBoundException();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

其打印信息:

两个自顶向下地输出从throw到处理异常的调用路径,而且我们看源码:

 

 这个函数内部是调用另外一个printStackTrace的重载,很容易看出来我们将信息输出大标准错误流中;

【这里要注意,一般在工程中不要使用printStackTrace,因为这个方法会将大量的字符串输出,占用内存,最后导致内存不足】;

异常与记录日志

为了记录错误和其他信息,一般我们都会用java内置的logging库;

我们可以写一个自动将错误信息记录到日志中的错误:

class LoggingException extends Exception{
    static Logger logger=Logger.getLogger("LoggingException");
    public LoggingException(){
        StringWriter trace =new StringWriter();//创建一个stringbuffer
        PrintWriter print = new PrintWriter(trace);//创建一个printWriter持有trace
        printStackTrace(print);//将错误信息存储到trace中
        logger.severe(trace.toString());//将错误信息提取出来,然后转化为string传入severe
    }
}

这里,String就是对StringBuffer的一个封装;

当我们new出来一个LoggingException对象的时候,调用其构造器,然后在构造器中实现我们的需求,注意,从环境中获取错误信息的操作是中Exception中实现的,在编译的时候,编译器会自动的在子类构造器中插入父类的构造器调用,且是first code,所以我们可以安全地使用printStackTrace函数;

看下面一串代码:

public class exception{
    static void ArrayIndexOutOfBoundException() throws LoggingException{
        throw new LoggingException("index out bound");
    }
    public static void main(String[] None){
        try{
            ArrayIndexOutOfBoundException();
        }catch(Exception e){
            System.err.println("catch it");
            return;
        }
    }
}

输出:

 

我们没有在catch语句中加入记录语句,只是做了一个标准性的输出;

我们将错误的记录提前到了ArrayIndexOutOfBoundException()函数中,这给我们带来了一种便利,即当我们不需要重复写一些记录错误信息的代码,因为这在LoggingException的构造器中就做了。

当然,这并不是银弹,当我们的错误信息需要沿着错误信息throw的轨迹更新时,这种方法就不好使了;

栈轨迹

printStackTrace中的错误信息我们可以直接通过getStackTrace方法来获取,在方法返回由栈轨迹构成的数组,其中每一个元素是栈中的一帧,元素0是栈顶元素,即最后一个方法的调用,与之对应,栈底元素是调用序列中的第一个方法,看下面代码:

class LoggingException extends Exception{
    static Logger logger=Logger.getLogger("LoggingException");
    public LoggingException(String message){
        super(message);
        StringWriter trace =new StringWriter();//创建一个stringbuffer
        
        PrintWriter print = new PrintWriter(trace);//创建一个printWriter持有trace
        printStackTrace(print);//将错误信息存储到trace中
        logger.severe(trace.toString());//将错误信息提取出来,然后转化为string传入severe
    }
}

public class exception{
    static void printException(Exception e){
        for (StackTraceElement ele : e.getStackTrace()) {
            System.err.println(ele);
        }
    }

    static void g() throws Exception{
        throw new Exception();
    }
    static void f() throws Exception{
        g();
    }
    static void h() throws Exception{
        f();
    }
    public static void main(String[] None){
        try{
            g();
        }catch(Exception e){
            printException(e);
        }
        System.err.println();
        try{
            f();
        }catch(Exception e){
            printException(e);;
        }
        System.err.println();
        try{
            h();
        }catch(Exception e){
            printException(e);
        }
    }
}

输出:

要注意,这里g()的异常会抛到f中,但因为f中没有解决这个异常的环境,所以f接着将异常抛给h,同样的道理,最后抛到main中,由main进行处理;

重新抛出异常:

        对于我们已经catch一个异常的时候,我们发现我们不能处理的时候,就将其throw到更高的环境当中处理;

        但当一个异常被往更高环境抛的时候,内部的栈轨迹信息不会自动更新,这个需要我们用fillInStackTrace函数来更新;  

        看下列代码:

public class exception{
    static void printException(Exception e){
        for (StackTraceElement ele : e.getStackTrace()) {
            System.err.println(ele);
        }
    }

    static void g() throws Exception{
        throw new Exception();
    }
    static void f() throws Exception{
        try{
            g();
        }catch(Exception e){
            e.fillInStackTrace();
            throw e;
        }
    }
    static void h() throws Exception{
        g();
    }
    public static void main(String[] None){
        try{
            h();
        }catch(Exception e){
            printException(e);
        }
        System.err.println();
        try{
            f();
        }catch(Exception e){
            printException(e);;
        }
        System.err.println();
    }
}

输出:

 

啊~~~~~,写完了,学完后面的接着写!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值