异常
- 异常就是代表程序出现的问题
当一个方法出现问题,这个方法内部就会把这个问题的信息封装成一个异常对象,然后把这个异常对象抛给jvm虚拟机,jvm收到之后会先把出问题的程序先停下来,然后再把这个异常对象打印出来,里面会包含该问题的很多信息
例:
异常的体系
Error:代表的系统级别错误(属于严重问题),也就是说系统一旦出现问题,sun公司会把这些问题封装成Error对象给出来。说白了,Error是给sun公司自己用的,不是给我们程序员用的,因此我们开发人员不用管它
Exception:叫异常,它代表的才是我们程序可能出现的问题,所以,我们程序员通常会用Exception以及它的孩子来封装程序出现的问题
- 运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现的异常(如:数组索引越界异常)
- 编译时异常:编译阶段就会出现错误提醒的。(如:日期解析异常)
运行时异常:
刚才举出的例子就是运行时异常:
还有典型的数组越界异常:
编译时异常:
当你写代码时就会通过报错强制提醒你这个方法很容易出问题,提醒你最好认真检查一下~如果不检查不处理,程序将会报错。可以通过try catch捕获可能出现的异常抛出去,也可以通过throws把异常抛给上一层(jvm虚拟机)处理,当然jvm也不知道怎么处理你的问题,只是帮你去用rty catch去环绕问题代码
try catch 捕获异常:
throws抛出异常:
自定义异常
- Java无法为这个世界上全部的问题都提供异常类来代表,如果企业自己的某种问题,想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了。
自定义异常的种类:
自定义运行时异常
自定义异常继承类:
public class AgeIllegalRuntimeException extends RuntimeException{ //运行时异常必须继承自RuntimeExceptionpublic AgeIllegalRuntimeException() {}public AgeIllegalRuntimeException(String message) {super(message);}
}
test:
public class 自定义异常 {public static void main(String[] args) {try { //用try catch捕获异常SetAge(151); //非法值System.out.println("底层执行成功!");} catch (Exception e) {e.printStackTrace();System.out.println("底层出现bug!");}}private static void SetAge(int age) {if(age >= 0 && age <= 150){System.out.println("年龄设置成功");}else{ //触发else说明age的值有问题不合法//用一个异常对象封装这个问题//用throw抛出去throw new AgeIllegalRuntimeException("年龄异常,年龄为非法值(Age is illegal, your age is):"+age); } }
}
运行结果:
自定义编译时异常
public class AgeIllegalException extends Exception{ //编译时异常必须继承自Exceptionpublic AgeIllegalException() {}public AgeIllegalException(String message) {super(message);}
}
test:
public class 自定义异常 {public static void main(String[] args) {try { //用try catch捕获异常或抛出异常,否则直接报错SetAge(151); //非法值System.out.println("底层执行成功!");} catch (Exception e) {e.printStackTrace();System.out.println("底层出现bug!");}}private static void SetAge(int age) throws AgeIllegalException{if(age >= 0 && age <= 150){System.out.println("年龄设置成功");}else{ //触发else说明age的值有问题不合法//用一个异常对象封装这个问题//用throw抛出去//用throws用在方法上,抛出这个方法内部出现的异常throw new AgeIllegalException("年龄异常,年龄为非法值(Age is illegal, your age is):"+age);}}
}
运行结果:
总结:自定义运行时异常和自定义编译时异常用法是非常相似的,不过在效果上自定义编译时异常会在编译时就提醒你处理
异常有什么作用?
- 异常是用来查询系统Bug的关键参考信息
- 异常可以作为方法内部的一种特殊返回值,以便通知上层调用者底层的执行情况
开发中关于异常的常见处理方式
1、捕获异常,记录异常并响应合适的信息给用户
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class ExceptionTest2 {public static void main(String[] args) throws ParseException{try { //调用者捕获异常test1();} catch (Exception e) { //记录异常并响应合适的信息给用户System.out.println("您当前的操作有问题");e.printStackTrace();}}//直接抛Exception就行了,不用抛具体异常private static void test1() throws Exception{ //异常,抛给调用者SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date d = sdf.parse("2021-07-07 23:23:20");System.out.println(d);test2();}private static void test2() throws Exception{ //异常,抛给调用者SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date d = sdf.parse("2021-07-07 23:23");System.out.println(d);}
}
运行结果:
2、捕获异常,"尝试重新修复
import java.text.ParseException;
import java.util.Scanner;public class ExceptionTest3 {public static void main(String[] args) throws ParseException {while (true) { //循环围住,直到成功执行try {System.out.println(getMoney());break;} catch (Exception e) {System.out.println("请输入数字!");}}}private static double getMoney() {Scanner sc = new Scanner(System.in);while (true) { //循环围住,直到输入合适的价格或者非法价格(往上层抛异常)System.out.print("请输入合适的价格:");double money = sc.nextDouble(); //假如输入非double型就会往上抛异常if(money >= 0){return money;}else{System.out.println("您输入的价格不合适吧");}}}
}
运行结果:
可以大大增加程序的健壮性