▪ 在Java语言中,将程序执行中发生的不正常情况称为“异常”,Java在编译或运行或者运行过程中出现的错误 (例如要求用户输入数字,但是用户输入了一串字符串,此时就会发生异常)
异常的根接口Throwable,其下有2个子接口,Error和Exception。
▪ Error:指的是JVM错误,这时的程序并没有执行,无法处理;
▪ Exception:指的是程序运行中产生的异常,用户可以使用处理格式处理。
运行时异常
▪ 是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。
▪ 对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
编译时异常
▪ 是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。
▪ 对于这类异常,如果程序不处理,可能会带来意想不到的结果。
方式一:
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"); } }
手动抛出异常使用的关键字是 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; } }
一般情况下,用户自定义异常类都是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); } }
大家不要误以为红色字体就是自己的代码有错误,要仔细分析里面的错误信息,例如这里就自定义了错误信息。
我们之前说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需要放入一些比较重要的代码,避免因为错误而延误这些代码的运行。