异常
1 异常的分类
▪ 在Java语言中,将程序执行中发生的不正常情况称为“异常”,Java在编译或运行或者运行过程中出现的错误 (例如要求用户输入数字,但是用户输入了一串字符串,此时就会发生异常)
异常的根接口Throwable,其下有2个子接口,Error和Exception。
▪ Error:指的是JVM错误,这时的程序并没有执行,无法处理;
▪ Exception:指的是程序运行中产生的异常,用户可以使用处理格式处理。
运行时异常
▪ 是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。
▪ 对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
编译时异常
▪ 是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。
▪ 对于这类异常,如果程序不处理,可能会带来意想不到的结果。
2 异常的处理
方式一:
try…catch、 try…catch…finally、 try…finally
try{
...... //可能产生异常的代码
}
catch( ExceptionName1 e ){
...... //当产生ExceptionName1型异常时的处置措施
}
catch( ExceptionName2 e ){
...... //当产生ExceptionName2型异常时的处置措施
}[ finally{
...... //无论是否发生异常,都无条件执行的语句
} ]
▪ catch 不能独立于 try 存在
▪ 在 try/catch 后面添加 finally 块并非强制性要求的
▪ catch里面不能没有内容
▪ 如果程序可能存在多个异常,需要多个catch进行捕获,其没有先后顺序
▪ 当捕获到异常时执行相应catch,没有捕获到异常时执行finally
方式二:
throws
▪ 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
▪ 在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
▪ 重写方法不能抛出比被重写方法范围更大的异常类型。
public class ReturnFinally {
public static void main(String[] args) {
// int i = test01();
// System.out.println(i);
int i = test02();
System.out.println(i);
}
private static int test02() {
int num = 10;
try {
System.out.println(num);
return num;
} catch (Exception e) {
num += 10;
System.out.println("发生异常");
} finally {
num++;
System.out.println("必须要执行的代码");
}
return num;
}
public static int test01() {
int num = 10;
try {
System.out.println(num);
// 在函数中,如果在finally之前,使用return关键字,则在return完成前,执行finally,再return
return num + 1;
} catch (Exception e) {
System.out.println("发生异常");
} finally {
System.out.println("必须要执行的代码");
}
return num + 2;
}
}
public class Error {
public static void main(String[] args) throws RuntimeException{
try {
MyException(5,-1);
} catch (Exception e) {
System.out.println(e.getMessage());
}finally {//必须执行
System.out.println("必须执行");
}
System.out.println("55");
}
public static void MyException(int i,int j) {//throws RuntimeException{
int t;
t = i/j;
System.out.println("11");
if(i<0||j<0) {
System.out.println("222");
throw new RuntimeException ("数字必须为正数");//message
}
System.out.println("33");
System.out.println(t);
System.out.println("44");
}
}
3 手动抛出异常
手动抛出异常使用的关键字是 throw
▪ 首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给Java运
行环境)。
▪ 可以抛出的异常必须是Throwable或其子类的实例。
public static void getDrink(int drinkType) throws DrinkNotFoundException { //声明异常
if ( drinkType<1||drinkType>3){
throw new DrinkNotFoundException("请输入正确的编号");
}
switch (drinkType) {
case 1:
System.out.println("咖啡");
break;
case 2:
System.out.println("啤酒");
break;
case 3:
System.out.println("牛奶");
break;
default:
break;
}
}
4 用户自定义异常类
一般情况下,用户自定义异常类都是RuntimeException的子类。
用户自己的异常类必须继承现有的异常类。这里继承的是 Exception。
public class DrinkNotFoundException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
public DrinkNotFoundException() {
super();
// TODO Auto-generated constructor stub
}
public DrinkNotFoundException(String string) {
super(string);
// TODO Auto-generated constructor stub
}
}
这个异常类就是上面手动抛出异常的自定义异常类
下面是测试类
private static Scanner sc;
public static void main(String[] args) {
Coffee c = new Coffee();
Milk m = new Milk();
Beer b = new Beer();
sc = new Scanner(System.in);
System.out.println("请输入你要购买的饮料的编号:");
try {
int i = sc.nextInt();
Drink.getDrink(i);
if(i==1){
c.taste();
}else if(i==2){
b.taste();
}else if(i==3){
m.taste();
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
当用户输入的编号不是1-3的话就会产生异常,手动抛出到自定义异常类,输出自己编辑的message。
public class yic {
public static void main(String[] args) throws Class12.MyException {
MyException(5,0);
}
public static void MyException(int i,int j) throws Class12.MyException {
try {
int t;
t = i/j;
System.out.println(t);
} catch (ArithmeticException e) {
// TODO Auto-generated catch block
throw new MyException("不能为0");
}
}
}
public class MyException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
public MyException(String string) {
// TODO Auto-generated constructor stub
super(string);
}
}
大家不要误以为红色字体就是自己的代码有错误,要仔细分析里面的错误信息,例如这里就自定义了错误信息。
5 当return遇上finally
我们之前说finally里的语句是必须执行的,语句执行到return是直接结束掉函数。
public class ReturnFinally {
public static void main(String[] args) {
int i = test01();
System.out.println(i);
}
public static int test01() {
int num = 10;
try {
System.out.println(num);
// 在函数中,如果在finally之前,使用return关键字,则在return完成前,执行finally,再return
return num + 1;
} catch (Exception e) {
System.out.println("发生异常");
} finally {
System.out.println("必须要执行的代码");
}
return num + 2;
}
}
此时执行的是 num+1,并没有执行num+2,
在函数中,如果在finally之前,使用return关键字,则在return完成前,执行finally,再return。可以认为此时return已经拿到了自己所要的数据,只是给finally做出了让步,让其先执行。
public static int test01() {
int num = 10;
try {
System.out.println(num);
// 在函数中,如果在finally之前,使用return关键字,则在return完成前,执行finally,再return
return num + 1;
} catch (Exception e) {
System.out.println("发生异常");
} finally {
System.out.println("必须要执行的代码");
return num + 2;
}
}
如果将return放入finally中执行的结果是
一般不建议在finally中放入这种代码,finally需要放入一些比较重要的代码,避免因为错误而延误这些代码的运行。