Java进阶异常

Posted Ricky_0528

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java进阶异常相关的知识,希望对你有一定的参考价值。

文章目录

1 异常简介

错误在编写程序的过程中经常发生,包括编译期间和运行期间的错误

在程序运行过程中,意外发生的情况,背离程序本身的意图的表现,都可以理解为异常

2 异常处理简介

Throwable

  • Error
    • VirtualMachineError:虚拟机错误
    • OutOfMemoryError:内存溢出
    • ThreadDeath:线程死锁
  • Exception
    • Unchecked Exception:非检查异常
      • RuntimeException
        • NullPointerException:空指针异常
        • ArrayIndexOutOfBoundsException:数组下标越界异常
        • ArithmeticException:算术异常
        • ClassCastException:类型转换异常
    • Checked Exception:检查异常
      • IOException:IO异常
      • SQLException:SQL异常

异常处理机制为

  • 抛出异常

    • 异常类型
    • 异常出现时的程序状态
  • 捕捉异常

    对于运行时异常、错误或可查异常,Java技术所要求的异常处理方式有所不同

    • 对于可查异常必须捕捉、或者声明抛出
    • 允许忽略不可查的RuntimeException(含子类)和Error(含子类)
    • 捕获异常
      • try:执行可能产生异常的代码
      • catch:捕获异常
      • finally:无论是否发生异常,代码总能执行
    • 声明异常
      • throws:声明可能要抛出的异常
    • 抛出异常
      • throw:手动抛出异常

3 使用try-catch-finally处理异常

public void method() 
    try 
        // 代码段1
        // 产生异常的代码段2
     catch(异常类型 ex) 
        // 对异常进行处理的代码段3
     finally 
        // 代码段4
    

try块:用于捕获异常

catch块:用于处理try捕获到的异常

finally块:无论是否发生异常代码总能执行

语法要求:try块后可接零或多个catch块,如果没有catch块,则必须跟一个finally块,即try必须跟catch或finally组合使用

  • try-catch结构

    package com.ricky.test;
    
    import java.util.Scanner;
    
    public class TryDemoOne 
    
    	public static void main(String[] args) 
    		try 
    			Scanner input = new Scanner(System.in);
    			System.out.print("请输入第一个数:");
    			int one = input.nextInt();
    			System.out.print("请输入第二个数:");
    			int two = input.nextInt();
    			System.out.println("两个数的商为:" + (one / two));
    		 catch(Exception e) 
    			e.printStackTrace(); // 将抛出的错误直接输出
    		 finally 
    			System.out.println("运算结束");
    		
    	
    
    
  • 多重catch结构

    package com.ricky.test;
    
    import java.util.InputMismatchException;
    import java.util.Scanner;
    
    public class TryDemoOne 
    
    	public static void main(String[] args) 
    		try 
    			Scanner input = new Scanner(System.in);
    			System.out.print("请输入第一个数:");
    			int one = input.nextInt();
    			System.out.print("请输入第二个数:");
    			int two = input.nextInt();
    			System.out.println("两个数的商为:" + (one / two));
    		 catch(ArithmeticException e) 
    			System.out.println("除数不允许为0");
    		 catch(InputMismatchException e) 
    			System.out.println("请输入整数");
    		 catch(Exception e) 
    			// 通常建议在最后加上父类Exception用来追踪前面无法捕获的异常信息
    			// 一定是放在最后的
    			e.printStackTrace();
    		 finally 
    			System.out.println("运算结束");
    		
    	
    
    
  • 终止finally执行

    package com.ricky.test;
    
    import java.util.InputMismatchException;
    import java.util.Scanner;
    
    public class TryDemoOne 
    
    	public static void main(String[] args) 
    		try 
    			Scanner input = new Scanner(System.in);
    			System.out.print("请输入第一个数:");
    			int one = input.nextInt();
    			System.out.print("请输入第二个数:");
    			int two = input.nextInt();
    			System.out.println("两个数的商为:" + (one / two));
    		 catch(ArithmeticException e) 
    			System.exit(1); // 非0即表示程序异常终止,后面的语句都不会执行包括finally
    			System.out.println("除数不允许为0");
    		 catch(InputMismatchException e) 
    			System.out.println("请输入整数");
    		 catch(Exception e) 
    			e.printStackTrace();
    		 finally 
    			System.out.println("运算结束");
    		
    	
    
    
  • return关键字不要用早finally语句块中,这样无论如何返回的都是finally中的值,前面try、catch中的return都失效了

4 使用throw和throws实现异常处理

可以通过throws声明将要抛出何种类型的异常,通过throw将产生的异常抛出

①throws

throws语句用在方法定义是声明该方法要跑出的异常类型

public void method() throws Exception1, Exception2,...,ExceptionN 
	// 可能产生异常的代码

当方法抛出异常列表中的异常时,方法将不对这些类型及其子类类型的异常作处理,而抛向调用该方法的方法,由他去处理

  • throws后面接多个异常类型,中间以逗号分隔

    package com.ricky.test;
    
    import java.util.InputMismatchException;
    import java.util.Scanner;
    
    public class TryDemoOne 
    
    	public static void main(String[] args) 
    		try 
    			int result = test();
    			System.out.println("两个数的商为:" + result);
    		 catch(ArithmeticException e) 
    			System.out.println("除数不可以为0");
    			e.printStackTrace();
    		 catch(InputMismatchException e) 
                System.out.println("请输入整数");
    			e.printStackTrace();
            
    	
    	
    	public static int test() throws ArithmeticException, InputMismatchException 
    		Scanner input = new Scanner(System.in);
    		System.out.print("请输入第一个数:");
    		int one = input.nextInt();
    		System.out.print("请输入第二个数:");
    		int two = input.nextInt();
    		return one / two;
    	
    
    
  • throws后面接Exception

    package com.ricky.test;
    
    import java.util.InputMismatchException;
    import java.util.Scanner;
    
    public class TryDemoOne 
    
    	public static void main(String[] args) 
    		try 
    			int result = test();
    			System.out.println("两个数的商为:" + result);
    		 catch (ArithmeticException e) 
    			System.out.println("除数不可以为0");
    		 catch(InputMismatchException e) 
                System.out.println("请输入整数");
             catch(Exception e) 
                e.printStackTrace();
            
    	
    	
    	public static int test() 
    		Scanner input = new Scanner(System.in);
    		System.out.print("请输入第一个数:");
    		int one = input.nextInt();
    		System.out.print("请输入第二个数:");
    		int two = input.nextInt();
    		return one / two;
    	
    
    
    • throws Exception的情况,catch必须对Exception进行处理,前面Exception的子类都可以没有,因为Exception涵盖的范围很大
    • 并且由于Exception包含了Checked Exception(检查异常),因此不对Exception进行处理,编译器会直接报错
  • 书写文档注释,会提醒需要处理的异常(/** + 回车)

②throw

throw用来抛出一个异常,例如:throw new IOException();

throw抛出的只能够是可抛出类Throwable或者其子类的实例对象,例如throw new String("出错啦");是错误的

  • 方法一:通过try…catch包含throw语句——自己抛自己处理

    public void method() 
        try 
            // 代码段1
            throw new 异常类型();
         catch(异常类型 ex) 
            // 对异常进行处理的代码段2
        
    
    
  • 方法二:通过throws在方法声明处抛出异常类型——谁调用谁处理,调用者可以自己处理,也可以继续向上抛

    public void method() throws 异常类型 
        // 代码段1
        throw new 异常类型();
    
    

此时可以抛出与throw对象相同的类型或者其父类,不可以为子类

同时建议抛出一个检查异常,因为这样编译器对于异常的约束更强

5 自定义异常

使用Java内置的异常类可以描述在编程时出现的大部分异常情况

也可以通过自定义异常描述特定业务产生的异常类型

所谓自定义异常,就是定义一个类,去继承Throwable类或者它的子类

CustomTryDemo.java

package com.ricky.test;

import java.util.Scanner;

public class CustomTryDemo 
	
	public static void main(String[] args) 
		try 
			testAge();
		 catch(HotelAgeException e) 
			System.out.println(e.getMessage());
			System.out.println("不允许办理入住");
		
	
	
	public static void testAge() throws HotelAgeException 
		System.out.print("请输入年龄:");
		int age = new Scanner(System.in).nextInt();
		if (age < 18 || age > 80) 
			throw new HotelAgeException();
		 else 
			System.out.println("欢迎入住!");
		
	

HotelAgeException.java

package com.ricky.test;

public class HotelAgeException extends Exception 
	public HotelAgeException() 
		super("18岁以下80岁以上入住酒店需要有人陪同");
	

6 异常链

在捕获一个异常之后,再抛出一个异常,新抛出的异常会导致之前的异常丢失,如:

package com.ricky.test;

public class ExceptionChain 
	
	public static void main(String[] args) 
		try 
			testThree();
		 catch(Exception e) 
			e.printStackTrace();
		
	
	
	public static void testOne() throws HotelAgeException 
		throw new HotelAgeException();
	
	public static void testTwo() 
		try 
			testOne();
		 catch (HotelAgeException e) 
			throw new Exception("新产生的异常1");
		
	
	public static void testThree() 
		try 
			testTwo();
		 catch (Exception e) 
			throw new Exception("新产生的异常2");
		
	

为解决这个问题,Throwable类提供了一个构造方法

同时也提供了一个方法

package com.ricky.test;

public class ExceptionChain 
	
	public static void main(String[] args) 
		try 
			testThree();
		 catch(Exception e) 
			e.printStackTrace();
		
	
	
	public static void testOne() throws HotelAgeException 
		throw new HotelAgeException();
	
	public static void testTwo() 
		try 
			testOne();
		 catch (HotelAgeException e) 
			throw new Exception("新产生的异常1", e); //
		
	
	public static void testThree() 
		try 
			testTwo();
		 catch (Exception e) 
			Exception ee = new Exception("新产生的异常2");
			ee.initCause(e); //
			throw ee;
		
	


由此可见,异常链就是将异常发生的原因一个传一个串起来,即把底层的异常信息传给上层,这样逐层抛出

7 总结

try-catch-finally

  • 处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理
  • 在多重catch块后面,可以加一个catch(Exception)来处理可能会遗漏的异常
  • 对于不确定的代码,也可以加上try-catch,处理潜在的异常
  • 尽量去处理异常,切忌只是简单的调用printStackTrace()去打印输出
  • 具体如何处理异常,要根据不同的业务需求和异常类型去决定
  • 尽量添加finally语句去释放占用的资源

以上是关于Java进阶异常的主要内容,如果未能解决你的问题,请参考以下文章

Java进阶异常

异常 异常处理

Java中的异常

Java中的异常

Java中的异常

java基础知识十二