异常简单的说就是程序出现了不正常的情况。
异常类的祖先类就是Throwable类,其实严格来说它还有一个父亲类Object,但是这个时候我们说的是所有异常的祖先类都是Throwable类中
而异常祖先了类(Throwable)分为两种,一种是error问题,这类的问题属于严重问题,一般我们不需要处理,还有一种就是我们平时遇到最多的Exception类的异常类。
而Exception类再往下就是编译异常(非RuntimeException)和运行异常(RuntimeException)。
编译异常就是在编译器就必须处理的异常,否则无法正常运行,简单的说就是在编译时报红的字段就是编译异常。
运行异常,就是编译的时候不检查,等到运行的时候就会报错的异常,也就是编译时为报红,但是在执行测试的时候会报错的异常。
Throwable中的方法之间的区别:
String getMessage():返回此throwable的详细消息字符串,通过Throwable中的成员变量和构造方法来获得getMesssage,因为在try里创建的异常对象,会对应异常的祖父类中方法带入对应的参数,以下同理(也就是返回异常的原因)
String toString():返回此可抛出的简短描述(也就是返回异常的原因和异常的类名,也就是包含了getMessage中的信息)
void printStackTrace():把异常的错误信息输出再控制台上(也就是返回异常的类名,异常的原因和异常的位置,因为是这三个方法中最全的所以一般是用此方法来处理异常)
而在JVM虚拟机遇到异常时,会先把异常相关信息输出在控制台,然后从异常的位置后面就不执行了,但是有时候我们就想让异常后面的代码继续执行,这个时候我们就有了两种方法:
第一种:处理异常
通过try-catch-finally来处理对应的异常,通过try来运行可能出错的代码段,然后如果出错了,会在错的代码段创建对应的异常类,然后会通过catch来捕捉,捕捉可以继续Throwable中的方法来显示对应的信息,最后可以用finally不管try和catch怎么终止就比如return,finally都会在return之前运行。
第二中:抛出异常
通过throws,在异常存在的方法中使用throws来抛出异常,丢给调用该方法的地方,同时接到该异常后可以进行try-catch来处理,所以异常的处理只有try-catch的方法。
格式一:就是不处理这个异常抛出
public static void main(String[] args) throws ParseException {
System.out.println("开始");
method();//这里看上面使用了thross又把这个异常抛出main方法
System.out.println("结束");
}
public static void method() throws ParseException {
SimpleDateFormat se = new SimpleDateFormat();
String s = "2000-2-30";
Date d = se.parse(s);//把这个异常抛给main方法中的method
System.out.println(d);
}
格式二:再main方法中处理异常
public static void main(String[] args) {
System.out.println("开始");
try {
method();
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("结束");
}
public static void method() throws ParseException {
SimpleDateFormat se = new SimpleDateFormat();
String s = "2000-2-30";
Date d = se.parse(s);//把这个异常抛给main方法中的method
System.out.println(d);
}
}
throw的用法:throw new 异常类名(String message);
这里的异常类名可以看代码运行报错的异常类名获得,或者时自定义异常,然后通过自定义的异常类名来在catch中捕捉,这里的message最终是会传到祖先类Throwable类中的成员变量detaiMessage中,最后可以通过getmessage或者Throwable中的其他成员方法得到。
自定义异常:
自定义的异常要注意继承的是RunTimeException类还是非RunTimeException类,其中要在自定义异常设置构造方法:无参构造和有参构造,下面我们来看一段自定义异常:
格式:
public class ScoreError extends Exception{
public ScoreError(){};
public ScoreError(String message){
super(message);
}
}
上面有两个构造器我们来看不同的效果:
我们先看定义好的测试类:
public class TeacherTest {
public static void main(String[] args) throws ScoreError {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个数");
int i = sc.nextInt();
Teacher teacher =new Teacher();
teacher.Score(i);
}
}
无参构造:
public void Score(int score) throws ScoreError {
if (score<0 | score>100){
throw new ScoreError();
}else {
System.out.println("成绩正常");
}
}
得到的是:
请输入一个数
102
Exception in thread "main" Test.ScoreError
at Test.Teacher.Score(Teacher.java:7)
at Test.TeacherTest.main(TeacherTest.java:11)
有参构造
public void Score(int score) throws ScoreError {
if (score<0 | score>100){
throw new ScoreError("你输入的成绩有误");
}else {
System.out.println("成绩正常");
}
}
运行时的结果:
请输入一个数
102
Exception in thread "main" Test.ScoreError: 你输入的成绩有误
at Test.Teacher.Score(Teacher.java:7)
at Test.TeacherTest.main(TeacherTest.java:11)
根据前面的自定义异常我们发现:使用无参构造的时候,得到的是异常的类名和异常的位置,而有参构造得到的是异常的原因和异常的位置和异常的类名,所以我们发现有参构造传入到父类的是异常的原因,能更方便我们知道错误。
try中的return问题:
1.如果使用return返回值,如果有catch,那么try中是不会有return的同时如果没有catch,只有try和finally,如果try和finally中都有return,最后只会返回finally中的return值,如果finally没有则会返回try中的return值,同理与catch和finally。
2.ry中有return,那么finally中的code也会执行,但是是再return之前,要不然不会有意义,,也就是try中执行到try后会去执行finally,等finally执行完成后再执行return,如果finally中有return,那么try中的return就不会执行
关键字:throw,throws,try和catch的用法如下:
1、throws出现在方法的声明中,表示该方法可能会抛出的异常,抛给调用该方法的方法中,允许throws后面跟着多个异常类型。
2、throw出现在方法体中,用于抛出异常。当方法在执行过程中遇到异常情况时,将异常信息封装为异常对象,然后throw,一般来说是和try-catch中使用,同时throw抛出异常后,后面的代码就不会执行。
3、try出现在方法体中,它自身是一个代码块,表示尝试执行代码块的语句。如果在执行过程中有某条语句抛出异常,那么代码块后面的语句将不被执行。
4、catch出现在try代码块的后面,自身也是一个代码块,用于捕获异常try代码块中可能抛出的异常。catch关键字后面紧接着它能捕获的异常类型,所有异常类型的子类异常也能被捕获。