方法的调用是在栈中进行的,方法之间也可以相互调用,所以我们把这种方法在栈中调用的轨迹称为堆栈信息,简称栈轨迹。

Jvm在异常发生时,也就时每当一个Exception实例化后,JVm就会对整个栈进行快照,以便用于异常信息接着向外部的函数扩散。

类似的异常的问题,意思下面的情况:

例子:

com.ydlclass.CustomizationException.UsernameException: 用户名错误 at com.ydlclass.CustomizationException.Client.fun(Client.java:13) at com.ydlclass.CustomizationException.Client.fun1(Client.java:7) at com.ydlclass.CustomizationException.Client.main(Client.java:23)

504

用户名错误

Note:

1.异常链:多个异常组成的一个链条叫做异常链(有时我们捕获到一个异常后,却抛出另外一个异常)。 2.每个Throwable子类的构造器都支持一个cause对象,这个cause可以定位到异常所发生时的一个最初的位置。其他的异常类可以通过InitCause()来设置cause

package com.ydlclass.CustomizationException;

import java.util.Scanner;

public class Client {
    public static void fun1(){
        fun();
    }
    public static void fun(){
        Scanner scanner = new Scanner(System.in);
        String username = scanner.next();
        if(!"abc".equals(username)){
            throw new UsernameException("用户名错误",504);//这个字段可能需要我们创建时就维护
        }
        Scanner scanner1 = new Scanner(System.in);
        String passsword = scanner1.next();//注意类型
        if(!"123".equals(passsword)){
            throw new PasswordErrorException();
        }
    }
    public static void main(String[] args) {
        try{
            fun1();
        } catch (UsernameException e){//分别捕获不同的异常
//            e.printStackTrace();//当异常被捕获后使用这个方法来打印异常信息的这种方式,不会将程序打断掉。不同于jvM所抛出的异常
//            System.out.println(e.getCode());//由于自定义的异常添加了一个code的字段,使用这个字段可以用于标记我们想要的自定义数字
//            System.out.println(e.getMessage());//可以使用这句话来代替下面的内容
////            System.out.println("用户名出现错误");
            PasswordErrorException passwordErrorException = new PasswordErrorException();//由于我们没有给这个异常一个构造器,所以我们使用
            //initCause()方法来实现
            passwordErrorException.initCause(e);
            throw passwordErrorException;
            //运行后出现的异常就可以发现passwordException的是由于UserErrorException这个异常导致的:
            /**
             * Exception in thread "main" com.ydlclass.CustomizationException.PasswordErrorException
             * 	at com.ydlclass.CustomizationException.Client.main(Client.java:29)
             * Caused by: com.ydlclass.CustomizationException.UsernameException: 用户名错误
             * 	at com.ydlclass.CustomizationException.Client.fun(Client.java:13)
             * 	at com.ydlclass.CustomizationException.Client.fun1(Client.java:7)
             * 	at com.ydlclass.CustomizationException.Client.main(Client.java:23)
             */
            
        } catch (PasswordErrorException e){//业务的异常问题
            e.printStackTrace();//这个可以打印在我们的日志文件中,可以便于查找

            System.out.println("用户密码出现错误");
        }
    }
}

实现的方式二:(实现PasswordException的构造器,并且选择带有cause的构造器),将5行的代码简写为了一行;

package com.ydlclass.CustomizationException;

import java.util.Scanner;

public class Client {
    public static void fun1(){
        fun();
    }
    public static void fun(){
        Scanner scanner = new Scanner(System.in);
        String username = scanner.next();
        if(!"abc".equals(username)){
            throw new UsernameException("用户名错误",504);//这个字段可能需要我们创建时就维护
        }
        Scanner scanner1 = new Scanner(System.in);
        String passsword = scanner1.next();//注意类型
        if(!"123".equals(passsword)){
            throw new PasswordErrorException();
        }
    }
    public static void main(String[] args) {
        try{
            fun1();
        } catch (UsernameException e){//分别捕获不同的异常
//            e.printStackTrace();//当异常被捕获后使用这个方法来打印异常信息的这种方式,不会将程序打断掉。不同于jvM所抛出的异常
//            System.out.println(e.getCode());//由于自定义的异常添加了一个code的字段,使用这个字段可以用于标记我们想要的自定义数字
//            System.out.println(e.getMessage());//可以使用这句话来代替下面的内容
////            System.out.println("用户名出现错误");

//            PasswordErrorException passwordErrorException = new PasswordErrorException();//由于我们没有给这个异常一个构造器,所以我们使用
//            //initCause()方法来实现
//            passwordErrorException.initCause(e);
//            throw passwordErrorException;
//            //运行后出现的异常就可以发现passwordException的是由于UserErrorException这个异常导致的:
            throw new PasswordErrorException("密码异常错误",e); //前面的5行内容实现的效果和本行的效果相同,区别是当前的转台是将我们的构造器手写出来了
            //我们就可以使用这个构造器,并且将引发这个异常的原因异常传入到构造器的第二个字段中。
            
            /**
             * Exception in thread "main" com.ydlclass.CustomizationException.PasswordErrorException
             * 	at com.ydlclass.CustomizationException.Client.main(Client.java:29)
             * Caused by: com.ydlclass.CustomizationException.UsernameException: 用户名错误
             * 	at com.ydlclass.CustomizationException.Client.fun(Client.java:13)
             * 	at com.ydlclass.CustomizationException.Client.fun1(Client.java:7)
             * 	at com.ydlclass.CustomizationException.Client.main(Client.java:23)
             */

        } catch (PasswordErrorException e){//业务的异常问题
            e.printStackTrace();//这个可以打印在我们的日志文件中,可以便于查找

            System.out.println("用户密码出现错误");
        }
    }
}