Java中的异常分为两大类:

  1、已检查异常(Checked Exception):凡是继承自Exception类,但是不继承自RuntimeException类的异常类都叫做已检查异常;

  2、未检查异常(Unchecked Exception)或叫Runtime Exception:凡是继承自RuntimeException类的异常类都叫做未检查异常。

Throwable类底下存在两个子类分别是Error类和Exception类:

  1、对于Error类,表示系统错误,我们在程序中无法对其进行操作,一旦出现错误,只能是程序终止;

  2、对于Exception类,我们可以编写相应的异常处理器来对异常进行及时的处理。

Java中所有的异常都会直接或间接地继承自Exception。

RuntimeException类也是继承自Exception类,它叫做运行时异常,Java中所有的运行时异常都会直接或间接地继承自RuntimeException。


异常对象生成机制讲解:            七十三-04:00

finally详解:                      七十三-10:00

异常处理的一般结构是:

try
{
  // ur code here
}

catch(Exception e)
{
     // Exception disposal
}
finally
{
    // finally code here
}

 

无论程序是否出现异常,finally块中的代码均会执行。

一个try后面不管有多少个catch被定义,最多仅仅会有一个catch语句块被执行!!

代码编写抛出异常对象:

package com.edu.bupt.exception;

public class Exception2
{
    public void method() throws Exception
    {
        System.out.println("in method");
        
        throw new Exception();
    }
    
    public static void main(String[] args) throws Exception
    {
        Exception2 e2 = new Exception2();
        
        e2.method();
    }
}

 

异常本质也是一种类,因此在抛出的时候也是首先需要new一个异常类型的对象,然后通过throw关键字对生成的异常对象进行抛出。 

当抛出一个异常对象的时候,会有两种途径对其进行处理(这里的异常,可以是cheked Exception,也可以是unchecked Exception),一种是通过try...catch处理器对其进行处理,另一种就是在方法声明部分利用throws关键字将异常对象传递至调用该方法的方法中,那个方法负责对该异常对象进行后续处理。

当在main方法头部使用throws关键字进行抛出的时候异常的时候,是由虚拟机对其进行抛出。

当打印出来异常的堆栈信息的时候,最底下的信息时调用方法的最顶层,例如main函数,如下图:

java 违反检查约束条件 java已检查异常_System

 


 

对于checked exception ,必须对其进行处理,处理方式仍然是上述的两种。

对于unchecked exception , 我们可以不对其进行处理,也可以对其进行处理,推荐不对其进行处理,因为Runtime Excetpion是在编写代码的时候完全可以避免的,与其对Runtime Exception编写处理方法,不如好好检查程序,避免这种异常情况的发生。

NullPointerExcepion,是发生频率最高的Runtime Exception,它表示某一个引用变量指向了null,而你还去按照该引用变量的方式去调用其中的方法。

 


自定义异常:

 所谓自定义异常,通常就是定义了一个继承自Exception类的子类(可以继承自RuntimeException,也可以继承自Exception,前者自定义了一个运行时异常,后者自定义了一个非运行时异常);

一般不会继承某个运行时的异常类。

七十四-21:47

package com.edu.bupt.exception;

public class MyException extends Exception
{
    public MyException()
    {
        super();
    }
    
    public MyException(String message)
    {
        super(message);
    }
}

 

 对底层异常进行二次封装(例如:数据库连接异常),即可使用自定义异常,并在构造的时候传入底层异常,使之成为本地化的异常信息:

package com.edu.bupt.exception;

public class ExceptionTest4
{
    public void method(String str) throws MyException
    {
        if (null == str)
        {
            throw new MyException("null String passed into method");
        }
        else
        {
            System.out.println(str);
        }
    }
    
    public static void main(String[] args) throws MyException
    {
        new ExceptionTest4().method(null);
    }
}

 

运行结果:

java 违反检查约束条件 java已检查异常_sed_02

main方法不被任何方法调用,而是由JavaVM调用main方法,因此当main方法继续将异常抛出的时候,有JavaVM对main方法抛出的异常进行处理。

package com.edu.bupt.exception;

public class ExceptionTest4
{
    public void method(String str) throws MyException
    {
        if (null == str)
        {
            throw new MyException("null String passed into method");
        }
        else
        {
            System.out.println(str);
        }
    }

    public static void main(String[] args)
    {
        try
        {
            new ExceptionTest4().method(null);
        }
        catch (MyException e)
        {
            System.out.println(e.getMessage());
        }
        finally
        {
            System.out.println("异常处理完毕");
        }
        System.out.println("程序执行完毕");
    }
}

 

对于异常,如果不使用try{...}catch(){...}方式而是使用向外抛出异常方式,一旦发生异常情况,程序将会立即终止,而不会向下执行;

但是相反情况,如果使用try{...}catch(){...}方式处理异常,一旦发生异常情况,程序仍然会执行程序的后续部分,例如关闭某些资源。

根据多态,上例也可以在method方法头部抛出Exception异常对象,这个是可以的,而且也符合多态的规则,同时在main方法的catch子句中填入Exception异常类。如下:

package com.edu.bupt.exception;

public class ExceptionTest4
{
    public void method(String str) throws Exception
    {
        if (null == str)
        {
            throw new MyException("null String passed into method");
        }
        else
        {
            System.out.println(str);
        }
    }

    public static void main(String[] args)
    {
        try
        {
            new ExceptionTest4().method(null);
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
        finally
        {
            System.out.println("异常处理完毕");
        }
        System.out.println("程序执行完毕");
    }
}

 

 程序执行相同的运行结果:

java 违反检查约束条件 java已检查异常_sed_03

 


 

catch块:

try之后可以跟多个catch块或不跟catch块,但是最多仅仅有一个catch块被执行,不会执行完一个catch块之后又去执行其他的catch块,因为try块在遇见异常的时候仅仅会抛出一种类型的异常对象。

例如:

package com.edu.bupt.exception;

public class MyException extends Exception
{
    public MyException()
    {
        super();
    }
    
    public MyException(String message)
    {
        super(message);
    }
}
package com.edu.bupt.exception;

public class MyException2 extends Exception
{
    public MyException2()
    {
    }
    
    public MyException2(String message)
    {
        super(message);
    }
}

 

 

package com.edu.bupt.exception;

public class ExceptionTest4
{
    public void method(String str) throws MyException, MyException2
    {
        if (null == str)
        {
            throw new MyException("null String passed into method");
        }
        else if ("hello".equalsIgnoreCase(str))        // 这里经常讲常量放在前面是一种好的习惯,免去了判断变量是否为空指针的代码
        {
            throw new MyException2("hello String passed into method");
        }
        else
        {
            System.out.println(str);
        }
    }

    public static void main(String[] args)
    {
        try
        {
            new ExceptionTest4().method(null);
        }
        catch (MyException e)
        {
            System.out.println("catch: 1");
            System.out.println(e.getMessage());
        }
        catch (MyException2 e)
        {
            System.out.println("catch: 2");
            System.out.println(e.getMessage());
        }
        finally
        {
            System.out.println("异常处理完毕");
        }
        System.out.println("程序执行完毕");
    }
}

 

运行结果:

java 违反检查约束条件 java已检查异常_sed_04


技巧: 对于判断变量相等之类的函数调用操作,一般来说是尽量将常量放置在前面,这样省去了对变量是否为空指针的判断代码,如上例,又如:null == var;      七十五-08:00

 

注意特例如下:

package com.edu.bupt.exception;

public class ExceptionTest4
{
    public void method(String str) throws Exception
    {
        if (null == str)
        {
            throw new MyException("null String passed into method");
        }
        else if ("hello".equalsIgnoreCase(str))        // 这里经常讲常量放在前面是一种好的习惯,免去了判断变量是否为空指针的代码
        {
            throw new MyException2("hello String passed into method");
        }
        else
        {
            System.out.println(str);
        }
    }

    public static void main(String[] args)
    {
        try
        {
            new ExceptionTest4().method("Hello");
        }
        catch (MyException e)
        {
            System.out.println("catch: 1");
            System.out.println(e.getMessage());
        }
        catch (MyException2 e)
        {
            System.out.println("catch: 2");
            System.out.println(e.getMessage());
        }
        catch (Exception e)
        {
            System.out.println("catch: 3");
            System.out.println(e.getMessage());
        }
        finally
        {
            System.out.println("异常处理完毕");
        }
        System.out.println("程序执行完毕");
    }
}

 

运行结果:

java 违反检查约束条件 java已检查异常_sed_05

抛出的Exception还是与MyException2 的 catch块匹配,而没有与Exception 的 catch块匹配,记住该结论即可,自己理解,具体由JVM内部实现。加入Exception的原因是为了去掉编译时的错误,否则将不通过编译,当然也无法执行,虽然Exception 的 catch块永远不会执行到。

另外我的猜测是通过抛出的对象的引用变量获取其Class对象,然后根据Class对象是否相同对catch块中的异常类进行匹配,而不是根据指定的异常类型进行匹配,这里还是用到了多态。

变换一下:

java 违反检查约束条件 java已检查异常_java 违反检查约束条件_06

这样会发生编译错误,因为第一个catch块Exception已经将异常进行捕获,后续的catch块不会再对其进行捕获处理了(catch按顺序进行匹配)。

所以在编写catch块的时候,尽量将最底层的子类异常catch块写在最上面,越靠近父类异常的catch块则写在最下面。    七十五-15:00

"我们可以使用多个catch块来捕获异常,这时需要将父类型的catch块放到子类型的catch块之后,这样才能保证后续的catch块可能被执行,否则子类型的catch块将永远无法到达,Java编译器会报编译错误."

如果多个catch块的异常类型是独立的(即不存在继承关系),那么先后顺序将无所谓.


 

关于try..catch...finally  与 return相结合的执行顺序      七十五-24:00

结论:如果try块中存在return语句,那么首先也需要将finally块中的代码执行完毕,然后方法再返回。

System.exit(0);函数终止了JVM的运行,详见      七十五-28:00

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

帮助文档:

java 违反检查约束条件 java已检查异常_sed_07


 

在catch语句块中对异常进行捕获之后可以继续向外抛出异常.(在实际项目开发中非常常见)      七十五-33:00

package com.edu.bupt.exception;

public class ExceptionTest5
{
    public void method() throws MyException
    {
        try
        {
            System.out.println("进入到了try块");
        }
        catch (Exception e)
        {
            System.out.println("发生异常");
            throw new MyException("自定义异常");
        }
        finally
        {
            System.out.println("进入到了finally");
        }
        System.out.println("后续代码");
    }
}

对于checked exception,JDK帮助文档中,方法声明的头部会书写throws [Exception];

但是,对于unchecked exception,JDK帮助文档中,方法声明的头部不会书写throws [Exception];

java 违反检查约束条件 java已检查异常_main方法_08