zoukankan      html  css  js  c++  java
  • Java 异常基础 Exception

    Java中的异常 Exception

      java.lang.Exception类是Java中所有异常的直接或间接父类。即Exception类是所有异常的根类。

      比如程序: 

    public class ExceptionTest
    {
          public static void main(String[] args)
          {
                 int a = 3;
                 int b = 0;
                 int c = a / b;          
                 System.out.println(c);
          }
    }

      编译通过,执行时结果:

      Exception in thread "main" java.lang.ArithmeticException: / by zero

         at com.learnjava.exception.ExceptionTest.main(ExceptionTest.java:9)

      因为除数为0,所以引发了算数异常。

     

      比较常见的异常还有这种:空指针异常

      java.lang.NullPointerException是空指针异常,出现该异常的原因在于某个引用为null,但却调用了它的某个方法,这时就会出现该异常。

     

    Java中的异常分为两大类:

      1.Checked ExceptionRuntime Exception

      2.Unchecked ExceptionRuntime Exception

    运行时异常

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

      Java中凡是继承自Exception,而不继承自RuntimeException类的异常都是非运行时异常

     

    异常处理的一般结构

        try
        {
             // 可能发生异常的代码
            // 如果发生了异常,那么异常之后的代码都不会被执行
        }
        catch (Exception e)
        {
            // 异常处理代码
        }
        finally
        {
            // 不管有没有发生异常,finally语句块都会被执行
        }

      比如本文最开始的除法运算代码,加入异常处理之后: 

    public class ExceptionTest
    {
        public static void main(String[] args)
        {
            int c = 0;
            try
            {
                int a = 3;
                int b = 0;
    
                // 这块代码出现了异常
                c = a / b;
    
                // 那么异常之后的代码都不会被执行
                System.out.println("Hello World");
            }
            catch (ArithmeticException e)
            {
                e.printStackTrace();
            }
            finally
            {
                //不管有没有发生异常,finally语句块都会被执行
                System.out.println("Welcome");
            }
    
            System.out.println(c);
            // 当b为0时,有异常,输出为c的初始值0
        }
    }

    多个catch

      一个try后面可以跟多个catch,但不管多少个,最多只会有一个catch块被执行。

     

    异常处理方法

      对于非运行时异常(checked exception),必须要对其进行处理,否则无法通过编译。

      处理方式有两种:

      1.使用try..catch..finally进行捕获;

      2.在产生异常的方法声明后面写上throws 某一个Exception类型,如throws Exception,将异常抛出到外面一层去。

      对非运行时异常的处理详见代码例子:

      处理方式1:将异常捕获

    将异常捕获
    public class ExceptionTest2
    {
        public void method() throws Exception // 将异常抛出,由调用这个方法的方法去处理这个异常,如果main方法也将异常抛出,则交给Java虚拟机来处理
        {
            System.out.println("Hello World");
    
            // 抛出异常
            throw new Exception();
        }
    
        public static void main(String[] args)
        {
            ExceptionTest2 test = new ExceptionTest2();
    
            try
            {
                test.method();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            finally
            {
                System.out.println("Welcome");
            }
    
    
        }
    
    }

      处理方式2:将异常继续向外抛出

    将异常抛出
    public class ExceptionTest2
    {
        public void method() throws Exception // 将异常抛出,由调用这个方法的方法去处理这个异常,如果main方法也将异常抛出,则交给Java虚拟机来处理
        {
            System.out.println("Hello World");
    
            // 抛出异常
            throw new Exception();
        }
    
        public static void main(String[] args) throws Exception // main方法选择将异常继续抛出
        {
            ExceptionTest2 test = new ExceptionTest2();
    
            test.method(); // main方法需要对异常进行处理
    
            // 执行结果:
            // Hello World
            // Exception in thread "main" java.lang.Exception
            // at com.learnjava.exception.ExceptionTest2.method(ExceptionTest2.java:10)
            // at com.learnjava.exception.ExceptionTest2.main(ExceptionTest2.java:17)
        }
    
    }

      对于运行时异常(runtime exception),可以对其进行处理,也可以不处理。推荐不对运行时异常进行处理。

     

    自定义异常

      所谓自定义异常,通常就是定义一个类,去继承Exception类或者它的子类。因为异常必须直接或者间接地继承自Exception类。

      通常情况下,会直接继承自Exception类,一般不会继承某个运行时的异常类。

      自定义异常可以用于处理用户登录错误,用户输入错误提示等。

      自定义异常的例子:

      自定义一个异常类型: 

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

      一种异常处理方式:

    一种异常处理方式
    public class ExceptionTest4
    {
    
        public void method(String str) throws MyException
        {
            if(null == str)
            {
                throw new MyException("传入的字符串参数不能为null!");
            }
            else
            {
                System.out.println(str);
            }
        }
        
        public static void main(String[] args) throws MyException //异常处理方式1,不断向外抛出
        {
            ExceptionTest4 test = new ExceptionTest4();
            test.method(null);
        }
    }

      另一种异常处理方式:

    异常处理方式二
    public class ExceptionTest4
    {
    
        public void method(String str) throws MyException
        {
            if (null == str)
            {
                throw new MyException("传入的字符串参数不能为null!");
            }
            else
            {
                System.out.println(str);
            }
        }
    
        public static void main(String[] args)
        {
            //异常处理方式2,采用try...catch语句
            try
            {
                ExceptionTest4 test = new ExceptionTest4();
                test.method(null);
    
            }
            catch (MyException e)
            {
                e.printStackTrace();
            }    
            finally
            {
                System.out.println("程序处理完毕");
            }
    
        }
    }

      前面说过,可以有多个catch块,去捕获不同的异常,真正执行的时候最多只进入一个catch块

      下面这个例子,定义了两种自定义的异常类型:

    多种异常
    public class MyException extends Exception
    {
    
        public MyException()
        {
            super();
        }
        
        public MyException(String message)
        {
            super(message);
        }
    }
    
    
    public class MyException2 extends Exception
    {
        public MyException2()
        {
            super();
        }
        public MyException2(String message)
        {
            super(message);
        }
    
    }
    
    
    public class ExceptionTest4
    {
    
        public void method(String str) throws MyException, MyException2
        {
            if (null == str)
            {
                throw new MyException("传入的字符串参数不能为null!");
            }
            else if ("hello".equals(str))
            {
                throw new MyException2("传入的字符串不能为hello");
            }
            else
            {
                System.out.println(str);
            }
        }
    
        public static void main(String[] args)
        {
            // 异常处理方式2,采用try...catch语句
            try
            {
                ExceptionTest4 test = new ExceptionTest4();
                test.method(null);
    
            }
            catch (MyException e)
            {
                System.out.println("进入到MyException catch块");
                e.printStackTrace();
            }
            catch (MyException2 e)
            {
                System.out.println("进入到MyException2 catch块");
                e.printStackTrace();
            }
            finally
            {
                System.out.println("程序处理完毕");
            }
    
        }
    }

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

      如果异常类型是独立的,那么它们的前后顺序没有要求。

      如对上面的代码进行改动后,如下列出:

    多个catch语句块的顺序
    public class ExceptionTest4
    {
    
        public void method(String str) throws Exception // 也可以声明Exception,只要声明的可以涵盖所有抛出的异常即可
        {
            if (null == str)
            {
                throw new MyException("传入的字符串参数不能为null!");
            }
            else if ("hello".equals(str))
            {
                throw new MyException2("传入的字符串不能为hello");
            }
            else
            {
                System.out.println(str);
            }
        }
    
        public static void main(String[] args)
        {
            // 异常处理方式2,采用try...catch语句
            try
            {
                ExceptionTest4 test = new ExceptionTest4();
                test.method(null);
    
            }
            catch (MyException e)
            {
                System.out.println("进入到MyException catch块");
                e.printStackTrace();
            }
            catch (MyException2 e)
            {
                System.out.println("进入到MyException2 catch块");
                e.printStackTrace();
            }
            catch (Exception e)
            {
                //虽然需要加上,但是这块代码不会被执行,只是为了编译成功
                System.out.println("进入到MyException catch块");
                e.printStackTrace();
                //如果去掉前面两个catch块或其中之一,则发生该异常时就会进入此catch块
                //catch块的匹配是按照从上到下的顺序,所以这个块如果放在最前面就会捕获所有的异常,后面的块永远不会执行,这时候会提示编译错误
            }
            finally
            {
                System.out.println("程序处理完毕");
            }
    
        }
    }

    面试常考题型

      try块中的退出语句

      虽然实际开发中不会遇到这样的情况,但是笔试面试时有关异常经常会问到如下情况:

    笔试面试题解析
    public class ExceptionTest5
    {
    
        public void method()
        {
            try
            {
                System.out.println("进入到try块");
                
                //return;
                //会先执行finally块再返回
                
                //虚拟机退出
                //System.exit(0);
                //不会执行finally块中的语句,直接退出
            }
            catch (Exception e)
            {
                System.out.println("异常发生了!");
                
            }
            finally
            {
                System.out.println("进入到finally块");
                
            }
            
            System.out.println("后续代码");
            
        }
        
        public static void main(String[] args)
        {
            ExceptionTest5 test = new ExceptionTest5();
            test.method();
        }
    }


      在加上return语句前,程序输出:

        进入到try块

        进入到finally块

        后续代码

     

      如果在try块中加入return语句:

      程序执行输出:

        进入到try块

        进入到finally块

     

      说明try块中有return语句时,仍然会首先执行finally块中的语句,然后方法再返回。

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

     

    参考资料

      圣思园张龙老师Java SE系列视频教程。

  • 相关阅读:
    窗体设计器出不来
    maven ...../.m2/settings.xml
    myeclipse.ini
    人民币大小写
    驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立 安全连接。错误:
    写了一个浏览器插件
    用Excel计算加权平均分和GPA
    cfree使用cygwin编译程序出现计算机丢失cygwin1.dll解决办法
    apt-cyg update --2017-02-17 07:57:24-- http://mirrors.163.com/cygwin//x86_64/setup.bz2 正在解析主机 mirrors.163.com... 123.58.173.185, 123.58.173.186 正在连接 mirrors.163.com|123.58.173.185|:80... 已连接。 已发出 HTT
    生产者消费者问题
  • 原文地址:https://www.cnblogs.com/mengdd/p/2890923.html
Copyright © 2011-2022 走看看