阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

JAVA中异常处理

190次阅读
没有评论

共计 8775 个字符,预计需要花费 22 分钟才能阅读完成。

1、异常概述

异常:异常就是 Java 程序在运行过程中出现的错误。
异常由来:问题也是现实生活中一个具体事务,也可以通过 java 的类的形式进行描述,并封装成对象。其实就是 Java 对不正常情况进行描述后的对象体现。
我们见过的异常, 角标越界异常, 空指针异常

jvm 对异常的默认处理方案

如果程序出现了问题,我们没有做任何处理,最终 jvm 会做出默认的处理。

把异常的名称,原因及出现的问题等信息输出在控制台。

同时会结束程序。

案例一:

public static void main(String[] args) {// 第一阶段 int a = 10; int b = 0; System.out.println(a / b); }

运行结果

Exception in thread "main" java.lang.ArithmeticException: / by zero at cn.itcast_01.ExceptionDemo.main(ExceptionDemo.java:29)

案例二:

public static void main(String[] args) {int[] arr = {10,9,8}; System.out.println(arr[3]); }
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3 at cn.itcast_01.ExceptionDemo.main(ExceptionDemo.java:27)

案例三:

public static void main(String[] args) {String str = null; System.out.println(str.length()); }
Exception in thread "main" java.lang.NullPointerException at cn.itcast_01.ExceptionDemo.main(ExceptionDemo.java:26)

2、异常的分类

  • 编译时异常
  • 运行时异常
  • 严重错误问题

JAVA 中异常处理

编译时异常

​ 除了 RuntimeException 及其子类,Exception 中所有的子类都是, 这种异常必须要处理, 要不编译通不过

运行时异常

​ RuntimeException 及其子类都是, 这种异常不用处理, 编译会通过, 不过这样的程序会有安全隐患, 遇到这种异常是需要改代码的

严重错误问题

用 Error 进行描述, 这个问题发生后, 一般不编写针对代码进行处理, 而是要对程序进行修正. 通常都是由虚拟机抛出的问题

3、异常处理方案

  • JVM 的默认处理方案
  • try…catch…finally
  • throws

try…catch…finally 的异常处理方案

3.1、格式

try {可能出现问题的代码;}catch(异常名 变量) {针对问题的处理;}finally {释放资源;}

3.2、变形格式

try {可能出现问题的代码;}catch(异常名 变量) {针对问题的处理;}

3.3、注意事项

​ A:try 里面的代码越少越好

​ B:catch 里面必须有内容,哪怕是给出一个简单的提示

** 案例演示一:** 一个异常的处理

public static void main(String[] args) {// 第一阶段 int a = 10; // int b = 2; int b = 0; try {System.out.println(a / b);// 有异常,被捕获 } catch (ArithmeticException ae) {System.out.println("除数不能为 0");// 异常处理代码 } // 第二阶段 System.out.println("over"); }

程序运行结果:

 除数不能为 0
over

** 案例演示二:** 两个异常的处理

格式:

a: 每一个写一个 try...catch try {可能出现问题的代码;}catch(异常名 变量) {针对问题的处理;} b: 写一个 try,多个 catch try{...}catch(异常类名 变量名) {...} catch(异常类名 变量名) {...}

a 方案的实现

public static void method() {int a = 10; int b = 0; try {System.out.println(a / b); } catch (ArithmeticException e) {System.out.println("除数不能为 0"); } int[] arr = { 1, 2, 3 }; try {System.out.println(arr[3]); } catch (ArrayIndexOutOfBoundsException e) {System.out.println("你访问了不该的访问的索引"); } System.out.println("over"); }

b 方案的实现

public static void method3() {int a = 10; int b = 0; int[] arr = { 1, 2, 3 }; try {System.out.println(arr[3]); System.out.println(a / b); } catch (ArithmeticException e) {System.out.println("除数不能为 0"); } catch (ArrayIndexOutOfBoundsException e) {System.out.println("你访问了不该的访问的索引"); } System.out.println("over"); }

注意问题:多个异常,爷爷一定要在儿子或孙子后面

public static void method4() {int a = 10; int b = 0; int[] arr = { 1, 2, 3 }; // 爷爷在最后 try {System.out.println(a / b); System.out.println(arr[3]); System.out.println("这里出现了一个异常,你不太清楚是谁,该怎么办呢?"); } catch (ArithmeticException e) {System.out.println("除数不能为 0"); } catch (ArrayIndexOutOfBoundsException e) {System.out.println("你访问了不该的访问的索引"); } catch (Exception e) {System.out.println("出问题了"); } // 爷爷在前面是不可以的 // try { // System.out.println(a / b); // System.out.println(arr[3]); // System.out.println("这里出现了一个异常,你不太清楚是谁,该怎么办呢?"); // } catch (Exception e) {//Error 编译期会报错 // System.out.println("出问题了"); // } catch (ArithmeticException e) { // System.out.println("除数不能为 0"); // } catch (ArrayIndexOutOfBoundsException e) { // System.out.println("你访问了不该的访问的索引"); // } System.out.println("over"); }

JDK7 出现了一个新的异常处理方案:(不推荐使用)

public static void method() {int a = 10; int b = 0; int[] arr = { 1, 2, 3 }; // JDK7 的处理方案 try {System.out.println(a / b); System.out.println(arr[3]); } catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {System.out.println("出问题了"); } System.out.println("over"); }

4、编译时异常和运行时异常的区别

Java 中的异常被分为两大类:编译时异常和运行时异常。所有的 RuntimeException 类及其子类的实例被称为运行时异常,其他的异常就是编译时异常
编译时异常
Java 程序必须显示处理,否则程序就会发生错误,无法通过编译
运行时异常
无需显示处理,也可以和编译时异常一样处理

public static void main(String[] args) {int a = 10; int b = 0; if (b != 0) {System.out.println(a / b);// 运行时异常无需显示处理 } String s = "2014-11-20"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // Date d = sdf.parse(s); 编译期异常必须显示处理 try {Date d = sdf.parse(s); System.out.println(d); } catch (ParseException e) {// e.printStackTrace(); System.out.println("解析日期出问题了"); } }

5、Throwable 中的方法

Throwable 是 java 异常继承体系中的顶层父类,所有的异常对象都是从其继承过来。

当程序遇到异常后,JVM 会帮我们生产一个异常对象,然后剖出,此时我们可以用 catch 语句进行捕获,捕获后的异常对象会传递到 catch 里面的异常参数里;如果没有对异常进行处理,那么异常最终会交给 JVM 进行处理,JVM 会把异常对象的相关信息打印出来。所以我们要学习一下异常对象的几个从 Throwable 继承过来的方法。

getMessage()
获取异常信息,返回字符串。
toString()
获取异常类名和异常信息,返回字符串, 该字符串由以下三部分组成:

(1)此对象的类的 name(全路径名)

(2)”: “(冒号和一个空格)

(3)调用此对象 getLocalizedMessage() 方法的结果 ( 默认返回的是 getMessage() 的内容 )

printStackTrace()
获取异常类名和异常信息,以及异常出现在程序中的位置。返回值 void。
printStackTrace(PrintStream s)
通常用该方法将异常内容保存在日志文件中,以便查阅。

public static void main(String[] args) {String s = "2014-11-20"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try {// 创建了一个 ParseException 对象,然后抛出去,和 catch 里面进行匹配 Date d = sdf.parse(s); System.out.println(d); // e 对象相当于 // ParseException e = new ParseException(); } catch (ParseException e) {//printStackTrace() //e.printStackTrace(); /* 上面的输出结果:java.text.ParseException: Unparseable date: "2014-11-20" at java.text.DateFormat.parse(DateFormat.java:357) at com.tyschool.test.main(ExceptionDemo.java:24) */ // getMessage() // System.out.println(e.getMessage()); // 输出结果:Unparseable date: "2014-11-20" // toString() // System.out.println(e.toString()); // 输出结果: //java.text.ParseException: Unparseable date: "2014-11-20" } System.out.println("over"); }

6、throws 关键字 - 抛出异常方案

该关键字可以将不想处理的异常交给调用者进行处理。

定义功能方法时,需要把出现的问题暴露出来让调用者去处理。那么就通过 throws 在方法上标识。

有些时候,我们是可以对异常进行处理的,但是又有些时候,我们根本就没有权限去处理某个异常。
或者说,我处理不了,我就不处理了。
为了解决出错问题,Java 针对这种情况,就提供了另一种处理方案:抛出。

格式:
throws 异常类名
注意:这个格式必须跟在方法的括号后面。

注意:
尽量不要在 main 方法上抛出异常。
但是我讲课为了方便我就这样做了。

小结:
编译期异常抛出,将来调用者必须处理。
运行期异常抛出,将来调用可以不用处理。

代码演示:

public static void main(String[] args) {System.out.println("今天天气很好"); try {method(); } catch (ParseException e) {e.printStackTrace(); } System.out.println("但是就是不该有雾霾"); method2();} // 运行期异常的抛出 public static void method2() throws ArithmeticException {int a = 10; int b = 0; System.out.println(a / b); } // 编译期异常的抛出 // 在方法声明上抛出,是为了告诉调用者,你注意了,我有问题。 public static void method() throws ParseException {String s = "2014-11-20"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date d = sdf.parse(s); System.out.println(d); }

7、throw 关键字

在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用 throw 把异常对象抛出。

代码演示

public static void main(String[] args) {// method(); try {method2(); } catch (Exception e) {e.printStackTrace(); } } public static void method() {int a = 10; int b = 0; if (b == 0) {throw new ArithmeticException();} else {System.out.println(a / b); } } public static void method2() throws Exception {int a = 10; int b = 0; if (b == 0) {throw new Exception();// 手动创建异常并扔出 } else {System.out.println(a / b); } }

8、throws 和 throw 的区别

throws

  • 用在方法声明后面,跟的是异常类名

  • 可以跟多个异常类名,用逗号隔开

  • 表示抛出异常,由该方法的调用者来处理

  • throws 表示出现异常的一种可能性,并不一定会发生这些异常

throw

  • 用在方法体内,跟的是异常对象名

  • 只能抛出一个异常对象名

  • 表示抛出异常,由方法体内的语句处理

  • throw 则是抛出了异常,执行 throw 则一定抛出了某种异常

9、处理异常的原则

如果该功能内部可以将问题处理, 用 try, 如果处理不了, 交由调用者处理, 这是用 throws

举例:感冒了就自己吃点药,这个时候用 try 的方式对异常进行处理;如果是跌倒骨折了,自己处理不了就去医院。

区别:try 处理了,别人就不需要处理;throws 的话,别人仍然需要处理。

10、finally 关键字

使用格式

格式:try...catch...finally...

finally 的特点

被 finally 控制的语句体一定会执行
特殊情况:在执行到 finally 之前 jvm 退出了 (比如 System.exit(0))

finally 的作用

用于释放资源,在 IO 流操作和数据库操作中会见到

代码演示

public static void main(String[] args) {String s = "2014-11-20"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date d = null; try {// System.out.println(10 / 0); d = sdf.parse(s); } catch (ParseException e) {e.printStackTrace(); System.exit(0); } finally {System.out.println("这里的代码是可以执行的"); } System.out.println(d); }

finally 面试题
(1):final,finally 和 finalize 的区别
final:最终的意思,可以修饰类,成员变量,成员方法
修饰类,类不能被继承
修饰变量,变量是常量
修饰方法,方法不能被重写
finally:是异常处理的一部分,用于释放资源。
一般来说,代码肯定会执行,特殊情况:在执行到 finally 之前 jvm 退出了
finalize:是 Object 类的一个方法,用于垃圾回收

(2): 如果 catch 里面有 return 语句,请问 finally 里面的代码还会执行吗?

如果会,请问是在 return 前,还是 return 后。

答:会,在之前。

参考代码:

public static void main(String[] args) {System.out.println(getInt()); } public static int getInt() {int a = 10; try {System.out.println(a / 0); a = 20; } catch (ArithmeticException e) {a = 30; return a; /* * return a 在程序执行到这一步的时候,这里不是 return a 而是 return 30; 这个返回路径就形成了。* 但是呢,它发现后面还有 finally,所以继续执行 finally 的内容,a=40 * 再次回到以前的返回路径,继续走 return 30; */ } finally {a = 40; return a;// 如果这样结果就是 40 了。 } // return a; }

11、自定义异常

  • java 不可能对所有的情况都考虑到,所以,在实际的开发中,我们可能需要自己定义异常。
  • 而我们自己随意的写一个类,是不能作为异常类来看的,要想你的类是一个异常类,就必须继承自 Exception 或者 RuntimeException

种类

继承自 Exception
继承自 RuntimeException

参考代码:

public class MyException extends Exception {public MyException() { } public MyException(String message) {//message 就是异常的描述性信息 super(message); } } // public class MyException extends RuntimeException { // // }
class Teacher {public void check(int score) throws MyException {if (score > 100 || score < 0) {throw new MyException("分数必须在 0 -100 之间"); } else {System.out.println("分数没有问题"); } } // 针对 MyException 继承自 RuntimeException // public void check(int score) { // if (score > 100 || score < 0) { // throw new MyException(); // } else { // System.out.println("分数没有问题"); // } // } }
/* * 自定义异常测试类 */ public class StudentDemo {public static void main(String[] args) {Scanner sc = new Scanner(System.in); System.out.println("请输入学生成绩:"); int score = sc.nextInt(); Teacher t = new Teacher(); try {t.check(score); } catch (MyException e) {e.printStackTrace(); } } }

12、异常注意事项

(a)子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了, 儿子不能比父亲更坏)
(b) 如果父类抛出了多个异常, 子类重写父类时, 只能抛出相同的异常或者是他的子集, 子类不能抛出父类没有的异常
©如果被重写的方法没有异常抛出, 那么子类的方法绝对不可以抛出异常, 如果子类方法内有异常发生, 那么子类只能 try, 不能 throws

代码演示

public class ExceptionDemo { } class Fu {public void show() throws Exception { } public void method() {}} class Zi extends Fu {@Override public void show() throws ArithmeticException { } @Override public void method() {// String s = "2014-11-20"; // SimpleDateFormat sdf = new SimpleDateFormat(); // Date d = sdf.parse(s); // System.out.println(d); } }

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-06-06发表,共计8775字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中