java异常详解编程语言

Java异常类类图
下面是这几个类的层次图:
java.lang.Object
  java.lang.Throwable
      java.lang.Exception
       java.lang.RuntimeException
   java.lang.Error
       java.lang.ThreadDeath
下面四个类的介绍来自java api 文档。
1、Throwable
  Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。
两个子类的实例,Error 和 Exception,通常用于指示发生了异常情况。通常,这些实例是在异常情况的上下文中新近创建的,因此包含了相关的信息(比如堆栈跟踪数据)。
2、Exception
  Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件,表示程序本身可以处理的异常
 
3、Error
  Error 是 Throwable 的子类,表示仅靠程序本身无法恢复的严重错误,用于指示合理的应用程序不应该试图捕获的严重问题。
在执行该方法期间,无需在方法中通过throws声明可能抛出但没有捕获的 Error 的任何子类,因为Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没有用try…catch语句捕获它,也没有用throws字句声明抛出它,还是会编译通过。
4、RuntimeException
  RuntimeException 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没有用try…catch语句捕获它,也没有用throws字句声明抛出它,还是会编译通过,这种异常可以通过改进代码实现来避免。
5.方法重写时:在子类中一个重写的方法可能只抛出父类中声明过的异常或者异常的子类

Error类和Exception类都继承自Throwable类。

  • Error的继承关系:

java.lang.Object 
java异常详解编程语言 java.lang.Throwable
      java异常详解编程语言java.lang.Error

  • Exception的继承关系:

java.lang.Object
java异常详解编程语言java.lang.Throwable
     java异常详解编程语言java.lang.Exception

二者的不同之处:

 

Exception:
1.可以是可被控制(checked) 或不可控制的(unchecked) 
2.表示一个由程序员导致的错误 
3.应该在应用程序级被处理

Error:
1.总是不可控制的(unchecked) 
2.经常用来用于表示系统错误或低层资源的错误 
3.如何可能的话,应该在系统级被捕捉

Java 中定义了两类异常: 

  1) Checked exception: 这类异常都是Exception的子类 。异常的向上抛出机制进行处理,假如子类可能产生A异常,那么在父类中也必须throws A异常。可能导致的问题:代码效率低,耦合度过高。这种异常的特点是要么用try…catch捕获处理,要么用throws语句声明抛出,否则编译不会通过。  
  2) Unchecked exception: 这类异常都是RuntimeException的子类,虽然RuntimeException同样也是Exception的子类,但是它们是非凡的,它们不能通过client code来试图解决,所以称为Unchecked exception 。这种异常的特点是Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没有用try…catch语句捕获它,也没有用throws字句声明抛出它,还是会编译通过。例如,当除数为零时,就会抛出java.lang.ArithmeticException异常。

Checked Exception与Runtime Exception 的区别

异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。Java编译器要求方法必须声明抛出可能发生的受检异常,但是并不要求必须声明抛出未被捕获的运行时异常。异常和继承一样,是面向对象程序设计中经常被滥用的东西,神作《Effective Java》中对异常的使用给出了以下指导原则:

  • 不要将异常处理用于正常的控制流(设计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)
  • 对可以恢复的情况使用受检异常,对编程错误使用运行时异常
  • 避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)
  • 优先使用标准的异常
  • 每个方法抛出的异常都要有文档
  • 保持异常的原子性
  • 不要在 catch 中忽略掉捕获到的异常
RuntimeException异常表示无法让程序恢复运行的异常,导致这种异常的原因通常是由于执行了错误的操作。一旦出现错误,建议让程序终止。
受检查异常表示程序可以处理的异常。如果抛出异常的方法本身不处理或者不能处理它,那么方法的调用者就必须去处理该异常,否则调用会出错,连编译也无法通过。当然,这两种异常都是可以通过程序来捕获并处理的,比如除数为零的运行时异常:
<span style="font-family:SimSun;">public class HelloWorld { 
 public static void main(String[] args) { 
  System.out.println("Hello World!!!");  
  try{ 
   System.out.println(1/0); 
  }catch(ArithmeticException e){ 
   System.out.println("除数为0!"); 
  } 
  System.out.println("除数为零后程序没有终止啊,呵呵!!!");   
 } 
} 

运行结果:
Hello World!!!
除数为0!
除数为零后程序没有终止啊,呵呵!!!
最佳解决方案
  对于运行时异常,我们不要用try…catch来捕获处理,而是在程序开发调试阶段,尽量去避免这种异常,一旦发现该异常,正确的做法就会改进程序设计的代码和实现方式,修改程序中的错误,从而避免这种异常。捕获并处理运行时异常是好的解决办法,因为可以通过改进代码实现来避免该种异常的发生。
  对于受检查异常,没说的,老老实实去按照异常处理的方法去处理,要么用try…catch捕获并解决,要么用throws抛出!
   对于Error(运行时错误),不需要在程序中做任何处理,出现问题后,应该在程序在外的地方找问题,然后解决。
Java异常处理通过5个关键字try、catch、throw、throws、finally进行管理。一般情况下是用 try 来执行一段程序,如果出现异常,系统会抛出(throw)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理;try 用来指定一块预防所有“异常”的程序;catch 子句紧跟在 try 块后面,用来指定你想要捕捉的“异常”的类型;throw 语句用来明确地抛出一个“异常”;throws用来标明一个成员函数可能抛出的各种“异常”;finally 为确保一段代码不管发生什么“异常”都被执行一段代码;可以在一个成员函数调用的外面写一个 try 语句,在这个成员函数内部写另一个 try 语句保护其他代码。每当遇到一个 try 语句,“异常”的框架就放到栈上面,直到所有的 try 语句都完成。如果下一级的 try 语句没有对某种“异常”进行处理,栈就会展开,直到遇到有处理这种“异常”的 try 语句。finally语句块会在方法执行return之前执行,一般结构如下:
 public void test() throws 异常{
 try{
  程序代码
  throw 异常
 }catch(异常类型1 异常的变量名1){
  程序代码
 }catch(异常类型2 异常的变量名2){
  程序代码
 }finally{
  程序代码
 }
}
  catch语句可以有多个,用来匹配多个异常,匹配上多个中一个后,执行catch语句块时候仅仅执行匹配上的异常。catch的类型是Java语言中定义的或者程序员自己定义的,表示代码抛出异常的类型,异常的变量名表示抛出异常的对象的引用,如果catch捕获并匹配上了该异常,那么就可以直接用这个异常变量名,此时该异常变量名指向所匹配的异常,并且在catch代码块中可以直接引用。这一点非常非常的特殊和重要!
<span style="font-family:SimSun;"> public void getCustomerInfo() { 
        try { 
            // do something that may cause an Exception 
        } catch (java.io.FileNotFoundException ex) { 
            System.out.print("FileNotFoundException!"); 
        } catch (java.io.IOException ex) { 
            System.out.print("IOException!"); 
        } catch (java.lang.Exception ex) { 
            System.out.print("Exception!"); 
        } 
    }

如果在该方法运行中产生了一个 IOException,输出结果为:

 IOException!
5种常见到的RuntimeExcption

NullPointerException:当操作一个空引用时会出现此错误。

NumberFormatException:数据格式转换出现问题时出现此异常。

ClassCastException:强制类型转换类型不匹配时出现此异常。

ArrayIndexOutOfBoundsException:数组下标越界,当使用一个不存在的数组下标时出现此异常。

ArithmeticException:数学运行错误时出现此异常

注意问题:

1、子类继承父类后,覆盖父类原方法时,所抛出的具体异常的个数必须是小于等于父类方法抛出的具体异常的个数。
2、调用方法抛出的必须等同于被调用方法抛出的异常或者是被调用方法所抛异常的父类,绝不可以是其子类,如下是错的,编译错误:
public static void main(String[] args) throws FileNotFoundException { 
		Scanner sc = new Scanner(System.in); 
		test(); 
	}	 
	public static void test() throws Exception{ 
		System.out.println("file not found");		 
	}

方法中同一种异常只能存在于catch和throws之一,不能同时存在,如下是错的,编译错误:

	public static void test() throws FileNotFoundException{ 
		try{ 
		System.out.println("file not found"); 
		}catch( FileNotFoundException e){ 
			e.printStackTrace(); 
		} 
	}

但如下是对的:catch可能还捕获了其他类型能改的异常,而函数声明中只抛出了FileNotFoundException

	public static void test() throws FileNotFoundException{ 
		try{ 
		System.out.println("file not found"); 
		}catch( Exception e){ 
			e.printStackTrace(); 
		} 
	}

如下是错的:编译错误,即throws 中声明的错误必须是catch的子类,不可是同等级或者其父类

public static void test() throws Exception{ 
		try{ 
		System.out.println("file not found"); 
		}catch( FileNotFoundException e){ 
			e.printStackTrace(); 
		} 
	}

但如下是对的:

	public static void test() throws Exception{ 
		try{ 
		System.out.println("file not found"); 
		throw new Exception();//或者为<span style="font-family: Arial, Helvetica, sans-serif;">throw new <span style="font-family: Arial, Helvetica, sans-serif;">FileNotFoundException <span style="font-family: Arial, Helvetica, sans-serif;">() 
		}catch( FileNotFoundException e){ 
			e.printStackTrace(); 
		} 
	}

对比,如下是错的,编译错误:

	public static void test() throws Exception{ 
		try{ 
		System.out.println("file not found"); 
		throw new NullPointerException(); 
		}catch( FileNotFoundException e){ 
			e.printStackTrace(); 
		} 
	}

由此可见,如果throw了某类异常,则可以catch该类异常,同时throws声明,如果throw了某类异常,而catch了其他类型异常,不管有没有throws,都不可以。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/13762.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论