异常

异常

1 三种类型的异常:

  • 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
  • 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
  • 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

2 Java异常处理涉及到五个关键字,分别是:trycatchfinallythrowthrows。下面将骤一介绍,通过认识这五个关键字,掌握基本异常处理知识。

  • try        -- 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。
  • catch   -- 用于捕获异常。catch用来捕获try语句块中发生的异常。
  • finally  -- finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
  • throw   -- 用于抛出异常。
  • throws -- 用在方法签名中,用于声明该方法可能抛出的异常。

 3 Java的异常类型

1 编译时异常

1、除0发生算数异常(ArithmeticException)
关键技术解析:在数学中,除0的操作时不对的,在Java程序中也是这样,一个被除数为0,就要抛出异常.

2、数组下标越界异常(ArrayIndexOutOfException)
关键技术解析:ArrayIndexOutOfException异常用非法索引访问数组时抛出的异常,如果索引为负或大于等于数组大小,则该索引为非法索引。

3、数组元素类型不匹配异常(ArrayStoreExption)
关键技术解析:定义三个不同类型的元素对象,这三个元素对象相互组合,就会出现数组元素类型不匹配异常。试图将错误类型的对象储存到一个对象数组时抛出异常。

4、强制类型转换异常(ClassCastException)
关键技术解析:在进行转换时,转换的两个类型不匹配,就会发生异常。

5、索引越界异常(IndexOutOfBoundsException)
关键技术解析:索引越界异常在某排序索引(例如对字符串或数组的排序)超出范围是抛出。应用程序可以为这个类创建子类,以指示类似的异常。

6、空指针异常(NullPointerException)
关键技术解析:当应用程序试图在需要对象的地方使用null时,抛出该异常。这种情况包括:
a.调用null对象的实例方法
b.访问或修改null对象的字段
c.应用程序应该抛出该类实例,只是其他对null对象的非法使用

7、数字格式转换异常(NumberFornatException)
关键技术解析:当应用试图把一个字符串转换成一个数值类型,但这个字符串没有恰当的格式时就会抛出数字格式转换异常。

8、字符串索引越界异常(StringIndexOutException)
关键技术解析:StringIndexOutException异常用非法索引访问字符串抛出的异常。如果索引为负或大于等于字符串的大小,则该索引为非法索引。

8、操作错误(UnsupportedOperationException)
关键技术解析:java.lang.UnsupportedOperationException异常是由于Arrays.asList()返回java.util.Arrays$ArrayList,而不是ArrayList。Arrays$ArrayList和ArrayList都是继承AbstractList,add等方法在AbstractList中是默认抛出UnsupportedOperationException而且不做任何操作。

2 运行时异常

1、找不到指定类时发生的异常(ClassNotFoundException)
关键技术解析
a.当程序加载Class类中的forName()方法时,异常抛出。同时,也有其它方法可以抛出同样的异常,如:ClassLoader类中的findSystemClass方法,loadClass方法。
b.在构造时提供并通过getException()方法访问的"加载类是引发的可选异常",现在被称为原因,它可以通过Throwable.getCause()方法以及上面提到的"遗留犯方法"来访问。

2、请求的方法不存在(NoSuchMethodException)
关键技术解析:当应用试图调用某个类的某种方法,而该类中没有该方法的定义时抛出该异常。

下面是两种常见异常

package com.example;
import java. util .Scanner ;
public class AllDemo
{
      public static void main (String [] args )
      {
            System . out. println( "----欢迎使用命令行除法计算器----" ) ;
            CMDCalculate ();
      }
      public static void CMDCalculate ()
      {
            Scanner scan = new Scanner ( System. in );
            int num1 = scan .nextInt () ;
            int num2 = scan .nextInt () ;
            int result = devide (num1 , num2 ) ;
            System . out. println( "result:" + result) ;
            scan .close () ;
      }
      public static int devide (int num1, int num2 ){
            return num1 / num2 ;
      }
}
/*****************************************

----欢迎使用命令行除法计算器----
2
0
Exception in thread "main" java.lang.ArithmeticException : / by zero
     at com.example.AllDemo.devide( AllDemo.java:30 )
     at com.example.AllDemo.CMDCalculate( AllDemo.java:22 )
     at com.example.AllDemo.main( AllDemo.java:12 )

----欢迎使用命令行除法计算器----
1
r
Exception in thread "main" java.util.InputMismatchException
     at java.util.Scanner.throwFor( Scanner.java:864 )
     at java.util.Scanner.next( Scanner.java:1485 )
     at java.util.Scanner.nextInt( Scanner.java:2117 )
     at java.util.Scanner.nextInt( Scanner.java:2076 )
     at com.example.AllDemo.CMDCalculate( AllDemo.java:20 )
     at com.example.AllDemo.main( AllDemo.java:12 )
*****************************************/

4 异常的分层结构

 

5 异常处理的基本语法

在编写代码处理异常时,对于检查异常,有2种不同的处理方式:使用try...catch...finally语句块处理它。或者,在函数签名中使用throws 声明交给函数调用者caller去解决。

1 try...catch...finally

try{
     //try块中放可能发生异常的代码。     //如果执行完try且不发生异常,则接着去执行finally块和finally后面的代码(如果有的话)。     //如果发生异常,则尝试去匹配catch块。

}catch(SQLException SQLexception){
    //每一个catch块用于捕获并处理一个特定的异常,或者这异常类型的子类。Java7中可以将多个异常声明在一个catch中。
    //catch后面的括号定义了异常类型和异常参数。如果异常与之匹配且是最先匹配到的,则虚拟机将使用这个catch块来处理异常。
    //在catch块中可以使用这个块的异常参数来获取异常的相关信息。异常参数是这个catch块中的局部变量,其它块不能访问。
    //如果当前try块中发生的异常在后续的所有catch中都没捕获到,则先去执行finally,然后到这个函数的外部caller中去匹配异常处理器。    //如果try中没有发生异常,则所有的catch块将被忽略。
}catch(Exception exception){
    //...
}finally{
       //finally块通常是可选的。   //无论异常是否发生,异常是否匹配被处理,finally都会执行。
   //一个try至少要有一个catch块,否则, 至少要有1个finally块。但是finally不是用来处理异常的,finally不会捕获异常。
  //finally主要做一些清理工作,如流的关闭,数据库连接的关闭等。 

  

需要注意的地方

1、try块中的局部变量和catch块中的局部变量(包括异常变量),以及finally中的局部变量,他们之间不可共享使用。
 
2、每一个catch块用于处理一个异常。异常匹配是按照catch块的顺序从上往下寻找的,只有第一个匹配的catch会得到执行。匹配时,不仅运行精确匹配,也支持父类匹配,因此,如果同一个try块下的多个catch异常类型有父子关系,应该将子类异常放在前面,父类异常放在后面,这样保证每个catch块都有存在的意义。
 
3、java中,异常处理的任务就是将执行控制流从异常发生的地方转移到能够处理这种异常的地方去。也就是说:当一个函数的某条语句发生异常时,这条语句的后面的语句不会再执行,它失去了焦点。执行流跳转到最近的匹配的异常处理catch代码块去执行,异常被处理完后,执行流会接着在“处理了这个异常的catch代码块”后面接着执行。
有的编程语言当异常被处理后,控制流会恢复到异常抛出点接着执行,这种策略叫做:resumption model of exception handling(恢复式异常处理模式 )
而Java则是让执行流恢复到处理了异常的catch块后接着执行,这种策略叫做:termination model of exception handling(终结式异常处理模式)
public static void main(String[] args){
        try {
            foo();
        }catch(ArithmeticException ae) {
            System.out.println("处理异常");
        }
}
public static void foo(){
        int a = 5/0;  //异常抛出点
        System.out.println("为什么还不给我涨工资!!!");  //////////////////////不会执行
}

  

2 throws 函数声明

throws声明:如果一个方法内部的代码会抛出检查异常(checked exception),而方法自己又没有完全处理掉,则javac保证你必须在方法的签名上使用throws关键字声明这些可能抛出的异常,否则编译不通过。

throws是另一种处理异常的方式,它不同于try...catch...finally,throws仅仅是将函数中可能出现的异常向调用者声明,而自己则不具体处理。

采取这种异常处理的原因可能是:方法本身不知道如何处理这样的异常,或者说让调用者处理更好,调用者需要为可能发生的异常负责

public void foo() throws ExceptionType1 , ExceptionType2 ,ExceptionTypeN
{ 
     //foo内部可以抛出 ExceptionType1 , ExceptionType2 ,ExceptionTypeN 类的异常,或者他们的子类的异常对象。
}

 

3 throw 异常抛出语句

throw exceptionObject

程序员也可以通过throw语句手动显式的抛出一个异常。throw语句的后面必须是一个异常对象。

throw 语句必须写在函数中,执行throw 语句的地方就是一个异常抛出点,它和由JRE自动形成的异常抛出点没有任何差别。

 
public void save(User user)
{
      if(user  == null) 
          throw new IllegalArgumentException("User对象为空");
      //......
        
}

  

 

6 自定义异常

在程序中使用自定义异常类,大体可分为以下几个步骤:

  • 创建自定义异常类。
  • 在方法中通过throw关键字抛出异常对象。
  • 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
  • 在出现异常方法的调用者中捕获并处理异常。
    class MyException extends Exception {
        private int detail;
        MyException(int a){
            detail = a;
        }
        public String toString(){
            return "MyException ["+ detail + "]";
        }
    }
    public class TestMyException{
        static void compute(int a) throws MyException{
            System.out.println("Called compute(" + a + ")");
            if(a > 10){
                throw new MyException(a);
            }
            System.out.println("Normal exit!");
        }
        public static void main(String [] args){
            try{
                compute(1);
                compute(20);
            }catch(MyException me){
                System.out.println("Caught " + me);
            }
        }
    }
    

      

 

posted @ 2021-01-18 15:46  想变成葡萄的橙子  阅读(250)  评论(0)    收藏  举报