① Java异常机制相关关键字
Java异常机制相关关键字有: try
、catch
、finally
、throw
、throws
.
关键字解释:
- try 用于监听. 将被监听的代码(可能抛出异常的代码)放在try语句块之内, 当try语句块内发生异常时,异常就被抛出.
- catch 用来捕获try语句块中发生的异常.
- finally finally语句块总是会被执行. 主要用于回收在
try
块里打开的物理资源(如文件, 网络连接, 数据库连接等).
finally语句中return
只有finally块执行完成之后,才会执行try或者catch块中的return或者throw语句. 如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止.
- throw 用于抛出异常.
- throws 用在方法签名中,用于声明该方法可能抛出的异常.
② Java异常框架
Java将可抛出(Throwable)的结构分为三种类型:
- 编译异常(Checked Exception)
- 运行时异常(RuntimeException)
- 错误(Error)
Java异常框架继承关系如图:
1.Throwable
Throwable
是Java
语言中所有错误或异常的超类, 包含两个子类:Error
和Exception
.它们通常用于指示发生了异常情况.Throwable
包含了其线程创建时线程执行堆栈的快照,提供了printStackTrace()
等接口用于获取堆栈跟踪数据等信息.
2.运行时异常RuntimeException
RuntimeException
是那些可能在Java
虚拟机正常运行期间抛出的异常的超类, 简称运行时异常
. RuntimeException及其子类都被称为运行时异常.
Java编译器不会检查运行时异常.当程序中可能出现这类异常时,倘若既”没有通过throws声明抛出它”,也”没有用try-catch语句捕获它”,还是会编译通过.
虽然Java编译器不会检查运行时异常, 但是我们也可以通过throws进行声明抛出, 也可以通过try-catch对它进行捕获处理. 如果产生运行时异常,则需要通过修改代码来进行避免.
例如:
* 除数为零时产生的ArithmeticException异常
* 数组越界时产生的IndexOutOfBoundsException异常
* fail-fail机制产生的ConcurrentModificationException异常等,都属于运行时异常.
异常 | 描述 |
ArithmeticException | 除数为零异常 |
ArrayIndexOutOfBoundsException | 数组越界 |
ClassCastException | 对象转型错误 |
IllegalArgumentException | 参数不合法 |
IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围 |
NegativeArraySizeException | 数组长度为负值 |
NullPointerException | 空指针异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常. |
3.编译异常Exception
Exception
类以及Exception
的子类中除了”运行时异常”之外的其它子类都属于被检查异常. 此类异常,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译.
异常 | 描述 |
ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常. |
FileNotFoundException | 文件不存在异常 |
ClassCastException | 对象转型错误 |
InterruptedException | 一个线程被另一个线程中断,抛出该异常. |
NoSuchFieldException | 请求的变量不存在 |
NoSuchMethodException | 请求的方法不存在 |
4.Error
Error
类及其子类统称错误
. 用于指示试图捕获的严重问题, 大多数这样的错误都是异常条件. 和运行时异常
一样, 编译器也不会检查Error
. 当资源不足、约束失败、或是其它导致程序无法继续运行的条件发生时, 就产生错误. 程序本身无法修复这些错误.
例:
- VirtualMachineError就属于错误.
按照Java惯例, 不应该实现任何新的Error子类, 需要自定义异常可以采用Exception类.
到底该哪一种异常?
对于可以恢复的条件使用被检查异常,对于程序错误使用运行时异常.虚拟机及系统错误采用Error.
③ 捕获异常
使用try
和catch
关键字可以捕获异常.try/catch
代码块放在异常可能发生的地方.
语法如下:
try {
/** 程序代码*/
} catch (Exception e) {
/** 异常处理*/
}
- 1
- 2
- 3
- 4
- 5
try {
/** 程序代码*/
} catch (Exception1 e) {
/** 异常处理*/
} catch (Exception1 e) {
/** 异常处理*/
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
④ 抛出异常
可以使用throw
关键字抛出一个异常.
public static void testThrow() {
/** 方法体*/
throw new NullPointerException();
}
- 1
- 2
- 3
- 4
public static void testThrows() throws NullPointerException {
/** 方法体*/
}
- 1
- 2
- 3
public static void testThrows() throws NullPointerException, ArithmeticException {
/** 方法体*/
}
- 1
- 2
- 3
⑤ finally关键字
finally
关键字用来创建在try
代码块后面执行的代码块. 无论是否发生异常,finally
代码块中的代码总会被执行. 在finally
代码块中,可以运关闭链接, 释放系统资源等必须要执行的语句.
finally
代码块出现在catch
代码块最后.
语法如下:
try {
/** 方法体*/
} catch (Exception e) {
/** 异常处理*/
} finally {
/** finally语句*/
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
finally块并非强制添加,但是try代码块后面不能既没有catch块也没有finally块
代码示例
package exception;
public class ArithmeticDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 66;
int b = 0;
try {
System.out.println(a / b);
} catch (ArithmeticException e) {
// TODO: handle exception
//用输出语句来处理异常
System.out.println("除数不能为0");
e.printStackTrace();
} finally {
// TODO: handle finally clause
System.out.println("run finally");
}
System.out.println("over");
}
}
如何处理多个异常 两个或两个以上的异常怎么处理?
try{可能出现问题的代码
int[] arr = {1,2,3} ;
Sop(arr[3]);
int a = 10 ;
int b =0 ;
Sop(a/b) ;
}catch(异常类名1 对象名1){
//异常处理
}catch(异常类名2 对象名2(){
//异常处理
}
代码示例
package exception;
public class ExceptionDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
method();
}
private static void method() {
int a = 11;
int b = 0;
int[] array = { 1, 2, 3 };
try {
System.out.println(array[3]);
System.out.println(a / b);
System.out.println("代码到这一步可能出现问题,怎么办?");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("访问了数组中不存在的角标");
e.printStackTrace();
} catch (ArithmeticException e) {
// TODO: handle exception
System.out.println("除数不能为0");
e.printStackTrace();
} catch (Exception e) {
// TODO: handle exception
System.out.println("程序出问题了");
} finally {
System.out.println("run finally");
}
}
}
Jdk7以后出现了另外一种方式来处理多个异常 try{
可能出现问题的代码;
}catch(异常类名1 | 异常类名2 |... 对象名){
处理异常
}
package exception;
public class ExceptionDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
method();
}
private static void method() {
int a = 11;
int b = 0;
int[] array = { 1, 2, 3 };
try {
// sSystem.out.println(array[3]);
System.out.println(a / b);
System.out.println("代码到这一步可能出现问题,怎么办?");
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
// TODO: handle exception
System.out.println("程序出现异常了");
e.printStackTrace();
}
}
}
编译时期异常和运行时期异常的区别?编译时期异常:开发者必须进行显示处理,如果不处理,编译不能通过,
运行时期异常:不需要进行显示处理,但是也可以像编译时期异常一样进行处理
处理异常的第二种方式:使用throws 抛出异常 (跟在方法的后面)
xxx 返回值 方法名() throws 异常类名{
}
代码示例
package exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo2 {
public static void main(String[] args) throws ParseException {
// TODO Auto-generated method stub
System.out.println("今天天气很好!");
method2();
method1();
System.out.println("但是不该有雾霾....");
}
private static void method1() {
int a = 10;
int b = 0;
try {
System.out.println(a / b);
} catch (ArithmeticException e) {
// TODO: handle exception
System.out.println("除数不能为0");
e.printStackTrace();
}
}
private static void method2() throws ParseException {
String string = "2018-5-17";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = simpleDateFormat.parse(string);
System.out.println("date" + date);
}
}
标准格式 try{ ... }catch(异常类 对象){ // 异常处理 }
执行try里面的代码,如果出现了问题,它会创建一个异常类的对象,然后判断异常类对象的类型和catch里面的异常类
是否一致
如果一致的情况,就会执行catch里面的代码,执行Throwable里面的方法
public String getMessage() :消息字符串 例如: Unparseable date: "2018-6-20"
public String toString(): 异常的简短描述 ": 例如: java.text.ParseException: Unparseable date: "2018-6-20"
public void printStackTrace():返回值void 直接调用
包含了toString(),出现的异常在源码中的行数以及在本程序中的行数
例如: java.text.ParseException: Unparseable date: "2018-6-20"
at java.text.DateFormat.parse(DateFormat.java:366)
at exception.Exception.main(Exception.java:13)
面试题:
final,finally,finalize的区别?
final: 可以修饰类,该类不能被继承;可以修饰变量,该变量是常量;可以修饰成员方法,该方法重写finalize: gc():运行垃圾回收器,实际是调用finalize()方法,和垃圾回收器有关系
finally:在io,数据库中以及后面对数据库操作(DBUtuls/c3p0/Hibernate/MyBatis)里面中释放资源的
代码示例
package exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Exception {
public static void main(String[] args) {
try {
String string = "2018-6-20";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = simpleDateFormat.parse(string);
System.out.println(date);
} catch (ParseException e) {
// TODO: handle exception
String string = e.getMessage();
System.out.println(string);
String string2 = e.toString();
System.out.println(string2);
e.printStackTrace();
}
System.out.println("日期解析完毕!!!");
System.out.println("------------------------------");
try {
String string = "2018-6-6";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = simpleDateFormat.parse(string);
System.out.println(date);
System.exit(0);// 终止当前正在运行的Java虚拟机,如果没有出现解析异常,则直接执行exit(0),不再执行finally块中的代码
} catch (ParseException e) {
// TODO: handle exception
e.printStackTrace();
} finally {
System.out.println("这里释放资源......");
}
}
}
throw:表示也是抛出异常,抛出的一个异常对象 (throw new 异常类名() :匿名对象的方式)面试题:
throws和throw的区别?
throws:也是表示抛出异常,它后面跟的异常类名,并且可以多个异常类名中间逗号开
举例:
public void show() throws IoException,ClassNotFoundException{...}
在方法上抛出,由调用者处理
它抛出可能出现的异常
throw:抛出的一个异常对象
在语句体中抛出的,由语句体进行处理
它抛出肯定出现的异常
代码示例
package Exception;
public class Exception1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
method();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
private static void method2() throws Exception {
int a = 10;
int b = 0;
if (b == 0) {
throw new Exception();
} else {
System.out.println(a / b);
}
}
private static void method() {
int a = 10;
int b = 0;
if (b == 0) {
throw new ArithmeticException();
} else {
System.out.println(a / b);
}
}
}
try...catch...finallyfinally语句体是一定会执行的,除非终止JVM的运行 System.exit(0);
面试题:
如果catch里面有return语句,finally中的代码还会执行,是在return语句之前执行还是return后执行?
finally中代码是一定会执行的,在return前执行,如果先执行return则方法终止运行,finally块就不会运行,与规则冲突,所以return是一个方法体最后执行的部分,它的后面不会再执行任何操作
try的代码出现问题了,执行catch中的语句,30赋值a,
* return 30(已经形成了一个回路径)finally代码一定会执行(除非Jvm) a = 40 ,在fianlly外面
* 有return a: a记录的是回路径的那个a(30),所以返回30
package Exception;
public class Exception2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(getInt());
}
private static int getInt() {
int a;
try {
a = 10;
System.out.println(a / 0);
a = 20;
} catch (Exception e) {
// TODO: handle exception
a = 30;
return a;// 形成回路径
} finally {
a = 40;
System.out.println("执行了finally a:" + a);
}
return a;// 返回回路径a(30)
}
}
如何自定义一个异常类?
代码示例
package Exception;
public class Teacher {
public static void check(int score) throws MyException {
if (score < 0 || score > 100) {
throw new MyException("该学生成绩有问题...");
} else {
System.out.println("该学生成绩没有问题...");
}
}
}
package Exception;
public class MyException extends Exception {
public MyException() {
super();
// TODO Auto-generated constructor stub
}
public MyException(String message) {
super(message);
}
}
package Exception;
import java.util.Scanner;
public class Demo {
private static Scanner in;
public static void main(String[] args) throws MyException {
in = new Scanner(System.in);
System.out.println("请输入学生成绩:");
int score = in.nextInt();
Teacher teacher = new Teacher();
Teacher.check(score);
}
}
异常中的注意事项:子类继承父类的时候的注意事项
1)子类重写父类的方法的时候,子类方法抛出的异常要么和父类方法抛出的异常一样,要么是父类方法抛出的异常的子类
2)子类重写父类方法的时候,如果父类中的这个方法没有抛出异常,那么子类重写的这个方法也不能抛出异常,只能try...catch
代码示例
package Exception;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo1 {
public static void main(String[] args) {
Zi aZi = new Zi();
aZi.method();
}
}
class Fu {
public void show() throws Exception {
}
public void method() {
}
}
class Zi extends Fu {
@Override
public void show() throws ArithmeticException {
}
@Override
public void method() {
try {
String str = "2018-5-13";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(str);
System.out.println(d);
} catch (Exception e) {
e.printStackTrace();
}
}
}