https://blog.csdn.net/qq_18505715/article/details/73196421 最底层/最深处的函数抛出异常throws xxxException 上一层的函数处理异常try catch (继续进一步抛出异常)自定义异常trhow 自定义exception main()主函数处理最终的异常try catch
二、throws关键字 throws声明的方法表示该方法不处理异常,而由系统自动将所捕获的异常信息抛给上级调用方法。
三、throw关键字 throw的作用是手工抛出异常类的实例化对象。 我们能发现,throw好像属于没事找事,引发运行期异常,并自定义提示信息。事实上,throw通常和throws联合使用,抛出的是程序中已经产生的异常类实例
一、异常的抛出
1、定义 : 一个方法不处理这个异常,而是调用层次向上传递,谁调用这个方法,这个异常就由谁来处理。
2、throw : 将产生的异常抛出(强调的是动作),抛出的既可以是异常的引用,也可以是异常对象。(位置: 方法体内)
3、throws : 如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。用它修饰的方法向调用者表明该方法可能会抛出异常(可以是一种类型,也可以是多种类型,用逗号隔开)(位置: 写在方法名 或方法名列表之后 ,在方法体之前。)
注意 : 调用可能会抛出异常的方法,必须添加try-catch代码块尝试去捕获异常 或者 添加throws 声明 来将异常 抛出给更上一层的调用者进行处理,这里需要注意一个细节:新的异常包含原始异常的所有信息,根据这个我们可以去追溯最初异常发生的位置,
如下图所示
4、简单使用
// 定义一个方法,抛出 数组越界和算术异常(多个异常 用 "," 隔开) public void Test1(int x) throws ArrayIndexOutOfBoundsException,ArithmeticException{ System.out.println(x); if(x == 0){ System.out.println("没有异常"); return; } //数据越界异常 else if (x == 1){ int[] a = new int[3]; a[3] = 5; } //算术异常 else if (x == 2){ int i = 0; int j = 5/0; } }在main方法中调用
public static void main(String[] args) { //创建对象 //public void Test1(int x) throws ArrayIndexOutOfBoundsException,ArithmeticException{ ExceptionInital object = new ExceptionInital(); // 调用会抛出异常的方法,用try-catch块 try{ object.Test1(0); }catch(Exception e){ System.out.println(e); } // 数组越界异常 try{ object.Test1(1); }catch (ArrayIndexOutOfBoundsException e) { System.out.println("数组越界异常:"+e); } // 算术异常 try{ object.Test1(2); }catch(ArithmeticException e){ System.out.println("算术异常:"+e); } //使用 throw 抛出异常(可以抛出异常对象,也可以抛出异常对象的引用) try{ ArrayIndexOutOfBoundsException exception = new ArrayIndexOutOfBoundsException(); throw exception;//new ArrayIndexOutOfBoundsException(); }catch(ArrayIndexOutOfBoundsException e){ System.out.println("thorw抛出异常:"+e); } }总结下 throw 和throws 关键字的区别
1、写法上 : throw 在方法体内使用,throws 函数名后或者参数列表后方法体前 2、意义 : throw 强调动作,而throws 表示一种倾向、可能但不一定实际发生 3、throws 后面跟的是异常类,可以一个,可以多个,多个用逗号隔开。throw 后跟的是异常对象,或者异常对象的引用。 4、throws 用户抛出异常,当在当前方法中抛出异常后,当前方法执行结束(throws 后,如果有finally语句的话,会执行到finally语句后再结束。)。可以理解成return一样。
二、自定义异常
前面所讲的异常,都是系统自带的,系统自己处理,但是很多时候项目会出现特有问题,而这些问题并未被java所描述并封装成对象,所以对于这些特有的问题可以按照java的对问题封装的思想,将特有的问题进行自定义异常封装。在Java中要想创建自定义异常,需要继承Throwable或者他的子类Exception。 语法
class 自定义异常类 extends 异常类型(Exception){ // 因为父类已经把异常信息的操作都完成了, //所在子类只要在构造时,将异常信息传递给父类通过super 语句即可。 // 重写 有参 和 无参 构造方法 }例如:
package cn.itcast.itcaststore.exception; public class RegisterException extends Exception{ private static final long serialVersionUID = 1L; public RegisterException() { super(); // TODO Auto-generated constructor stub } public RegisterException(String message, Throwable cause) { super(message, cause); // TODO Auto-generated constructor stub } public RegisterException(String message) { super(message); // TODO Auto-generated constructor stub } public RegisterException(Throwable cause) { super(cause); // TODO Auto-generated constructor stub } } public class CustomException extends Exception { //无参构造方法 public CustomException(){ super(); } //有参的构造方法 public CustomException(String message){ super(message); } // 用指定的详细信息和原因构造一个新的异常 public CustomException(String message, Throwable cause){ super(message,cause); } //用指定原因构造一个新的异常 public CustomException(Throwable cause) { super(cause); } } // 备注: 这些方法怎么来的? 重写父类Exception的方法,那么如何查看Exception具有哪些API,快捷键:选中Exception, command+单击。windows系统 :选中Exception, control+单击。自定义异常的使用例子: 自定义test1()方法,抛出 "我喝酒了"的异常信息, test2()方法调用test1()方法,并将异常包装成RuntimeException类型的异常,继续抛出, 在main方法中调用test2()方法,并尝试捕获异常
public void test1() throws CustomException{ throw new CustomException("我喝酒了"); } public void test2() { try{ test1(); }catch (CustomException e){ //exception.initCause(cause) throw new RuntimeException(e); } } // main方法 public static void main(String[] args) { CustomExceptionInital object = new CustomExceptionInital(); //try{ object.test2(); //}catch(Exception e){ //e.printStackTrace(); //} }思考 ? 为什么上述demo, test1() 方法 抛出异常了,但是test1() 方法自己没办法处理,所以在 参数列表后方法体前将该异常抛出了,test2() 方法调用了test1()方法捕获其异常,并将其异常 包装成 RuntimeException 异常继续抛出,但是test2()方法却没有声明 抛出异常 ? 而且,在main 方法中,调用test2()方法的时候,也不用try-catch 代码块去捕获 异常呢 ?
https://blog.csdn.net/qq_18505715/article/details/76696439 https://download.csdn.net/download/qq_18505715/9870283
1 public class ExceptionDemo 2 { 3 public static void main(String[] args) 4 { 5 int[] a = new int[5]; 6 try 7 { 8 setZero(a,10); 9 } 10 catch(ArrayIndexOutOfBoundsException e) 11 { 12 System.out.println("异常:"+e); 13 } 14 System.out.println("main()方法结束!"); 15 } 16 public static void setZero(int[] a,int index) throws ArrayIndexOutOfBoundsException 17 { 18 System.out.println("setZero方法开始:"); 19 try 20 { 21 a[index] = 0; 22 } 23 catch(ArrayIndexOutOfBoundsException ex) 24 { 25 throw ex; 26 } 27 finally 28 { 29 System.out.println("setZero方法结束。"); 30 } 31 } 32 } ExceptionDemo输出结果:
setZero方法开始: setZero方法结束。 异常:java.lang.ArrayIndexOutOfBoundsException: 10 main()方法结束!四、RuntimeException类
Exception和RuntimeException的区别:
Exception:强制性要求用户必须处理;
RunException:是Exception的子类,由用户选择是否进行处理。 五、自定义异常类
自定义异常类继承自Exception类, 可以使用父类的大量的方法, 也可自己编写方法来处理特定的事件。 Java提供用继承的方式运行用户自己编写的异常类。
class MyException extends Exception { public MyException(String message) { super(message); } } public class DefinedException { public static void main(String[] args) { try { throw new MyException("\n自定义异常类!"); } catch(MyException e) { System.out.println(e); } } }自定义异常
如果要自定义异常类,则扩展Exception类即可,因此这样的自定义异常都属于检查异常(checked exception)。如果要自定义非检查异常,则扩展自RuntimeException。
按照国际惯例,自定义的异常应该总是包含如下的构造函数:
一个无参构造函数 一个带有String参数的构造函数,并传递给父类的构造函数。 一个带有String参数和Throwable参数,并都传递给父类构造函数 一个带有Throwable 参数的构造函数,并传递给父类的构造函数。下面是IOException类的完整源代码,可以借鉴。
public class IOException extends Exception { static final long serialVersionUID = 7818375828146090155L; public IOException() { super(); } public IOException(String message) { super(message); } public IOException(String message, Throwable cause) { super(message, cause); } public IOException(Throwable cause) { super(cause); } }异常的注意事项 三, java里对异常的处理 java里对异常的处理有三种. 3.1 程序猿对有可能出现的异常使用try catch处理. 例如我们将上面的例子改动一下:
package Exception_kng; class Exp2{ public int f(int a, int b){ int i = 0; try{ i = a/b; } catch(Exception e){ System.out.printf("Exception occurs!!\n"); System.out.println(e.getMessage()); //print the root cause System.out.printf("===========================\n"); e.printStackTrace(); //print the info of function stuck. } return i; } } public class Expt_2{ public static void g(){ Exp2 ex = new Exp2(); int i = ex.f(8,0); //call f() System.out.printf("i is %d\n", i); //successfully executed } }在f()函数中对可能 出现的异常的代码进行try catch处理后, 程序会执行catch里的代码. 而且不会中断整个程序, 继续执行try catch后面的代码.
程序执行输出:
[java] Exception occurs!! [java] / by zero [java] =========================== [java] java.lang.ArithmeticException: / by zero [java] at Exception_kng.Exp2.f(Expt_2.java:7) [java] at Exception_kng.Expt_2.g(Expt_2.java:23) [java] at Enter_1.main(Enter_1.java:31) [java] i is 0注意最终也执行了g()函数中的最后一条语句, 输出了i的值. 也就是说try catch处理后并不会终止程序, 令程序即使出现了错误, 也可以对错误进行一定的处理后继续执行. 这就是java异常机制比c语言安全的地方. 下面会详细讲解 try catch. 注: getMessage() 方法: Exception类的方法之一, 返回异常的原因, 上面的 / by zero 就是这个方法输出的. printStackTrace(): Exception类的方法之一, 在屏幕输出函数栈信息, 也就是异常出现的地方.
3.2 函数里并不处理异常, 使用throw or throws 关键字 把可能出现的异常抛给调用该函数的上级函数处理.
例如我在f()函数中不想处理可能出现的异常, 想把它抛出上级函数处理:
下面是个例子:
package Exception_kng; class Exp3{ public int f(int a, int b){ if (0 == b){ throw new ArithmeticException("Shit !!! / by zero!"); } return a/b; } } public class Expt_3{ public static void g() throws ArithmeticException{ Exp3 ex = new Exp3(); int i = 22; i = ex.f(8,0); //throw excetpion System.out.printf("i is %d\n", i); //failed executed System.out.printf("g() is done!!\n"); //failed executed } public static void h(){ try{ g(); }catch(ArithmeticException e){ System.out.printf("Exception occurs!!\n"); System.out.println(e.getMessage()); //print the root cause System.out.printf("===========================\n"); e.printStackTrace(); //print the info of function stuck. } System.out.printf("h() is done!!\n"); //successfully executed } }可以见到f() 加了个条件判断, 如果参数b = 0, 使用throw 直接手动抛出1个异常. 让调用它的函数处理.
g()调用f()函数, 预见到f()可能有异常, 但是也不想处理, 使用throws 关键字告诉调用它的函数本函数有可能抛出这种异常. // 注, 这里的throws对程序并没有实质的影响.
h()调用g(), 简单g()定义的throws, 用try catch在本函数进行处理.
输出:
[java] Exception occurs!! [java] Shit !!! / by zero! [java] =========================== [java] java.lang.ArithmeticException: Shit !!! / by zero! [java] at Exception_kng.Exp3.f(Expt_3.java:6) [java] at Exception_kng.Expt_3.g(Expt_3.java:18) [java] at Exception_kng.Expt_3.h(Expt_3.java:25) [java] at Enter_1.main(Enter_1.java:31) [java] h() is done!!