Java异常
- 什么是异常
- 如何处理异常
- try-catch-finally
- throw
- throws
- 自定义异常
- 异常链
什么是异常
- 错误在外面编写程序的过程中经常发生,包括编译期间和运行期间的错误。
编译期间的错误:
- 括号没有正常的配对
- 语句结束后少写了分号;
- 关键字编写错误
运行期间的错误:
使用空的对象引用调用方法
String str = null;
System.out.println(str.length());
数组访问时下标越界
int[] ary={
1,2,3};
for(int i=0;i<=3;i++){
System.out.println(ary[i]);
}
算数运算时除数为0
int one=12;
int two=0;
System.out.println(one/two);
类型转换时无法正常转型
class Animal {
}
class Dog extends Animal {
}
class Cat extends Animal {
}
public class Test {
public static void main(String[] args){
Animal a1 = new Dog();
Animal a2 = new Cat();
Dog d1 = (Dog)a1;
Dog d2 = (Dog)a2;
}
}
在程序运行过程中,意外发生的情况,背离我们程序本身的意图的表现,都可以理解为异常。
异常分类
Throwable异常分为两种Error、Exception
Error
- 虚拟机错误 VirtualMachineError
- 内存溢出 OutOfMemoryError
- 线程死锁 ThreadDeath
它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的情况
Exception
Exception是程序本身可以处理的异常。异常处理通常指针对这种类型异常的处理。
- RuntimeException
- 检查异常 Checked Exception
- IO异常 IOException
- SQL异常 SQLException
RuntimeException
- 空指针异常 NullPointerException
- 数组下标越界异常 ArrayIndexOutOfBoundsException
- 算数异常 ArithmeticException
- 类型转换异常 ClassCastException
异常处理分类
- 在Java应用程序中,异常处理机制为:抛出异常、捕获异常
异常对象
- 异常类型
- 异常出现的时候的程序状态
- …
捕获异常
- 对于运行时异常、错误或可查异常,Java技术所要求的异常处理方式有所不同。
Java规定: - 对于可査异常必须捕捉、或者声明抛出
- 允许忽略不可査的RuntimeException(含子类)和Error(含子类)。
异常处理
捕获异常
- 通过5个关键字来实现:try、catch、finall、throw、throws
- try 执行可能产生异常的代码
- catch 捕获异常
- finally 无论是否发生异常代码总能执行
声明异常
- throws 声明可能要抛出的异常
抛出异常
- 手动抛出异常
try-catch-finall
public void method(){
try {
//代码段1
//产生异常的代码段2
}catch(异常类型 ex) {
// 对异常进行处理的代码段3
}finally{
// 代码段4
}
}
try块后可接零个或多个catch块,如果没有catch块,则必须跟一个finall块。
public class TryDemoOne {
public static void main(String[] args) {
// 要求:定义两个整数,输出两数之商
int one = 12;
int two = 2;
System.out.println("one和two的商是:" + (one/two));
//要求:定义两个整数,接受用户的键盘输入,输出两数之商
Scanner input = new Scanner(System.in);
System.out.println("====运算开始====");
System.out.println("请输入第一个整数:");
try{
int one = input.nextInt();
System.out.println("请输入第二个整数:");
int two = input.nextInt();
System.out.println("one和two的商是:" + (one/two));
}catch(Exception e) {
e.printStackTrace();//打印错误的堆栈信息
System.out.println("程序出错啦~~");
}finally{
System.out.println("====运算结束====");
}
}
}
终止finally执行的方法
public class TryDemoOne {
public static void main(String[] args) {
// 要求:定义两个整数,输出两数之商
int one = 12;
int two = 2;
System.out.println("one和two的商是:" + (one/two));
//要求:定义两个整数,接受用户的键盘输入,输出两数之商
Scanner input = new Scanner(System.in);
System.out.println("====运算开始====");
System.out.println("请输入第一个整数:");
try{
int one = input.nextInt();
System.out.println("请输入第二个整数:");
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();
}finally{
System.out.println("====运算结束====");
}
}
}
return关键字在异常处理中的作用
public class TryDemoOne {
public static void main(String[] args) {
int result = test();
System.out.println("one和two的商是: "+ result);
}
public static int test() {
Scanner input = new Scanner(System.in);
System.out.println("====运算开始====");
try{
System.out.print("请输入第一个整数:");
int one = input.nextInt();
System.out.print("请输入第二个整数:");
int two = input.nextInt();
return one/two;
}catch(ArithmeticException e){
System.out.println("除数不允许为零");
return 0;
}finally{
System.out.println("=====运算结束=====");
return -1000000;
}
}
}
//无论怎么运作,最后都是强制执行finally的return。
//如果将finally的return屏蔽掉,就会正常执行。
使用throws声明异常类型
throw & throws
-
可以通过throws声明将要抛出何种类型的异常,通过throw将产生的异常抛出。
-
throw语句用在方法定义时声明该方法该方法要抛出的异常类型。
public void method() throws Exception1,Exception2,..,ExceptionN {
// 可能产生异常的代码
}
- 当方法抛出异常列表中的异常时,方法将不对这些类型及其子类类型的异常作处理,而抛向调用该方法的方法,由他去处理。
public class TryDemoOne {
public static void main(String[] args) {
try {
int result = test();
System.out.println("one和two的商是: "+ result);
} catch (ArithmeticException e) {
System.out.println("除数不允许为零");
e.printStackTrace();
}
}
public static int test() throws ArithmeticException{
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;
}
}
如果你在处理的时候会出现多种异常的话可以这样做。
第一种方案
public class TryDemoOne {
public static void main(String[] args) {
try {
int result = test();
System.out.println("one和two的商是: "+ result);
} catch (ArithmeticException e) {
System.out.println("除数不允许为零");
e.printStackTrace();
} catch (InputMismatchException e) {
System.out.println("请输入整数");
e.printStackTrace();
}
}
/*通过throws抛出异常时,针对可能出现的多种异常情况,解决方案:
1、throws后面接多个异常类型,中间用逗号分隔*/
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;
}
}
第二种方案
public class TryDemoOne {
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){
}
test();
}
/*通过throws抛出异常时,针对可能出现的多种异常情况,解决方案:
1、throws后面接多个异常类型,中间用逗号分隔
2、throws后面接Exception
/**
* 测试接受数据相除结果的方法
**/
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;
}
}
使用throw抛出异常对象
- throw用来抛出一个异常
- 例如:throw new IOException();
- throw 抛出的只能够是可抛出类Throwable 或者其子类的实例对象。
- 例如:throw new String(“出错啦”); 是错误的
throw
- 规避可能出现的风险
- 完成一些程序的逻辑
举个例子:
假如我开了一家宾馆,这家宾馆有一些特殊规定,就是未满18岁的未成年人必须有监护人陪伴,不然不得入住。
方案一:throw抛出异常对象的处理方案,通过try…catch包含throw语句–自己抛出自己处理
public class TryDemoFour {
public static void main(String[] args){
testAge();
}
//描述酒店的入住规则:限定年龄,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) {
e.printStackTrace();
}
}
}
//如果我们输入q的话就会抛出格式异常
第二种方案:通过throws在方法所声明出抛出异常类型–谁调用谁处理–调用者可以自己处理,也可以继续向上抛
public class TryDemoFour {
public static void main(String[] args){
try{
testAge();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void testAge() throws Exception{
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("欢迎入住本酒店");
}
}
}
自定义异常
- 使用Java内置的异常类可以描述在编程时出现的大部分异常情况。
- 也可以通过自定义异常描述特定业务产生的异常类型。
- 所谓自定义异常,就是定义一个类,去继承Throwable类或者它的子类。
public class TryDemoFour {
public static void main(String[] args){
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 HotelAgeException();
} else {
System.out.println("欢迎入住本酒店");
}
}
}
package com.imooc.test;
public class HoteAgeException extends Exception {
public HotelAgeException(){
super("18岁以下,80岁以上的住宿必须由亲友陪同");
}
}
异常链
- 有时候我们会捕获一个异常后在抛出另一个异常
public class TryDemoFive {
public static void main(String[] args) {
testThree();
}
public static void testOne() throws HoteAgeException {
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.initCouse(e);
throw e1;
//throw new Exception("我是新产生的异常2",e);
}
}
}