Exception类

    技术2022-07-11  68

    异常类

    /*

    什么是异常(Exception)异常是程序在编译或运行过程中出现的例外,这些例外有的可以避免,有的却无法避免。Exception类继承自Throwable类,Throwable类还有一个子类ErrorError代表的是错误,不再是程序员编程处理的范围。检查异常也称为编译期异常不可避免,必须进行异常处理,要不编译器报错Exception以及它的子类(除去RuntimeException)未检查异常也称为运行时异常可以避免,不需要必须处理RuntimeException以及它的子类

    */

    常见的异常

    package SE02.n1Exception; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class Demo01Exception { public static void main(String[] args){ // 常见的运行时异常 // NullPointerException 空指针异常 String name=null; System.out.println(name.toString()); // ArithmeticException 算数异常 System.out.println(1/0); // ArrayIndexOutOfBoundsException 数组下标越界异常 String s[]=new String[2]; System.out.println(s[3]); // ClassCastException 类型转换异常 Object o=new Integer(20); String s= (String)o; // 常见编译期异常 // ParseException 解析异常 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); String string="1000年2月2日"; Date d=sdf.parse(string);//需异常处理 } }

    异常处理方法

    // Java编译期异常必须处理,否则编译器会提示错误,且源文件无法成功编译 // 处理方法两种 // 1.使用try_catch_finally关键字捕获并处理 // 2.使用throws关键字声明抛出异常,让别人去处理

    try_catch_finally关键字

    package SE02.n1Exception; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class Demo02try_catch { public static void main(String[] args) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); String string="1000年2月2日"; try { Date d=sdf.parse(string);//需异常处理 } catch (ParseException e) { // TODO 自动生成的 catch 块 System.out.println("try语句中发生异常,会跳转到此语句块执行"); e.printStackTrace();//打印栈路径 }finally { // 不论是否捕捉到异常都要执行的代码块 System.out.println("执行了finally代码块!!!"); } } }

    在try_catch语句块中有一个特殊情况:return的用法以及细节

    在try_catch_finally这三个语句块中分别执行return会有不同的细节,上代码!

    package SE02.n1Exception; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class Demo03Retrun { public static void main(String[] args) { System.out.println(test1()); // System.out.println(test2()); // System.out.println(test3()); // System.out.println(test4()); } private static String test1() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); String string="1000年2月2日";//代码正常,可以被正常年月日格式化 String rStr="begin"; try { Date d=sdf.parse(string);//需异常处理 return rStr;//上一条报错,此条不可达,不运行 }catch(ParseException e){ rStr="catch"; return rStr;//先封存,再finally,再return封存 }finally { rStr="finally"; return rStr; }

    当return写在finally代码块中时,无论是无异常还是有异常,最后返回的都是“finally” 接下来进行分类讨论: (1)当try语句中的代码无异常: try中的return rStr不会立马执行,会将rStr的内存地址封存在一个空间中,等finally代码块执行完才会return封存的内存地址,再根据内存地址寻找要输出的字符串。但是,当finally代码块中有return关键字时,程序会优先执行finally代码块中的return关键字,try语句块中的return封存的内存地址将被永久封存,return的是finally代码块中的rStr。 (2)当try语句中的代码需要异常处理: 同样的是封存try中的return,进入catch,再对catch中的return进行封存,最后执行finally中的代码块,若finally中有return语句,则执行finally中的return语句,而try和catch中return封存的值将永久封存,最终输出finally中的return。 所以上面代码输出的结果为:finally

    以上是finally中有return的情况

    下面介绍finally中没有return的情况

    话不多说先上代码!

    private static String test1() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); String string="2000年2月2日";//该字符串在格式化年月日时不会抛出异常,格式正确 String rStr="begin"; try { Date d=sdf.parse(string);//不需要异常处理 return rStr;//此条可达,执行 }catch(ParseException e){ rStr="catch"; return rStr;//先封存,再finally,再return封存 }finally { System.out.println("这里是finally代码块"); } }

    先上输出结果: 这里是finally代码块 begin 语句依次执行try—>catch—>finally。在执行try时:Date d=sdf.parse(string)执行完毕后,执行return语句,封存rStr的内存地址(begin),跳过catch语句块,执行finally语句块中的输出语句,最后return封存中的begin

    private static String test1() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); String string="2000年2月2日";//该字符串在格式化年月日时会抛出异常,非正确格式 String rStr="begin"; try { Date d=sdf.parse(string);//需要异常处理 return rStr;//此条不可达,不执行 }catch(ParseException e){ rStr="catch"; return rStr;//先封存,再finally,再return封存 }finally { System.out.println("这里是finally代码块"); } }

    先上输出结果: 这里是finally代码块 finally 同样,语句依次执行try—>catch—>finally。在执行try时:Date d=sdf.parse(string)会抛出异常,从而导致直接跳进catch语句块,使return不可达。进入catch语句后:此时rStr重新赋值。(注意!java中String类型的对象是固定的不变的,在本人的其他博客中有详细介绍String类型)此时的rStr和最开始定义的String rStr="begin"的内存地址是不同的,虽然变量名相同,但内存地址不同,这里的return封存的就是内存地址,所以现在封存的是catch。最后执行finally代码块的输出语句,再return rStr。

    以上是return String类型的语句看不出太明显的细节

    下面介绍return int类型的try_catch

    private static int test2() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); String string="100年2月2日"; int i =0; try { Date d=sdf.parse(string);//可能需异常处理的语句 i=1; return i; }catch(ParseException e){ System.out.println("catch"); i=2; System.out.println("ii"); return i;//先封存(基本数据类型的值)(八种数据类型的值可以直接放在栈中),再finally,再return封存 }finally { i=3; System.out.println("finally"); return i; } }

    先上结果: finally 3 同样如果finally中有return,不管try和catch中的封存,直接执行return中的封存。

    private static int test2() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); String string="100年2月2日"; int i =0; try { Date d=sdf.parse(string);//需异常处理 i=1; return i; }catch(ParseException e){ System.out.println("catch"); i=2; System.out.println("ii"); return i;//先封存(基本数据类型的值)(八种数据类型的值可以直接放在栈中),再finally,再return封存 }finally { i=3; System.out.println("finally"); } }

    先上结果: finally 1 需要注意的是:finally代码块中虽然i被重新赋值,但是try中的return已经率先封存了i=1的内存地址,所以… 与String类型相似的是:先封存(基本数据类型的值)(八种数据类型的值可以直接放在栈中),再finally,再return封存

    以上是int型与String类型类似,下面介绍一种比较特殊的类型

    自己新建一个Class:Person类 令try_catch语句的返回值为Person

    Person类

    package SE02.n1Exception; public class Person { int age=0; @Override public String toString() { return "Person [age=" + age + "]"; } } private static Person test3() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); String string="20**年2月2日"; Person p =new Person();//此时p.age=0 try { Date d=sdf.parse(string);//需异常处理的代码 System.out.println("try");//若进行异常处理,则代码不可达 }catch(ParseException e){ p.age=12; System.out.println("catch"); return p;//先封存(引用的地址值),再finally,再return封存 }finally { // p.age=11; System.out.println("finally"); } return p; }

    先上结果: catch finally Person [age=12] 由于封存的都是p的内存地址,所以每次p的属性被重新赋值都会改变封存中的内容。所以如果finally中有有关p对象的赋值语句,return中的封存内容就会被改写(内存地址值不变)。

    private static Person test3() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); String string="20**年2月2日"; Person p =new Person(); try { Date d=sdf.parse(string);//需异常处理 System.out.println("try"); }catch(ParseException e){ p.age=12; System.out.println("catch"); return p;//先封存(引用的地址值),再finally,再return封存 }finally { p.age=11; System.out.println("finally"); } return p; }

    先上输出结果: catch finally Person [age=11]

    当finally中有赋值语句,就会改写封存内容

    以上是返回Person类,下面看StringBuilder类的相关细节

    private static StringBuilder test4() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); String string="100#0年2月2日"; StringBuilder rStr=new StringBuilder("begin"); try { Date d=sdf.parse(string);//需异常处理 return rStr;//上一条报错,此条不可达,不运行 }catch(ParseException e){ rStr.append("catch"); return rStr;//先封存,再finally,再return封存 }finally { rStr.append("finally"); return new StringBuilder("finally"); } } }

    先上结果: finally 原因:finally中出现return,其他语句块的封存全部失效

    private static StringBuilder test4() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); String string="100#0年2月2日"; StringBuilder rStr=new StringBuilder("begin"); try { Date d=sdf.parse(string);//需异常处理 return rStr;//上一条报错,此条不可达,不运行 }catch(ParseException e){ rStr.append("catch"); return rStr;//先封存,再finally,再return封存 }finally { rStr.append("finally"); } } }

    注:有关StringBuilder的相关介绍和方法介绍在本人其他博客中有详解,请客官移步。 先上输出结果:begincatchfinally 从输出结果中可以看出,rStr游历了所有语句块,同样的是return封存了内存地址,而rStr对象中的属性改变,return出的rStr依旧会是append后的结果

    由于篇幅较长,下一篇写自定义异常

    Processed: 0.018, SQL: 9