第十八章_Java中的异常处理

在这里插入图片描述

第十八章 Java中的异常处理


提纲

  • 18.1 异常的概述
  • 18.2 编写时异常
  • 18.3 运行时异常
    • 18.3.1 什么是运行时异常
    • 18.3.2 异常举例
    • 18.3.3 捕捉异常
  • 18.4 Java常见的异常
    • 18.4.1 Java异常类层次结构图
    • 18.4.2 常见异常及解释举例
    • 18.4.3 举例
  • 18.5 使用throws关键字抛出异常
  • 18.6 自定义异常与thorw关键字抛出异常
  • 18.7 作业

18.1 异常的概述

  1. 在程序中,错误可能产生于程序员没有预料到的各种情况,或者是超出了程序员可控范围的环境因素,如用户的坏数据、视图打开一个根本不存在的文件等。
  2. 异常分为两种:一种是在编写的过程中产生的语法错误,代码编译器会用红线进行提示。第二种是运行过程中所产生的错误。

18.2 编写时异常

  1. 什么是编写时异常:编写的过程中产生的语法错误,代码编译器会用红线进行提示。

  2. 举例:

     public class Test {
     	public static void main(String[] args) {
     		//当我用字符串给int类型赋值时,编译器直接报错。这个就是编写时异常
     		int a = "AAA";
     	}
     }
    
  3. 总结:编写时所产生的错误是必须在程序运行前解决的,否则程序是运行不了的。一般情况下可以把鼠标放在报红线的地方,编译器会给出英文提示。可以将英文提示用翻译器翻译出来。


18.3 运行时异常

  • 18.3.1 什么是运行时异常:程序编写后编译器不会报出任何错误,但是在程序运行的过程中会因为某些错误导致JVM虚拟机无法执行而产生异常,如果异常产生不做任何处理,程序就会被终止。

  • 18.3.2 异常举例:

      public class Test {
      	public static void main(String[] args) {
      		int result = 3 / 0;//定义一个整型变量
      		System.out.println("result="+result);//输出结果
      	}
      }
      //执行结果
      Exception in thread "main" java.lang.ArithmeticException: / by zero
      at com.zxjy.day1012.Test.main(Test.java:5)
    

    结论:1.结果中并未打印result=语句。证明程序终止在了错误的那一句。int result = 3 / 0;2.在打印的结果中有一个java.lang.ArithmeticException异常,并且打印了错误信息:/ by zero,即除数为0的错误。

  • 18.3.3 捕捉异常

    • 什么叫捕捉异常:当程序员觉得某处代码块可能会出现异常,则通过一个语句块来处理可能产生异常的这部分。

    • Java语言的异常捕获结构由try、catch和finally3部分组成。其中,try语句块存放的是可能发生异常的Java语句;catch程序快在try语句块之后,用来激发被捕获的异常;finally语句块是异常处理结构的最后执行部分,无论try语句块中的代码如何退出,都将执行finally语句块。try不能单独存在。有try-catch块,有try-finally块。

        //捕捉异常语法
        try {
        	
        } catch (异常类型1 e) {
        	//对异常类型1进行处理
        } catch (异常类型2 e) {
        	//对异常类型2进行处理
        }
        ....
        finally{
        	//程序块
        }
      
    • 举例:单个catch块

        public static void main(String[] args) {
        	try {
        		System.out.println("计算结果是");
        		int result = 3 / 0;
        		System.out.println("result="+result);
        	} catch (Exception e) {
        		System.out.println("这里是异常处理模块!");
        		System.out.println("e.getMessage():"+e.getMessage());
        		System.out.println("e.toString():"+e.toString());
        		e.printStackTrace();
        	} finally {
        		System.out.println("finally语句块!");
        	}
        	System.out.println("程序结束!");
        }
        //执行结果
        计算结果是
        这里是异常处理模块!
        e.getMessage():/ by zero
        e.toString():java.lang.ArithmeticException: / by zero
        java.lang.ArithmeticException: / by zero
        	at com.zxjy.day1012.Test.main(Test.java:7)
        finally语句块!
        程序结束!
      
      • 结论:
        1. 发生异常的语句之前代码可以执行,try-catch语句块中,异常语句之后的代码没有执行,而是直接运行了catch中的语句。
        2. 其中,Exception是一个异常对象类型,e是变量名,这个类中的主要方法:e.getMessage():得到具体错误的性质,e.toString():给出异常的类型与性质,e.printStackTrace();指出异常的类型、性质及出现在程序中的位置。
        3. 程序没有终止,try-catch语句块外的语句继续在执行。
        4. Java的异常处理是结构化的,不会因为一个异常影响整个程序的执行。
        5. finally语句块:无论程序中有无异常发生,并且无论之间的try-catch是否顺利执行完毕,都会执行finally语句。但是有以下五种特殊情况下,finally块不会被执行:
          1. 在finally语句块中发生了异常
          2. 在前面的代码中使用了System.exit(0)退出程序。这个System.exit(0)代码是终止Java虚拟机的运行,即退出结束当前的程序。
          3. 程序所在的线程死亡。
          4. 关闭CPU。
          5. 如果一个方法内在执行try{}语句之前就已经return了。只有与 finally 相对应的 try 语句块得到执行的情况下,finally 语句块才会执行。

18.4 Java常见的异常

  • 18.4.1 Java异常类层次结构图(见图解)
    在这里插入图片描述

  • 18.4.2 常见异常及解释举例:Java中提供了一些异常用来描述经常发生的错误,其中,有的需要程序员进行捕获处理或声明抛出,有的是由Java虚拟机自动进行捕获处理。
    在这里插入图片描述

    • 运行时异常RuntimeException
      1. ArithmeticException:算术异常。(当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。)

      2. ArrayIndexOutOfBoundsException:数组下标越界异常。(用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。)

      3. NullPointerException:空指针异常。(当应用程序试图在需要对象的地方使用 null 时,抛出该异常。)

         这种情况包括: 
         调用 null 对象的实例方法。 
         访问或修改 null 对象的字段。 
         将 null 作为一个数组,获得其长度。 
        
      4. ArrayStoreException:数组中包含不兼容的值抛出的异常。(试图将错误类型的对象存储到一个对象数组时抛出的异常。)

         Object x[] = new String[3];
         x[0] = new Integer(0);
        
      5. IllegalArgumentException:非法参数异常。(抛出的异常表明向方法传递了一个不合法或不正确的参数。)

      6. SecurityException:安全性异常。(由安全管理器抛出的异常,指示存在安全侵犯。)

      7. NegativeArraySizeException:数组元素个数为负数抛出的异常。(如果应用程序试图创建大小为负的数组,则抛出该异常。)

    • 其他异常
      1. ClassCastException:类型转换异常。(API官方解释:当试图将对象强制转换为不是实例的子类时,抛出该异常)

         Object x = new Integer(0);
         System.out.println((String)x);
        
      2. ClassNotFoundException:未找到相应类异常。(当应用程序试图使用以下方法通过字符串名加载类时,抛出该异常)

         Class 类中的 forName 方法。 
         ClassLoader 类中的 findSystemClass 方法。 
         ClassLoader 类中的 loadClass 方法。 
        
      3. SQLException:操作数据库异常类。(提供关于数据库访问错误或其他错误信息的异常。 )

      4. NoSuchFieldException:字段未找到异常。(类不包含指定名称的字段时产生的信号。 )

      5. NoSuchMethodException:方法未找到抛出的异常。(无法找到某一特定方法时,抛出该异常。)

      6. NumberFormatException:字符串转换为数字抛出异常。(当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。)

      7. StringIndexOutOfBoundsException:字符串索引超出范围抛出的异常。(此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。)

      8. IOException:输入输出异常。(当发生某种 I/O 异常时,抛出此异常。此类是失败或中断的 I/O 操作生成的异常的通用类。)

      9. IllegalAccessException:不允许访问某类异常。(当应用程序试图反射性地创建一个实例(而不是数组)、设置或获取一个字段,或者调用一个方法,但当前正在执行的方法无法访问指定类、字段、方法或构造方法的定义时,抛出 IllegalAccessException。)

      10. InstantiationException:当应用程序试图使用Class类中的newInstance()方法创建一个类的实例时,而指定的类的对象无法被实例化,抛出该异常。

      11. EOFException:文件已结束异常。(当输入过程中意外到达文件或流的末尾时,抛出此异常。)

      12. FileNotFoundException:文件未找到异常。(当试图打开指定路径名表示的文件失败时,抛出此异常。)

  • 18.4.3 举例:

    • 18.4.3.1 例1:要求实现,要求输入一个int类型的整数,如果输入的不是整数则要求重新输入。

        public static int getInt() {
        	int a=0;
        	Scanner scan=new Scanner(System.in);
        	try {
        		a=scan.nextInt();
        	} catch (Exception e) {
        		System.out.println("只能输入数字,请重新输入");
        		a=getInt();//输入错误,继续调自己
        	}
        	return a;
        }
      
    • 18.4.3.2 例2:嵌套try-catch块

        //1.嵌套try-catch块如果内层没有捕捉到则会继续到外层判断
        public class Test {
        	public static void main(String[] args) {
        		try {
        			try {
        				int a=10;
        				int b=0;
        				int c=a/b;
        			} catch(ArrayIndexOutOfBoundsException e) {//内层数组越界异常,但是这个是算术异常
        				System.out.println("内层异常");
        			}
        		} catch (Exception e) {
        			System.out.println("外层异常");
        		}
        	}
        }
        //执行结果
        外层异常
        //2. 嵌套try-catch块如果内层捕捉到了之后就不会进行外层判断
        public class Test {
        	public static void main(String[] args) {
        		try {
        			try {
        				int a=10;
        				int b=0;
        				int c=a/b;
        			} catch(ArithmeticException e) {//内层算术异常
        				System.out.println("内层异常");
        			}
        		} catch (Exception e) {
        			System.out.println("外层异常");
        		}
        	}
        }
        //执行结果
        内层异常
      
    • 18.4.3.3 例3:多个try-catch块

        public class Test {
        	public static void main(String[] args) {
        		Scanner scan = new Scanner(System.in);
        		System.out.println("请输入第一个数:");
        		int a = scan.nextInt();
        		System.out.println("请输入第二个数:");
        		int b = scan.nextInt();
        		int[] arry = new int[a];
        		String str = null;
        		try {
        			int c = a / b;
        			arry[b] = a;
        			System.out.println(str.equals(a));
        			System.out.println(c);
        		} catch (ArithmeticException e) {
        			System.out.println("算术异常");
        		} catch (ArrayIndexOutOfBoundsException e) {
        			System.out.println("数组下标越界了");
        		} catch (RuntimeException e) {
        			System.out.println("运行时异常");
        		}
        	}
        }
        //执行结果
        1.
        请输入第一个数:
        10
        请输入第二个数:
        0
        算术异常
        2.
        请输入第一个数:
        10
        请输入第二个数:
        -3
        数组下标越界了
        3.
        请输入第一个数:
        10
        请输入第二个数:
        5
        运行时异常
      

    结论:1.多个catch块时越是父类,越要往后写,否则会报错,可平行写。因为越是父类,包含的错误信息越多。2.如果第一层没有捕捉到则会继续往下一层判断,直到判断到可捕捉的异常时停止。

    • 18.4.3.4 例4:try-finally块:即将异常向外抛出,自己并不处理

        public class Test {
        	public static void main(String[] args) {
        		try {
        			int a = 11/0;
        		} finally {
        			System.out.println("finally语句块");
        		}
        	}
        }
        //执行结果
        finally语句块
        Exception in thread "main" java.lang.ArithmeticException: / by zero
        	at com.zxjy.day1012.Test.main(Test.java:7)
      

    结论:1.先执行try代码块,再执行finally代码块,最后将异常抛出。2.好处:它做了自己必须要做的事(finally),并向外抛出自己无法处理的异常;对于调用者来说,能够感知出现的异常,并可以按照需要进行处理。也就是说这种结构实现了职责的分离,实现了异常处理(throw)与异常清理(finally)的解耦,让不同的方法专注于自己应该做的事。

    • 18.4.3.5 例5:finally在return之前执行还是在return之后执行:在return中间执行。

        public class Test {
        	public static void main(String[] args) {
        		System.out.println(Test.method());
        	}
        	public static int method(){
        		try {
        			return 1;
        		} catch (Exception e) {
        			return 0;
        		} finally {
        			return 2;
        		}
        	}
        }
        //执行结果
        2
      

    **结论:**1.执行过程:这里仅仅需要注意的是在try{}语句中执行到return 1 会在临时栈中存储值为1的变量。接着回去执行finally里面的内容,这时执行finally中的return 2;方法,这时临时栈中的值就是变为 2,会覆盖原来临时栈中的值1.所以它的返回值为2。2.finally 语句块在 try 语句块中的 return 语句之前执行。3.finally 语句块在 catch 语句块中的 return 语句之前执行。


18.5 使用throws关键字抛出异常

  1. 什么是throws:在某个方法可能会发生异常,但不想在当前方法中处理这个异常,则可以使用throws、throw关键字在方法中抛出异常。throws关键字通常被应用在声明方法时,用来指定方法可能抛出的异常。向外抛出异常。

  2. 举例:

     public class Shoot {
     	static void pop() throws NegativeArraySizeException{
     		//定义方法并抛出NegativeArraySizeException异常
     		int[] arr = new int[-2];//创建数组
     	}
     	public static void main(String[] args) {
     		try {//try语句处理异常信息
     			Shoot.pop();//调用pop()方法
     		} catch (NegativeArraySizeException e) {
     			System.out.println("pop()方法抛出的异常");
     			e.printStackTrace();
     		}
     	}
     }
     //执行结果
     pop()方法抛出的异常
    

    结论:1.使用throws关键字将异常抛给上一级后,如果不想处理该异常,可以继续向上抛出,但是最终要有能够处理该异常的代码。2.如果是Error、RuntimeException或他们的子类,可以不用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。


18.6 自定义异常与thorw关键字抛出异常

  1. 为什么使用自定义异常:使用Java内置的异常类可以描述在编程时出现的大部分异常情况。但是在出现我们认为的逻辑错误时,会使用到自定义异常。比如,一般情况下一个人的年龄不能小于0,不能大于200。如果设置了年龄在这个区间外程序不会报错,但是我们认为是错误的。

  2. 如何创建一个自定义异常类:用户只需要继承Exception类即可自定义异常类。

  3. 使用自定义异常类的几个步骤:

    1. 创建自定义异常类。
    2. 在方法中通过throw关键字抛出异常对象。
    3. 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句块捕获并处理,否则在方法的声明处通过thorws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
    4. 在出现异常方法的调用者中捕获并处理异常。
  4. 举例:如何创建一个自定义异常类。

     //创建自定义异常,继承Exception类
     public class AgeException extends Exception{
     	String msg;
     	//构造方法,errorMsg是要输出的错误信息
     	public AgeException(String errorMsg) {
     		super(errorMsg);//给父类的构造方法传参
     		this.msg = errorMsg;//将错误信息赋值给msg
     	}
     	//覆盖getMessage()方法
     	public String getMessage() {
     		return msg;
     	}
     }
    
  5. throw关键字:

    1. 什么是throw:thorw关键字通常用于方法体中,并且抛出一个异常对象。程序在执行到throw语句时立即终止,它后面的语句都不执行。通过throw抛出异常后,如果想在上一级代码中来捕获并处理异常,则需要在抛出异常的方法中使用throws关键字在方法的声明中要抛出的异常;如果要捕捉throw抛出的异常。则必须使用try-catch语句块。

    2. 举例:解决年龄所出现的逻辑问题。

       //1.创建自定义异常,继承Exception类
       public class AgeException extends Exception{
       	String msg;
       	//构造方法,errorMsg是要输出的错误信息
       	public AgeException(String errorMsg) {
       		super(errorMsg);//给父类的构造方法传参
       		this.msg = errorMsg;//将错误信息赋值给msg
       	}
       	//覆盖getMessage()方法
       	public String getMessage() {
       		return msg;
       	}
       }
       //2.创建一个人类Person
       public class Person {
       	private int age;
       	public int getAge() {
       		return age;
       	}
       	//设置年龄,如果年龄不在0-200则抛出相应异常,如果不捕捉处理则必须用throws抛出。
       	public void setAge(int age) throws AgeException {
       		if (age > 200) {
       			//手动抛出一个自定义异常,也可以抛出内置的异常,但是throws必须抛出
       			throw new Exception("年龄不能大于200!");
       			throw new AgeException("年龄不能大于200!");
       		} else if (age < 0) {
       			throw new AgeException("年龄不能小于0!");
       		} else {
       			this.age = age;
       		}
       	}
       }
       //3.测试类测试
       public class Test {
       	public static void main(String[] args) {
       		Person person = new Person();
       		try {
       			person.setAge(500);
       		} catch (AgeException e) {
       			e.printStackTrace();
       		} finally {
       			System.out.println("年龄为:"+person.getAge());
       		}
       	}
       }
       //4.执行结果
       		com.zxjy.day1012.AgeException: 年龄不能大于200!
       	at com.zxjy.day1012.Person.setAge(Person.java:12)
       	at com.zxjy.day1012.Test.main(Test.java:7)
       年龄为:0
      

18.7 作业

  1. 编写如下一段程序:
    • 定义一个长度为10的数组,并给默认值。

    • 然后由控制台输入两个整数,第一个表示要访问的数组的索引,第二个表示获得的元素要除以的数字。

    • 结果为将第一个数字对应索引的数组元素值除以输入的第二个数字。

        5  10 2  100 87
        index input:  2
        num  input: 10
        sysout(arr [index]/num)
      
    • 考虑 以上代码会可能会出现多少种异常,并用异常处理的代码块来处理异常。

  2. 编写如下一段程序:
    • 实现从控制台输入三个数值作为三角形的三条边,以此构造一个三角形。程序应该实现如下功能:
    • 检查输入的命令行参数是否为数值格式,如果输入的数值参数格式错误,则程序可能产生InputMismatchException异常(java.util.InputMismatchException 需要导入这个类)。
    • 检查输入的命令行参数中是否有负值或0,如果有负值或0,则程序可能产生NumberValueException异常( NumberValueException为自定义异常)。
    • 检查输入的命令行参数的三个数值是否能够构造一个三角形,如果不能构造一个三角形,则程序可能产生TriangleException异常(TriangleException为自定义异常)。
    • 没出现异常则显示三个数字。
    • 提示:三角形任意两边之和必须大于第三边。
  3. (课后)编写继承体系: 宠物(eat(),cry()),猫,狗(重写父类方法)。
    • 编写宠物店类 提供方法:出售宠物 Pet sellPet(int i)。传入1 则返回猫对象,2 则返回狗对象。
    • 若传入的参数不是1或2,则抛出异常,显示:类型错误!!!
    • 在方法内使用try catch 处理异常,注意:思考出现异常时如何处理返回值。
    • 无论是否有异常 都要能输出一句话:“欢迎下次光临”。
    • 测试sellPet() 方法,调用返回的对象的cry方法。
      berValueException为自定义异常)。
    • 检查输入的命令行参数的三个数值是否能够构造一个三角形,如果不能构造一个三角形,则程序可能产生TriangleException异常(TriangleException为自定义异常)。
    • 没出现异常则显示三个数字。
    • 提示:三角形任意两边之和必须大于第三边。
  4. (课后)编写继承体系: 宠物(eat(),cry()),猫,狗(重写父类方法)。
    • 编写宠物店类 提供方法:出售宠物 Pet sellPet(int i)。传入1 则返回猫对象,2 则返回狗对象。
    • 若传入的参数不是1或2,则抛出异常,显示:类型错误!!!
    • 在方法内使用try catch 处理异常,注意:思考出现异常时如何处理返回值。
    • 无论是否有异常 都要能输出一句话:“欢迎下次光临”。
    • 测试sellPet() 方法,调用返回的对象的cry方法。
  • 32
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值