Java异常相关知识总结
异常:
概述:java程序运行过程中出现的错误
常见的异常:
StackOverflowError
ArrayIndexOutOfBoundsException
NullPointerException
ClassCastException
ParseException
异常的分类:
Trowable:
1.--Error: a.相当于天灾人祸,虚拟机出现了问题
2.--Exception:
1).RuntimeException:运行过程中出现的异常 可以处理可以不处理,一般出现这种问题都是代码逻辑有问题,推荐修改代码
2).编译期异常:出发之前因该检查的异常,必须处理,负责编译不通过
1,编译时异常: 除了RuntimeException及其子类,Exception中所有的子类都是,这种异常必须要处理,要不编译通不过。
2,运行时异常 :RuntimeException及其子类都是,这种异常不用处理,编译会通过,不过这样的程序会有安全隐患,遇到这种异常是需要改代码的。
3,严重错误问题 :用Error进行描述,这个问题发生后,一般不编写针对代码进行处理,而是要对程序进行修正.通常都是由虚拟机抛出的问题。
举例说明:
异常分三类:
骑车去旅行:
Error:走到半路上,发生山路塌陷,或者出现了泥石流,这个问题很严重,不是班长能够立马解决的。
Exception:出门前,班长要看看车轮子以及车链子等是否还在
RuntimeException:在骑车的过程中,有好路不走,偏偏要走石子路
异常举例:
1 //异常测试: 2 // a.除数为0 3 // b.数组越界 4 public class HomeWork_02 { 5 public static void main(String[] args) { 6 System.out.println("start"); 7 f1(); 8 //f2(); 9 System.out.println("end"); 10 } 11 //数组越界异常 12 public static void f2(){ 13 int[]arr={1,2,3}; 14 System.out.println(arr[0]); 15 System.out.println(arr[1]); 16 System.out.println(arr[2]); 17 //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3 18 } 19 //除数为0异常 20 public static void f1(){ 21 int a=23; 22 int b=0; 23 System.out.println(a/b);//ArithmeticException: / by zero 24 } 25 }
jvm对异常的默认处理:
a. 哪个线程出现的问题
b. 异常的类型以及详细信息
c. 调用栈信息
d. 终止程序
如下图为异常举例代码中数组溢出是jvm所报的错误:
因为jvm处理异常的时候直接停止了程序,所以我们要学会自己处理异常:
如何自己处理异常:
a. try...catch...finally
b. throws
1. try...catch...finally语句
try {
要检查的代码
} catch (异常类型 对象名) {
对异常的处理
} finally {
释放资源
}
a. 一种异常的情况
1 public class ExceptionDemo_03 { 2 public static void main(String[] args) { 3 System.out.println("Start"); 4 int a =10; 5 int b=0; 6 try{ 7 System.out.println(a/b); 8 System.out.println("one"); 9 System.out.println("two"); 10 System.out.println("three"); 11 }catch(ArithmeticException e){ 12 System.out.println("除数为0"); 13 System.out.println(e); 14 } 15 System.out.println("end"); 16 } 17 }
//问题:为什么e局部变量会有值?
//如果try里面出现了异常, JVM会把异常信息封装成对应类型的异常对象。
//然后和catch语句依次匹配,找到对应的异常类型,然后把它赋值给引用变量e
输出结果:
注意事项:
a. try里面的代码越少越好,最好只放可能出现异常的代码
b. try里面出现了异常,就不会执行try里面里面后序的代码
c. ArithmeticException e 是局部变量, 作用范围是对应的catch语句。
d. catch 捕获了异常,执行对应的处理,异常就不再存在了。
b.多种异常的情况:
a. 一个一个处理
b. 一次性处理
c. JDK7 新特性
把多个处理方式相同的catch语句,合成一个catch语句。
catch(类型1 | 类型2 | 类型3... e)
注意事项:
一个try语句中, 最多只会抛出一个异常,最多也只会执行一个catch语句
如果异常没有兼容惯性,谁先谁后没关系,如果有兼容关系,那么父类应该方法在子类之后。
JDK7新特性, 一个catch 语句不能出现子父类关系
测试代码:
1 /*多种异常的情况: 2 a. 一个一个处理 3 b. 一次性处理 4 处理方式相同的catch语句,合成一个catch语句。 5 catch(类型1 | 类型2 | 类型3... e)*/ 6 public class ExceptiomDemo_04 { 7 public static void main(String[] args) { 8 System.out.println("start"); 9 /*try { 10 f1(); 11 f2(); 12 // f2()在后面的时候,执行到f1()的时候就不再往下执行了,没有输出arr[0],arr[1],arr[2] 13 } catch (ArithmeticException e) { 14 // System.out.println("除数为0"); 15 System.out.println("发生了异常"); 16 } catch (ArrayIndexOutOfBoundsException e) { 17 // System.out.println("数组索引越界"); 18 System.out.println("发生了异常"); 19 } catch (Exception e) { 20 System.out.println("其他异常"); 21 }*/ 22 try { 23 f2(); 24 f1(); 25 } catch (ArithmeticException | ArrayIndexOutOfBoundsException e) { 26 System.out.println("除数为0或者数组索引越界"); 27 } 28 29 30 } 31 public static void f2(){ 32 int []arr={1,2,3}; 33 System.out.println(arr[0]); 34 System.out.println(arr[1]); 35 System.out.println(arr[2]); 36 System.out.println(arr[3]); // ArrayIndexOutOfBoundsException: 3 37 } 38 public static void f1(){ 39 int a =10; 40 int b=0; 41 System.out.println(a/b);// ArithmeticException: / by zero 42 43 } 44 } 45
编译期异常和运行时异常:
Exception:
|-- 运行时异常: RuntimeException和其子类。
可以显示处理,也可以不处理,一般出现运行时异常,都是代码逻辑有问题,推荐修改代码逻辑。
|-- 编译期异常:其他类。无论运行时是否发生异常,都必须显示处理,否则无法通过编译。
测试代码:
1 import java.text.ParseException; 2 import java.text.SimpleDateFormat; 3 import java.util.Date; 4 import java.util.SimpleTimeZone; 5 6 //编译期异常和运行时异常: 7 public class ExecptionDemo_05 { 8 //一般不要在主方法中抛出异常,这里为方便在主方法中抛出异常 9 public static void main(String[] args) throws ParseException { 10 //运行时异常: 11 int a=10; 12 int b=0; 13 try{ 14 System.out.println(a/b); 15 }catch(ArithmeticException e){ 16 System.out.println("除0异常"); 17 } 18 //编译期异常,不解决不能通过编译 19 Date time=new Date(); 20 SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 21 String date=sf.format(time); 22 System.out.println(date); 23 Date date1=sf.parse(date);//ParseException 24 } 25 }
Throwable
Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。
类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。
构造方法摘要:
Throwable()
构造一个将 null 作为其详细消息的新 throwable。
Throwable(String message)
构造带指定详细消息的新 throwable。
成员方法:
返回此 throwable 的详细消息字符串。
默认实现:getClass().getName()+“:”+getMessage();
返回此 throwable 的简短描述。
void printStackTrace() //推荐使用它,而且输出内容会用红色标识
将此 throwable 及其追踪输出至标准错误流。
注意:通常e.getMessage()并不能获取全部的错误信息,需要用到e.printStackTrace()查看完整错误信息,但是这个方法是void 只能在控制台输出。
测试代码:
1 import java.text.ParseException; 2 import java.text.SimpleDateFormat; 3 import java.util.Date; 4 5 //Throwable():、 6 public class ExceptionDemo_06 { 7 public static void main(String[] args) { 8 String s = "2001/01/01 00:00:00"; 9 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 10 Date date = null; 11 try{ 12 date=sdf.parse(s); 13 }catch(ParseException e){ 14 System.out.println("解析异常"); 15 System.out.println(e.getMessage()); 16 System.out.println(e.toString()); 17 e.printStackTrace(); 18 } 19 } 20 }
thorws
定义功能方法时,需要把出现的问题暴露出来让调用者去处理。那么就通过throws在方法上标识。
举例:
村里出现了问题,如果能自己解决就自己解决,解决不掉就交给乡里,乡里解决不掉就抛给县里解决, 县里解决不掉,抛给市里,如果市里解决不掉,抛给省里,如果省里解决不掉,抛给中央。中央就直接干掉。
throws: 把问题抛给调用者
a.编译期异常
b.运行期异常
注意事项:
不要在main()方法抛出异常,如果抛出异常就会执行JVM的默认处理。
测试代码:
1 import java.text.ParseException; 2 import java.text.SimpleDateFormat; 3 import java.util.Date; 4 5 public class ExceptionDemo_07 { 6 public static void main(String[] args) { 7 String s = "2019/7-9 11:31:00"; 8 String pattern = "yyyy-MM-dd HH:mm:ss"; 9 Date date = null; 10 try { 11 date = string2Date(s, pattern); 12 } catch (ParseException e) { 13 e.printStackTrace(); 14 } 15 System.out.println(date); 16 int a = 10; 17 int b = 0; 18 int c = 0; 19 try { 20 c = f1(a, b); 21 } catch (Exception e) { 22 e.printStackTrace(); 23 } 24 System.out.println("c = " + c); 25 System.out.println("end"); 26 } 27 //throw:告诉调用者,注意:调用这个方法可能会有某某异常 28 public static Date string2Date(String s, String pattern) throws ParseException { 29 SimpleDateFormat sdf = new SimpleDateFormat(pattern); 30 return sdf.parse(s); 31 } 32 public static int f1(int a, int b) throws Exception{ 33 // return a / b; 34 if (b != 0) { 35 return a / b; 36 } 37 throw new Exception("除0异常"); 38 } 39 }
throw
在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。
测试代码:
throws和throw的区别
throws
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常
throw
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定会出现异常, throw抛出了一个实实在在的异常
1 import java.util.Scanner; 2 3 //举例: 4 // 录入学生成绩 [0~100] 5 public class ExecptionDemo_08 { 6 public static void main(String[] args) { 7 System.out.println("请输入学生成绩"); 8 Scanner sr =new Scanner(System.in); 9 int score=sr.nextInt(); 10 //数据验证 11 try{ 12 checkScore(score); 13 }catch(Exception e){ 14 e.printStackTrace(); 15 16 } 17 } 18 public static void checkScore(int score) throws Exception { 19 if(score<0||score>100){ 20 throw new Exception("score="+score); 21 } 22 //throw抛出了异常后,后面的语句就不再执行 23 System.out.println("one"); 24 System.out.println("two"); 25 System.out.println("three"); 26 } 27 }
我们到底该怎么处理异常:
原则:如果该方法知道如何处理,那用try...catch, 如果不知道怎么处理,就抛给它的调用者去处理。
区别:
如果try...catch,后续代码会执行。
如果throws,后续代码不会被执行。
try语句的变形
try...catch
try...finally
try...catch...finally
try...catch...catch...
try...catch...catch...finally
finally语句:
特点:
被finally控制的语句体无论出现异常还是没有出现异常,都会执行。
特殊情况:在执行到finally之前jvm退出了. System.exit();
作用:
释放系统资源
final和finally和finalize区别:
final: 最终的
类:不能被继承
方法:不能被重写
变量:常量
finally:
try语句的子句。
finally里面的语句, 无论出现异常还是不出现异常,都会被执行。
用来释放资源。
finalize:
Object中的方法。
对象被回收前,该方法会被自动执行。用来释放资源。
手动调用该方法,对象不会被回收。
1 import java.text.ParseException; 2 import java.text.SimpleDateFormat; 3 import java.util.Date; 4 5 public class ExceptionDemo_09 { 6 public static void main(String[] args) { 7 String s = "2019/7/9 14:40:00"; 8 String pattern = "yyyy-MM-dd HH:mm:ss"; 9 SimpleDateFormat sdf = new SimpleDateFormat(pattern); 10 try { 11 Date date = sdf.parse(s); 12 } catch (ParseException e) { 13 e.printStackTrace(); 14 //finally只有在执行到finally之前虚拟机就退出的时候才会不执行 15 //System.exit(0); 16 } finally { 17 System.out.println("finally子句"); 18 } 19 System.out.println("end"); 20 } 21 }
如果catch里面有return语句,请问finally的代码还会执行吗?如果会,请问结果是怎样的?
finally语句会被执行
第一次执行return语句,就已经生成了返回路径, 并把返回值保存起来了。
后面在finally语句中修改变量,不会影响返回值。
如果finally中也有return语句。
最终执行的是finally中语句。
1 public class ExceptionDemo10 { 2 public static void main(String[] args) { 3 System.out.println(method()); //40 4 } 5 6 public static int method() { 7 String s = "2019/7/9 14:40:00"; 8 String pattern = "yyyy-MM-dd HH:mm:ss"; 9 SimpleDateFormat sdf = new SimpleDateFormat(pattern); 10 int a = 10; 11 try { 12 a = 20; 13 Date date = sdf.parse(s); 14 } catch (ParseException e) { 15 a = 30; 16 return a; 17 } finally { 18 System.out.println("finally"); 19 a = 40; 20 return a; //生成了另外一条返回路径 21 } 22 23 } 24 }
自定义异常:
类名就代表异常的种类(信息)
编译期异常:继承Exception
运行时异常:继承RuntimeException
异常类:
1 public class ScoreException extends RuntimeException { 2 public ScoreException(){ 3 super(); 4 } 5 public ScoreException(String message){ 6 super(message); 7 } 8 }
测试类:
1 public class EceptionDemo_11 { 2 public static void main(String[] args) { 3 System.out.println("请录入学生成绩;"); 4 Scanner scanner = new Scanner(System.in); 5 int score = scanner.nextInt(); 6 // 数据验证 7 /*try { 8 checkScore(score); 9 // 存入数据库 10 } catch (ScoreException e) { 11 e.printStackTrace(); 12 }*/ 13 checkScore(score); 14 } 15 private static void checkScore(int score) throws ScoreException{ 16 if (score < 0 || score > 100) { 17 // throw new RuntimeException("score=" + score); 18 throw new ScoreException("score=" + score); 19 } 20 } 21 }
异常注意的事项:(编译期异常)
子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。
如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws
儿子不能比父亲更坏。一代只能比一代强。
编译的时候,不检查运行时异常