方法的调用是在栈中进行的,方法之间也可以相互调用,所以我们把这种方法在栈中调用的轨迹称为堆栈信息,简称栈轨迹。
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("用户密码出现错误");
}
}
}