异常介绍、自定义异常、异常面试题

一、异常介绍

java.lang

Class Exception

  • java.lang.Object
    • java.lang.Throwable
      • java.lang.Exception

Exception是异常的英文,也是java.lang包下面的一个类,使用时不用导入。

java.langException继承自Throwable类。Throwable类有2个子类:Error,Exception其中,Error不进行处理,java中只处理异常Exception。

Exception是java中所有异常的父类、根类java中所有的异常类都直接或间接的继承自Exception类

1、java中异常有两大类:

异常介绍、自定义异常、异常面试题_第1张图片

(1)CheckedException(又叫非RuntimeException)

继承了Exception类的所有异常中,除了继承自运行时异常外的异常都是非运行时异常。

(2)Unchecked Exception(又叫RuntimeException运行时异常)

java中的运行时异常都直接或间接的继承自RuntimeException类。

  • java.lang.Object
    • java.lang.Throwable
      • java.lang.Exception
        • java.lang.RuntimeException

2、Exception的处理方法

(1)运行时异常RuntimeException的处理方法

运行时异常可做异常处理,也可以不做处理,推荐不做处理


有个常出现的运行时异常:NullPointerException

NullPointerException的意思是空指针异常,出现该异常的原因是某个引用为null,但却调用了此引用的某个方法。


(2)非运行时异常

对于非运行时异常必须要对其进行处理,处理方式有两种:第一种是使用try...catch...finally进行捕获;第二种是在调用了会产生异常方法的方法声明处进行抛出异常处理(throws Exception)。

  • if...catch...finally

if()

{

}

catch(Exception e)

{

}

finally

{

}

若if语句中遇到异常,则会继续执行catch语句,捕获异常;若if语句未出现异常,则不会处理catch语句;无论如何,finally中的语句一定会被执行,finally语句执行完后会继续执行下面的语句。

  • 抛出异常throw、throws
在一个方法里面可以使用关键字throw的方法手工去抛出异常,那么在方法声明处也应利用throws抛出异常,这就告诉调用此方法的其他方法这里有一个异常,也就是说在定义处不进行异常处理,在调用方法处再进行异常的处理;若调用方法时也使用了抛出异常,则最后会在main函数中会产生异常,若main函数也采用抛出异常的办法,则会交给JVM虚拟机自行处理此异常。

public class ExceptionTest

{

public void Method() throws Exception//告诉其他调用此方法的方法,要处理异常

{

throw new MyException();//此处会抛出一个异常,那么在方法声明处也必须进行异常处理

}

public static void main(String args[]) throws Exception//由于调用了Method方法,此处也要处理异常

{

ExceptionTest test = new ExceptionTest();

test.Method();

}

}


二、自定义异常

1、自定义异常的设计思路

所谓自定义异常,通常是定义了一个继承了Exception的子类。一般情况下,在定义时会直接继承Exception类,而不会去继承运行时异常类(RuntimeException)。

2、设计要点

(1)在使用自定义的异常时,必须要进行异常处理,可以进行抛出异常处理,也可以利用if...catch...finally捕获异常;

(2)若同时自定义了多个异常,则可利用多个catch块进行捕获,也可抛出异常。catch块是有顺序的,如果两个异常是子类和父类的关系,则父类的异常必须放在子类异常的后面;否则,若父类异常放在了子类异常的前面,则通过多态,所有异常都会在父类异常catch快中捕获,而没有机会去执行子类异常的catch块,程序编译会报错。

例如:

catch(Exception e)
        {
            e.printStackTrace();
        }
        catch(MyException1 e)
        {
            e.printStackTrace();
        }
        catch(MyException2 e)
        {
            e.printStackTrace();
        }

这样会报错,Exception的catch块必须放置在MyException1和MyException2的catch块之后。

 catch(MyException1 e)
        {
            e.printStackTrace();
        }
        catch(MyException2 e)
        {
            e.printStackTrace();
        }

catch(Exception e)
        {
            e.printStackTrace();
        }

当然,也可以只用Exception的catch块,因为Exception是所有异常的父类。

catch(Exception e)
        {
            e.printStackTrace();
        }

若两个异常没有关系,则可以随便放置,例如MyException1和MyException2的catch块可以调换顺序,而无影响。


3、示例

(1)MyException1异常定义

package com.lpp.exception;

@SuppressWarnings("serial")
public class MyException1 extends Exception
{
    @SuppressWarnings("unused")
    private String str;
    public MyException1()
    {
        
    }
    public MyException1(String str)
    {
        System.out.println(str);
    }
}

(2)MyException2异常定义

package com.lpp.exception;

@SuppressWarnings("serial")
public class MyException2 extends Exception
{
    @SuppressWarnings("unused")
    private String str;
    public MyException2()
    {
        
    }
    public MyException2(String str)
    {
        System.out.println(str);
    }
}

(3)调用异常

package com.lpp.exception;

public class ExceptionTest
{
    public void string(String str) throws Exception
    {
        if(null == str)
        {
            throw new MyException1("str不能为空");
        }
        else if("hello".equals(str))
        {
            throw new MyException2("str不能为hello");
        }
        else
        {
            System.out.println(str);
        }
    }
    public static void main(String[] args)
    {
        ExceptionTest test = new ExceptionTest();
        try
        {
            String str = null;
            test.string(str);
        }
        catch(MyException1 e)
        {
            e.printStackTrace();
        }
        catch(MyException2 e)
        {
            e.printStackTrace();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            System.out.println("OK");
        }
    }
    
}
结果:

str不能为空
com.lpp.exception.MyException1
    at com.lpp.exception.ExceptionTest.string(ExceptionTest.java:9)
    at com.lpp.exception.ExceptionTest.main(ExceptionTest.java:26)
OK

三、常见的异常面试问题

1、示例

public class ReturnException
{
    public static void main(String[] args)
    {
        try
        {
            System.out.println("try");
            return;
        }
        catch (Exception e)
        {
            System.out.println("catch");
            e.printStackTrace();
        }
        finally
        {
            System.out.println("finally");
        }
        System.out.println("ok");
    }
}

结果:

try
finally

总结:如果try块中存在return语句,则会先处理finally块(finally块外面的代码将不执行),然后方法再返回。


2、示例

public class ReturnException
{
    public static void main(String[] args)
    {
        try
        {
            System.out.println("try");
            System.exit(0);;
        }
        catch (Exception e)
        {
            System.out.println("catch");
            e.printStackTrace();
        }
        finally
        {
            System.out.println("finally");
        }
        System.out.println("ok");
    }
}

结果:

try

总结:如果try块中存在System.exit(0)语句,则不会执行finally中的代码,因为System.exit(0)会终止当前运行的java虚拟机,程序会在虚拟机终止前结束执行。


你可能感兴趣的:(JAVA基础)