异常的体系结构,产生原因,抛异常 ,异常的处理。全面的总结
在java中,程序运行过程中产生的问题叫做异常,在java中所有程序运行产生的问题都可以用一个类来表示,这个类叫做它Throwable,它有两个子类 Error:表示错误,程序中出现了不可挽回问题 Exception:表示异常,程序中出现的可以挽救补回的问题
异常产生原因流程
/* throw关键字,可以手动的抛出一个异常对象。 格式: throw new 异常类(); 注意: 只有异常体系下的类才具有可抛性。 一旦某个方法抛出异常,后面的代码都不会再执行了 */ public class Demo03Throw { public static void main(String[] args) { int[] a = new int[10]; //定义一个数组 int value = getValue(a, 10);//调用getValue获取数组指定索引的元素 System.out.println("value:" + value); } public static int getValue(int a[], int num) { if (num < 0 || num > a.length - 1) { //进行判断,如果num索引在一个不合法的范围内,那么就抛出异常 String msg = "这是一个数组越界异常"; throw new ArrayIndexOutOfBoundsException(msg); } System.out.println("你好");//并不会执行,因为之前抛了一个异常 return a[num]; } }
/* 空指针异常: Objects里面有一个方法,可以判断一个对象是否是null,如果是null会直接抛出一个空指针异常。 static <T> T requireNonNull(T obj):判断指定的对象是否是null。 static <T> T requireNonNull(T obj, String message): 第二个参数message表示异常信息。 */ public class Demo04Objects { public static void main(String[] args) { Object obj = null; /* if(obj==null) { throw new NullPointerException("某个对象的值为null"); }*/手动抛异常的方法 // Objects.requireNonNull(obj);//objects中的方法1 Objects.requireNonNull(obj, "这是一个空指针异常");//objects中的方法2 obj.toString(); System.out.println("sdf" + obj); } } 结果:Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 这是一个数组越界异常 at demo01exception.Demo03Throw.getValue(Demo03Throw.java:24) at demo01exception.Demo03Throw.main(Demo03Throw.java:16)
/* throw:手动的创建一个异常对象并抛出。是抛出 throws: 用来声明这个方法可能会抛出一个异常。 throws使用格式 修饰符 返回值类型 方法名(参数列表) throws 异常类名{ 方法体; return 返回值; } 注意: 1. 如果一个方法内抛出了编译时异常,那么一定要在这个方法上面加上throws异常声明。(也可以try...catch) 2. 如果方法内抛出的是运行时异常, 那么可以是使用throws声明,也可以不使用。 3. 如果一个方法内抛出了多个异常,可以使用throws关键字声明这个方法会抛出多个异常。 4. 如果一个方法可能抛出多个异常,那么除了第3种做法之外,也可以使用throws声明他 们的父类异常。 */ public class Demo05Throws { public static void main(String[] args) { } // 4. 如果一个方法可能抛出多个异常,那么除了第3种做法之外,也可以使用throws声明他们的父类异常。 public static void method4() throws Exception{ int i = 1; if(i % 2 == 0) { throw new IOException(); } else { throw new ClassNotFoundException(); } } //如果一个方法内抛出了多个异常,可以使用throws关键字声明这个方法会抛出多个异常。 public static void method3() throws IOException, ClassNotFoundException{ int i = 1; if(i % 2 == 0) { throw new IOException(); } else { throw new ClassNotFoundException(); } } //如果方法内抛出的是运行时异常, 那么可以是使用throws声明,也可以不使用。 public static void method2() { throw new ArrayIndexOutOfBoundsException(); } public static void method()throws IOException{ //手动抛出一个编译异常 //编译时异常是 Exception和Exception下面除了RuntimeException之外的其他子类 } }
/* 如果遇到异常之后,不希望把异常往外抛, 希望自己解决这个异常,那么可以使用try...catch关键字。 格式: try { 1. 要检测的代码 } catch(异常类名 变量名) { 2. 异常的处理方式的代码。 } 执行流程: 1. 会执行try中的代码,如果try中的代码没有出现异常,那么就会跳过catch往下执行。 2. 如果try中的代码出现了异常,并且catch捕获到了这个异常,那么就执行执行catch中的语句。 注意: 1. 如果try中的代码出现了问题,那么如果catch捕获到了这个异常,会直接进入到catch中。 2. 如果try中的代码出现了问题,但是catch并没有捕获到,那么这个异常会依旧抛给调用者。 总结: 异常有两种处理方式 1. 往外抛(甩锅) throw, throws 2. 自己真正的把这个异常给解决了 try...catch */ public class Demo06TryCatch { public static void main(String[] args) { try { Object obj = null; obj.toString(); System.out.println("1........try"); } catch (Exception e) { System.out.println("2.catch"); } System.out.println("2.catch---------"); } }
* try...catch...finally 格式: try { 【A. 要检测可能会出现异常的代码】 } catch(异常类名 变量名){ 【B.出现异常之后该怎么做的代码】 } finally { 【C. 一定会执行的代码 】 } 注意: 不管程序结果如何,finally代码块一定会执行。 执行流程: 假如try中的代码没有出现异常: 【A】【C】 假如try中的代码出现了异常并且catch捕获到了这个异常: 【A】【B】【C】 假如try中的代码出现了异常但是catch没有捕获到: 【A】【C】【把异常抛给调用者】 finally代码块不管怎样一定会执行。 finally代码块的使用场景。 一般用在释放资源。比如后期IO流释放资源,jdbc释放连接.... */ public class Demo07TryCatchFinally { public static void main(String[] args) { try { System.out.println("1...try start"); Object obj = null; obj.toString(); System.out.println("2...tryend"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("3..catch"); } finally { System.out.println("4...finally"); } } }
/*运行时异常和编译时异常的区别。 运行时异常: 指的是RuntimeException以及RuntimeException下面的所有子类。 编译时异常: 指的是Exception以及Exception下面除了RuntimeException之外的其他子类。 区别: 编译时异常: 当一个方法内抛出编译时异常,必须要进行处理。要么使用throws声明这个方法会抛出异常。要么使用trycatch直接把这个异常解决掉。 运行时异常: 一个方法抛出运行时异常,可以处理,也可以不处理。 如果希望让调用者知道自己这个方法可能会出现问题,那么最好用编译时异常。 如果不想让调用者知道我这个方法会有问题,那么可以使用运行时异常。 */ public class Demo08RunTimeException { public static void main(String[] args) { //运行时异常: 一个方法抛出运行时异常,可以处理,也可以不处理。 method2(); //如果运行时异常没有处理,等到程序运行的时候也会把这个异常抛给调用者。 } public static void method2() { throw new RuntimeException(); } public static void method1() { try { //抛出一个编译时异常 throw new Exception(); } catch (Exception e) { } } }
/*多个catch的异常处理方式 try { 要检测的代码 } catch(要捕获的异常 变量名) { 如果出现该异常对应的解决方案 } catch(要捕获的异常 变量名) { 如果出现该异常对应的解决方案 } catch(要捕获的异常 变量名) { 如果出现该异常对应的解决方案 } 执行流程: 如果try中的代码出现了问题,那么哪一个catch先捕获到,那么就执行哪个catch中的代码。 如果try中的代码没有任何问题,那么所有的catch都不执行。 注意事项: 如果使用多个catch捕获异常,那么父类异常不能放在子类异常的前面。因为子类异常能捕获到的,父类异常一定也可以捕获到,如果把父类异常放前面。父类异常会捕到所有的导致子类异常没有东西可以捕获。 */ public class Demo09TryCatchCatch { public static void main(String[] args) { try { Object obj = null; obj.toString(); System.out.println("1. try...end"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("2. ArrayIndexOutOfBoundsException"); } catch (NullPointerException e) { System.out.println("3. NullPointerException"); } catch (Exception e) { System.out.println("4. Exception"); } } }
/* 模拟注册的练习,定义方法,用来注册,如果这个注册的用户名已经存在,抛出异常。 */ public class Demo01ExceptionTest { private static String[] name = {"lalfa", "fas", "fdsf", "adbd"}; public static void main(String[] args) { // 定义数组,当做数据库,用来保存已经存在的用户名 try { //进行注册 regist("fas"); System.out.println("注册成功"); } catch (RegistException e) { System.out.println(e.getMessage()); } catch (Exception e) { System.out.println("出现了其他问题"); e.printStackTrace(); } } /* 定义一个方法,用来注册 参数是一个字符串,表示要注册的用户名 如果此用户名已经存在,那么就以抛出异常的方式提示注册失败。*/ public static void regist(String user) { for (String username : name) { if (user.equals(username)) { throw new RegistException("用户名" + user + "已经存在"); //抛的异常类型为自定义类型,需要创建一个类去继承任意异常 } } } } //自定义的异常
/* 如何自定义一个异常? 认贼作父。 找一个异常类当做父类。
如果使用一个类继承了异常类,那么这个类也就变成了异常类。
如果这个类继承的是编译时异常,那么这个类就会变成编译时异常类。 如果这个类继承的是运行时异常,那么这个类就会变成运行时异常类。
*/
//定义注册异常
public class RegistException extends RuntimeException { public RegistException() { } public RegistException(String Message) { super(Message); } }