【1】Java异常
一、异常分类
- 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
- 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
- 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
Throwable(异常根类) | Error(错误) | VirtualMachineError 虚拟机错误 | |
OutOfMemoryError内存溢出 | |||
ThreadDeath线程死锁 | |||
Exception(异常) |
RuntimeException(运行时异常) |
NullPointerException(空指针异常) | |
ClassCastException(类型转换异常) | |||
ArraylndexOutOfBoundException (下标越界异常) |
|||
ArithmeticException(算数异常) | |||
Checked Exceptions(检查异常) |
IOException(IO异常) | ||
SQLException(SQL异常) |
二、异常处理
1、捕获异常:try-catch-finally
代码形式:
try{ //代码段1 //产生异常的代码段2 }catch(异常类型 ex){ //对异常进行处理的代码段3 }finally{ //代码段四 }
补充
catch语句块中有System.exit(非零整数);则表示当前程序无条件终止运行,后面的语句不再执行
实例:
import java.util.InputMismatchException; import java.util.Scanner; public class TryDemoOne { /** * 多重catch语句,与执行顺序有关,当捕获到了一个异常时,剩下的catch语句就不再进行匹配。 * @param args */ public static void main(String[] args) { // 要求:定义两个整数,接受用户的键盘输入,输出两数之商 Scanner input=new Scanner(System.in); try{ System.out.print("请输入第一个整数:"); int one=input.nextInt(); System.out.print("请输入第二个整数:"); int two=input.nextInt(); System.out.println("one和two的商是:"+ (one/two)); }catch(ArithmeticException e){ System.exit(1);//终止程序运行 System.out.println("除数不允许为零"); e.printStackTrace();//打印错误的描述、类型、位置 }catch(InputMismatchException e){ System.out.println("请输入整数"); e.printStackTrace(); }catch(Exception e){ System.out.println("出错啦~~"); e.printStackTrace(); }finally{//无论是否有异常,都会执行finally的语句块 System.out.println("=====运算结束====="); } } }
2、声明异常类型:throws
1.)throws语句用在方法定义时什么该方法要抛出的异常类型。
2.)当方法抛出异常列表中的异常时,方法将不对这些类型及其子类型的异常做处理,谁调用这个方法则谁处理抛出的异常。
public void method()throws Exception1,Exception2,....,ExceptionN{ //可能产生异常的代码 }
实例:
import java.util.InputMismatchException; import java.util.Scanner; public class test { public static void main(String[] args) { try{ int result = test(); System.out.println("one和two的商是:" + result); }catch(ArithmeticException e){ }catch(InputMismatchException e){ }catch(Exception e){ } int result2=test(); } /*通过throws抛出异常时,针对可能出现的多种异常情况,解决方案: * 1、throws后面接多个异常类型,中间用逗号分隔 * 2、throws后面接Exception * */ /** * 测试接收数据相除结果的方法 * @return 两个接收数据的商 * @throws ArithmeticException * @throws InputMismatchException */ public static int test() throws ArithmeticException,InputMismatchException{ Scanner input = new Scanner(System.in); System.out.println("=====运算开始====="); System.out.print("请输入第一个整数:"); int one = input.nextInt(); System.out.print("请输入第二个整数:"); int two = input.nextInt(); System.out.println("=====运算结束====="); return one / two; } }
3、抛出异常对象:throw
1. throw用来抛出一个异常对象,例如:throw new IOException();
2. throw抛出的只能是Throwable或者是其子类的实例对象。
3. throw抛出异常对象的处理方案(具体格式如截图所示):
1)自己抛出自己处理,通过try-catch包含throw语句。
2)用throws往上抛,调用者可以try-catch处理或者继续往上抛。throws抛出异常类型时,要抛出与throw对象相同的类型或者其父类。
(例如:throw new Exception(); 那么可以throws Throwable)
4. 如果throw抛出的异常对象为InputMismatchException这样的非检查型异常,编译器不会强制要求必须进行异常处理。
5. 在程序中使用throw主动抛出异常对象的目的
1)规避可能出现的风险
2)完成程序逻辑
实例:
import java.util.Scanner; public class TryDemoFour { public static void main(String[] args) { // TODO Auto-generated method stub try { testAge(); } catch (HotelAgeException e) { System.out.println(e.getMessage()); System.out.println("酒店前台工作人员不允许办理入住登记"); }catch(Exception e){ e.printStackTrace(); } } /* * throw抛出异常对象的处理方案: * 1、通过try..catch包含throw语句--自己抛自己处理 * 2、通过throws在方法声明出抛出异常类型--谁调用谁处理--调用者可以自己处理,也可以继续上抛 * 此时可以抛出与throw对象相同的类型或者其父类 */ //方法1:自己处理异常 // 描述酒店的入住规则:限定年龄,18岁以下,80岁以上的住客必须由亲友陪同 /*public static void testAge() { try { System.out.println("请输入年龄:"); Scanner input = new Scanner(System.in); int age = input.nextInt(); if (age < 18 || age > 80) { throw new Exception("18岁以下,80岁以上的住客必须由亲友陪同"); } else { System.out.println("欢迎入住本酒店"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }*/ //方法2:方法调用处去处理异常 public static void testAge() throws HotelAgeException { System.out.println("请输入年龄:"); Scanner input = new Scanner(System.in); int age = input.nextInt(); if (age < 18 || age > 80) { //throw new ArithmeticException(); //throw new Exception("18岁以下,80岁以上的住客必须由亲友陪同"); throw new HotelAgeException(); } else { System.out.println("欢迎入住本酒店"); } } }
三、自定义异常
1. 使用Java内置的异常类可以描述在编程时出现的大部分异常情况。
2. 也可以通过自定义异常描述特定业务产生的异常类型。所谓自定义异常,就是定义一个类,去继承Throwable类或者它的子类。
public class HotelAgeException extends Exception { public HotelAgeException(){ super("18岁以下,80岁以上的住客必须由亲友陪同"); } } class SubException extends HotelAgeException{ }
public class test { public static void main(String[] args) { // TODO Auto-generated method stub try { testAge(); } catch (HotelAgeException e) { System.out.println(e.getMessage()); System.out.println("酒店前台工作人员不允许办理入住登记"); }catch(Exception e){ e.printStackTrace(); } } public static void testAge() throws HotelAgeException { System.out.println("请输入年龄:"); Scanner input = new Scanner(System.in); int age = input.nextInt(); if (age < 18 || age > 80) { //throw new ArithmeticException(); //throw new Exception("18岁以下,80岁以上的住客必须由亲友陪同"); throw new HotelAgeException(); } else { System.out.println("欢迎入住本酒店"); } } }
四、异常链
1、异常链:有时候我们会捕获一个异常后再抛出另一个异常,将异常发生的原因一个传一个串起来,即把底层的异常信息传给上层,逐层抛出,这就是异常链。
2、抛出最上层异常时仍旧保留底层异常信息的方法:
1)可以调用Throwable(String message,Throwable cause)的构造方法来保留底层异常的异常信息
2)或者采取"Throwable对象.initCause(Throwable cause) "的方法用来获取原始异常的描述信息,其中cause是原始异常的对象
public class TryDemoFive { public static void main(String[] args) { // TODO Auto-generated method stub try { testThree(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void testOne() throws HotelAgeException { throw new HotelAgeException(); } public static void testTwo() throws Exception { try { testOne(); } catch (HotelAgeException e) { throw new Exception("我是新产生的异常1",e); } } public static void testThree() throws Exception { try { testTwo(); } catch (Exception e) { Exception e1=new Exception("我是新产生的异常2"); e1.initCause(e); throw e1; // throw new Exception("我是新产生的异常2",e); } } }