Java---09---异常

异常:

异常概述:

异常时程序运行时代码序列中产生的一种异常情况。这里采用的名词是异常而不是错误,是为了强调发生的事件未必是一个错误,异常也可能是某些很少出现的特殊事件。也可以理解为程序在运行时出现的不正常的情况。

 

例如:

1.想要打开的文件不存在

2.程序执行时除数为0

3.数组下标越界

...

 

一个除数为0 的例子

 

import java.util.Scanner;


public class EXCEPTION
{
    public static void main (String[] args)
    {
        int a,b,c;
        Scanner readScanner = new Scanner(System.in);
        a = readScanner.nextInt();
        b = readScanner.nextInt();
        c = a/b;
        System.out.println(c);
    }
}



 

输入 10 0 在控制台会出现:

10 0
Exception in thread "main" java.lang.ArithmeticException: / by zero
at EXCEPTION.main(EXCEPTION.java:10)


 

在main函数中出现了算术异常:被0除了。

 

这就是一个异常。

 

在Java中任何异常都是继承自Throwable的,Throwable分为Error和Exception,其中Error是不可恢复的错误,只有尽量不免,而Exception则是异常,是可以进行处理的。

 

异常的处理:try-catch-finally

 

try {
//需要被检测的代码
} catch (Exception e) {
// TODO: handle exception
//处理异常的代码(处理方式)
}
finally{
//一定会执行的语句
}


 

还是刚才的那个程序,进行处理:

 

import java.util.Scanner;


public class EXCEPTION
{
    public static void main (String[] args)
    {
        int a,b,c;
        Scanner readScanner = new Scanner(System.in);
        a = readScanner.nextInt();
        b = readScanner.nextInt();
        try
        {
            c = a/b;
            System.out.println(c);
        }
        catch(Exception e)
        {
            System.out.println("出现异常,分母为0");
        }
    }
}



 

 

再输入 10 0

打印结果为:

10 0
出现异常,分母为0



程序运行到 c = a/b;  的时候出现了异常,相当于新创建了一个异常类的对象 //new Exception ();   

catch捕获到了这个异常,并进行处理 :System.out.println("出现异常,分母为0");  

   

对捕获到的异常对象进行常见方法操作:

1.String getMessage()获取异常的信息

在catch语句中加上:System.out.println(e.getMessage());

显示结果为:/ by zero   

2.toString    

在catch语句中加上:System.out.println(e.toString());   

显示结果为:

java.lang.ArithmeticException: / by zero   


显示 异常名称,异常信息

3.printStackTrace

打印堆栈中的追踪信息,此方法无返回值,不需打印,直接调用

Catch语句中,e.printStackTrace();

显示结果为:

java.lang.ArithmeticException: / by zero
at EXCEPTION.main(EXCEPTION.java:11)


显示异常名称,异常信息,异常出现的位置

其实JVM默认的异常处理机制就是调用此方法。

 

throw和throws

 

 

import java.util.Scanner;

class div
{
    int div (int a,int b)throws Exception//在功能上通过throes关键字声明了该功能有可能会出现问题
    {
        return a/b;
    }
}

public class EXCEPTION
{
    public static void main (String[] args)
    {
        int a,b,c;
        div d = new div();
        Scanner readScanner = new Scanner(System.in);
        a = readScanner.nextInt();
        b = readScanner.nextInt();
        c = d.div(a, b);
        System.out.println(c);
    }
}



 

编译不能通过。

处理方式有两种:1.捕获(try-catch),2.抛出

第一种处理方式:捕获


import java.util.Scanner;

class div
{
    int div (int a,int b)throws Exception//在功能上通过throes关键字声明了该功能有可能会出现问题
    {
        return a/b;
    }
}

public class EXCEPTION
{
    public static void main (String[] args)
    {
        int a,b,c;
        div d = new div();
        Scanner readScanner = new Scanner(System.in);
        a = readScanner.nextInt();
        b = readScanner.nextInt();
        try
        {
            c = d.div(a, b);
            System.out.println(c);
        }
        catch (Exception e)
        {
// TODO: handle exception
            System.out.println(e.toString());
        }

    }
}



 

第二种方式:抛出throws


import java.util.Scanner;

class div
{
    int div (int a,int b)throws Exception//在功能上通过throes关键字声明了该功能有可能会出现问题
    {
        return a/b;
    }
}

public class EXCEPTION
{
    public static void main (String[] args)throws Exception
    {
        int a,b,c;
        div d = new div();
        Scanner readScanner = new Scanner(System.in);
        a = readScanner.nextInt();
        b = readScanner.nextInt();
        c = d.div(a, b);
        System.out.println(c);
    }
}

 


在主函数后加 throws Exception

将异常抛给虚拟机

显示结果:

1 0
Exception in thread "main" java.lang.ArithmeticException: / by zero
at div.div(EXCEPTION.java:6)
at EXCEPTION.main(EXCEPTION.java:25)


 

就相当于 将麻烦推给别人(JVM)了。

 

对多异常的处理:

 

我们在定义功能的时候有可能发生不止一个异常,需要我们对多个异常进行处理

比如说在刚才的异常的基础上,发生了数组下标越界。

 

class div
{
    int div (int a,int b)throws ArithmeticException,ArrayIndexOutOfBoundsException
    {
        int arr[] = new int[b];
        System.out.println(arr[5]);//有可能会造成数组越界
        return a/b;
    }
}



这是该如何处理?

1.声明异常时,建议声明更为具体的异常,这样处理的可以更具体

2.如果有多个异常,就需要对应多个catch语句进行捕获。当然只用一个catch语句,catch (Exception e)

也能实现处理,但是这样做没有针对性。

如果多个catch块中出现继承关系,父类异常catch块放在最下面。

 

 

public class EXCEPTION
{
    public static void main (String[] args)//throws Exception
    {
        int a,b,c;
        div d = new div();
        Scanner readScanner = new Scanner(System.in);
        a = readScanner.nextInt();
        b = readScanner.nextInt();
        try
        {
            c = d.div(a, b);
            System.out.println(c);
        }
        catch(ArithmeticException e)
        {
            System.out.println("00000"+"\n"+e.toString());
        }
        catch (ArrayIndexOutOfBoundsException e)
        {
// TODO: handle exception
            System.out.println("数组下标越界"+"\n"+e.toString());
        }
    }
}



 

逐个测试异常是否被处理

1.

4 1
数组下标越界
java.lang.ArrayIndexOutOfBoundsException: 5


第二个catch语句处理

2.

10 0
0
00000
java.lang.ArithmeticException: / by zero


第一个catch语句处理

3.有没有可能两种情况都发生?

10 0
0
00000
java.lang.ArithmeticException: / by zero


只处理了下标越界的问题,而没有处理0的问题,这是为什么?

按照程序执行的顺序,首先执行的是 System.out.println(arr[5]);  到这里发生了异常,程序就会停止并进行处理。 

 

 

自定义异常:

因为项目中有可能会出现一些没有被Java所描述并封装对象的问题,对这些问题

按照Java对问题封装的思想,进行自定义异常。

 

除数为0已经被Java封装,现在假定除数为负数也是异常。

 

自定义异常类:


class FushuException extends Exception{
    
    
}




必须是自定义类继承Exception。

继承Exception的原因:

异常体系有一个特点:

异常类和异常对象都需要被抛出,他们都具备可抛性。这个可抛性是Throwable这个体系中的独有特点。只有这个体系中的类和对象才可以被throws、throw操作。

 

 

我们自定义的异常,Java 无法识别,无法自动抛出,只能手动抛出(throw)。

当在函数内部出现throw抛出异常对象,就必须要给出对应的处理动作,要么在函数内部进行try,要么在函数上声明(throws)。

 

一般情况下,函数内出现异常,函数上需要声明。

 

代码:

 

import java.util.Scanner;

class FushuException extends Exception
{
}

class div
{
    int div (int a,int b)throws ArithmeticException,FushuException
    {
        if (b < 0)
            throw new FushuException();
        return a/b;
    }
}

public class EXCEPTION
{
    public static void main (String[] args)//throws Exception
    {
        int a,b,c;
        div d = new div();
        Scanner readScanner = new Scanner(System.in);
        a = readScanner.nextInt();
        b = readScanner.nextInt();
        try
        {
            c = d.div(a, b);
            System.out.println(c);
        }
        catch(ArithmeticException e)
        {
            System.out.println("00000"+"\n"+e.toString());
        }
        catch (FushuException e)
        {
// TODO: handle exception
            System.out.println("出现负数"+"\n"+e.toString());
        }
    }
}



 

显示结果:

3 -2
出现负数
FushuException



发现打印结果中只有异常的名称,而没有异常的信息。

以为自定义的异常并未定义信息。

 

如何定义异常信息?

复写getMessage方法。

 

class FushuException extends Exception
{
    private String s;
    public FushuException(String s)
    {
        super();
        this.s = s;
    }
    public String getMessage ()
    {
        return s;
    }
}



复写完成后,在抛异常的时候,将信息内容传递过来。


class div
{
    int div (int a,int b)throws ArithmeticException,FushuException
    {
        if (b < 0)
            throw new FushuException("出现负数");
        return a/b;
    }
}




显示结果:


3 -2
FushuException: 出现负数




这样做虽然没有问题,但是太麻烦了。

 

 

Exception都是继承自Throwable的。

Throwable中所有的方法在子类中都可以直接调用。

我们通过查API文档发现Exception类中没有定义新的方法,所有的方法都是继承自Throwable的。

所以只需将调用Exception的构造方法完成初始化,就可以调用父类中的getMessage方法。无需复写。

 

class FushuException extends Exception
{
    public FushuException(String s)
    {
        super(s);
    }
}



 

 

Throw和throws的区别:

Throws使用在函数上

Throw使用在函数内

 

Throws后面跟的是异常类,可以跟多个。

Throw后面跟的是异常对象。

 

RuntimeException是一个非常特殊的异常类。(运行时异常)

如果在函数内抛出该异常,函数上可以不用声明,编译一样通过。

如果在函数上声明了该异常,调用者可以不用处理(try、throw),编译一样通过。

 

class div
{
    int div (int a,int b)
    {
        if (b == 0)
            throw new ArithmeticException();
        return a/b;
    }
}

class div
{
    int div (int a,int b)throws ArithmeticException
    {
//if (b == 0)
//throw new ArithmeticException();
        return a/b;
    }
}



 

这两种方式都可以通过编译。

之所以不用在函数上声明,是因为不需要让调用者处理。

当该异常发生,希望程序停止。因为运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修改。

 

自定义异常时,如果该异常的发生无法再继续进行运算的话,就让自定义的异常继承RuntimeException。


 

 

finally

finally中存放的是一定会执行的代码。

无论有没有异常,finally中的代码一定会被执行。

 

import java.util.Scanner;


class FushuException extends Exception
{
    private String s;
    public FushuException(String s)
    {
        super(s);
    }
}

class div
{
    int div (int a,int b)throws FushuException
    {
        if ( b < 0)
            throw new FushuException("出现负数");
        return a/b;
    }
}

public class EXCEPTION
{
    public static void main (String[] args)//throws Exception
    {
        int a,b,c;
        div d = new div();
        Scanner readScanner = new Scanner(System.in);
        a = readScanner.nextInt();
        b = readScanner.nextInt();
        try
        {
            c = d.div(a, b);
            System.out.println(c);
        }
        catch (FushuException e)
        {
// TODO: handle exception
            System.out.println(e.toString());
        }
        finally
        {
            System.out.println("finally");
        }
        System.out.println("Over");
    }
}



 

显示结果:

4 1
4
finally
Over


 

4 -2
FushuException: 出现负数
finally
Over

 


 

Over和finally都被执行了,看上去好像没什么区别。

当发生这种情况的时候:当程序出现异常时,处理完成后,程序return了,那么finall中的代码还会执行吗?Over还会执行吗?

 

在catch块中加return

显示结果;

 

4 -1
FushuException: 出现负数
finally


 

finally依然会执行,但是over却不会执行。

 

finally代码块中存放的是一定会被执行的代码。无论有没有异常都会执行。通常用于关闭资源。

 

Try-catch-finally语句的格式:

3个格式:

1.

try
{
}
catch (Exception e)
{
// TODO: handle exception
}



2.


 

try
{
}
catch (Exception e)
{
// TODO: handle exception
} finally
{
}

3.


try
{
    
} finally
{
    
}

 

 

异常在子父类覆盖中的体现;

1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者改异常的子类。

 

class AException extends Exception
{
}

class BException extends AException
{
}
class CException extends Exception
{
}

class Fu
{
    void show () throws AException
}

class Zi extends Fu
{
    void show ()throws AException 或者 BException
    {
    }
}



 

2.如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。

3.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类方法发生了异常,就必须进行try处理,绝对不能抛。

 

 

 


 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。