13、异常
1、什么是异常
概念:
程序在运行过程中出现的不正常现象。出现异常不处理将终止程序运行。
异常处理的必要性:
任何程序都可能存在大量的未知问题、错误;如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。
异常处理:
Java编程语言使用异常处理机制为程序提供了异常处理的能力。
2、异常的分类
Throwable:可抛出的,一切错误或异常的父类,位于java.lang包中。
l- Error: JVM、硬件、执行逻辑错误,不能手动处理。
l- StackOverflowError 栈空间溢出
l- OutOfMemoryError 内存不足
l- Exception:程序在运行和配置中产生的问题,可处理。
l- RuntimeException:运行时异常,可处理,可不处理。
l- CheckedException:检查时异常,必须处理。
3、常见运行时异常

/** * 演示常见运行时异常 * 运行时异常:RuntimeException以及子类 * 检查时异常:Exception以及子类,除了RuntimeException * */ public class Demo1 { public static void main(String[] args) { //常见运行时异常 //1NullPointerException // String name=null; // System.out.println(name.equals("zhangsan")); //2ArrayIndexOutOfBoundsException // int[] arr= {10,30,50}; // System.out.println(arr[3]); //3ClassCastException // Object str="hello"; // Integer i=(Integer)str; //4NumberFormatException // int n=Integer.parseInt("100a"); // System.out.println(n); //5ArithmeticExceptioin // int n=10/0; // System.out.println(n); // 检查时异常 // try { // FileInputStream fis=new FileInputStream("d:\\hell.txt"); // } catch (FileNotFoundException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } } }
4、异常的产生
自动抛出异常:
当程序在运行时遇到不符合规范的代码或结果时,会产生异常。
手动抛出异常:
语法: throw new异常类型(“实际参数”);
产生异常结果:
相当于遇到return语句,导致程序因异常而终止。
5、异常的传递
异常的传递:
按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)。
受查异常:
throws声明异常,修饰在方法参数列表后端。
运行时异常:
因可处理可不处理,无需声明异常。
/** * 演示异常的产生和传递 * 要求:输入两个数字实现两个数字相除 * */ public class Demo2 { public static void main(String[] args) { operation(); } public static void operation() { System.out.println("---opration-----"); divide(); } public static void divide() { Scanner input=new Scanner(System.in); System.out.println("请输入第一个数字"); int num1=input.nextInt();//出现异常,没有处理,程序中断 System.out.println("请输入第二个数字"); int num2=input.nextInt(); int result=num1/num2;//出现异常没有处理,所以程序中断 System.out.println("结果:"+result); System.out.println("程序执行完毕了..."); } }
6、异常处理
Java的异常处理是通过5个关键字来实现的:
try: 执行可能产生异常的代码
catch: 捕获异常,并处理
finally: 无论是否发生异常,代码总能执行
throw: 手动抛出异常
throws: 声明方法可能要抛出的各种异常
6.1、try...catch
会三种情况:
1:正常请求
2:出现异常并处理
3:异常类型不匹配
try { // 可能出现异常的代码 }catch (Exception e){ // 异常处理的相关代码,如:getMessage(). printStackTrace() }
/** * 演示try...catch...语句的使用 * try{...可能发生异常的代码} * catch{...捕获异常,并处理异常} * 三种情况: * (1)正常没有发生异常 * (2)发生异常并捕获 * (3)发生异常,不能捕获 * */ public class Demo3 { public static void main(String[] args) { Scanner input=new Scanner(System.in); int result=0; try { System.out.println("请输入第一个数字"); int num1=input.nextInt();//InputMismatchException System.out.println("请输入第二个数字"); int num2=input.nextInt(); result=num1/num2;//发生异常// ArethmicException }catch (Exception e) {//捕获 Exception:是所有异常的父类 //处理 //e.printStackTrace(); System.out.println(e.getMessage()); } System.out.println("结果是:"+result); System.out.println("程序结束了..."); } }
6.2、try...catch...finally
(1)finally块是否发生异常都执行,可以释放资源
(2)finally块不执行的唯一情况,退出java虚拟机
try{ // 可能出现异常的代码 }catch (Exception e){ // 异常处理的相关代码,如:getMessage(). printStackTrace() }finally { // 是否发生异常都会执行,可以释放资源等 }
/** * 演示try...catch...finally...使用 * finally最后的 * 表示有没有发生异常都会执行的代码 * */ public class Demo4 { public static void main(String[] args) { Scanner input=new Scanner(System.in); int result=0; try { System.out.println("请输入第一个数字"); int num1=input.nextInt();//InputMismatchException System.out.println("请输入第二个数字"); int num2=input.nextInt(); result=num1/num2;//发生异常// ArethmicException //手动退出JVM //System.exit(0); }catch (Exception e) {//捕获 Exception:是所有异常的父类 //处理 //e.printStackTrace(); System.out.println(e.getMessage()); }finally { System.out.println("释放资源..."); } System.out.println("结果是:"+result); System.out.println("程序结束了..."); } }
6.3、多重catch
(1)子类异常在前,父类异常在后
(2)发生异常时按顺序逐个匹配
(3)只执行第一个与异常类型匹配的catch语句
(4) finally根据需要可写或不写
try { // 可能出现异常的代码 }catch (异常类型1){ // 满足异常类型1执行的相关代码 }catch (异常类型2){ // 满足异常类型2执行的相关代码 }catch (异常类型3){ // 满足异常类型3执行的相关代码 }
/** * 演示多重catch的使用 * try...catch(类型1)...catch(类型2)... * */ public class Demo5 { public static void main(String[] args) { Scanner input=new Scanner(System.in); int result=0; try { // String string=null; // System.out.println(string.equals("hello")); System.out.println("请输入第一个数字"); int num1=input.nextInt();//InputMismatchException System.out.println("请输入第二个数字"); int num2=input.nextInt(); result=num1/num2;//发生异常// ArethmicException }catch (ArithmeticException e) {//捕获 Exception:是所有异常的父类 System.out.println("算术异常"); }catch (InputMismatchException e) { System.out.println("输入不匹配异常"); }catch (Exception e) { System.out.println("未知异常"); } System.out.println("结果是:"+result); System.out.println("程序结束了..."); } }
6.4、try...finally
try...finally不能捕获异常,仅仅用来当发生异常时,用来释放资源。
一般用在底层代码,只释放资源不做异常处理,把异常向上抛出。
try { // 可能出现异常的代码 }finally { // 是否发生异常都会执行,可以释放资源等... }
/** * try...finally的使用 * 不能处理异常,可以释放资源,把异常向上抛出 * */ public class Demo6 { public static void main(String[] args) {//JVM try { divide(); }catch (Exception e) { System.out.println("出现异常:"+e.getMessage()); } } public static void divide() { Scanner input=new Scanner(System.in); int result=0; try { System.out.println("请输入第一个数字"); int num1=input.nextInt();//InputMismatchException System.out.println("请输入第二个数字"); int num2=input.nextInt(); result=num1/num2;//发生异常// ArethmicException }finally { System.out.println("释放资源"); } System.out.println("结果是:"+result); System.out.println("程序结束了..."); } }
7、声明异常
如果在一个方法体中抛出了异常,如何通知调用者?
throws关键字:声明异常
使用原则:
底层代码向上声明或者抛出异常,最上层一定要处理异常,否则程序中断。
/** * throws:声明异常 * */ public class Demo7 { public static void main(String[] args){//JVM try { divide(); } catch (Exception e) { //e.printStackTrace(); System.out.println(e.getMessage()); } } public static void divide() throws Exception { Scanner input=new Scanner(System.in); System.out.println("请输入第一个数字"); int num1=input.nextInt(); System.out.println("请输入第二个数字"); int num2=input.nextInt(); int result=num1/num2; System.out.println("结果:"+result); } }
8、抛出异常
除了系统自动抛出异常外,有些问题需要程序员自行抛出异常。
throw关键字: 抛出异常
语法: throw 异常对象;
public class Person { private String name; private String sex; private int age; public Person() { } public Person(String name, String sex, int age) { super(); this.name = name; this.sex = sex; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) throws Exception { if(sex.equals("男")||sex.equals("女")) { this.sex = sex; }else { throw new Exception("性别不符合要求"); } } public int getAge() { return age; } public void setAge(int age) throws Exception { if(age>0&&age<=120) { this.age = age; }else { //抛出异常 throw new Exception("年龄不符合要求"); } } @Override public String toString() { return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]"; } }
public class TestPerson { public static void main(String[] args) throws Exception{ Person xiaozhang=new Person(); xiaozhang.setAge(20); xiaozhang.setSex("妖"); System.out.println(xiaozhang.toString()); } }
9、自定义异常
需继承自Exception或Exception的子类,常用RuntimeException.
必要提供的构造方法:
无参数构造方法
String message参数的构造方法
/** * 自定义异常 * (1)继承Exception 或子类 * (2)添加构造方法 * */ public class AgeException extends RuntimeException{ public AgeException() { super(); } public AgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } public AgeException(String message, Throwable cause) { super(message, cause); } public AgeException(String message) { super(message); } public AgeException(Throwable cause) { super(cause); } }
10、方法覆盖(重写)
带有异常声明的方法覆盖:
方法名、参数列表、返回值类型必须和父类相同。
子类的访问修饰符合父类相同或是比父类更宽。
子类中的方法,不能抛出比父类更多、更宽的检查时异常。
public class Animal { public void eat() throws Exception{ System.out.println("父类吃方法.........."); } }
public class Dog extends Animal{ @Override public void eat() throws Exception{ System.out.println("子类的吃的方法.........."); } }
11、总结
异常的概念:
程序在运行过程中出现的特殊情况。
异常的分类:
RuntimeException: 运行时异常,可处理,可不处理。
CheckedException: 检查时异常,必须处理。
异常的产生:
程序遇到错误,或手动抛出异常
异常的传递:
按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)
异常的处理:
try { } catch { } finally { }
带有异常声明的方法覆盖:
子类中的方法,不能抛出比父类更多、更宽的异常。

浙公网安备 33010602011771号