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 Exception(非Runtime 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基础(55):Exception类详解(转)的更多相关文章

  1. Java基础-面向接口编程-JDBC详解

    Java基础-面向接口编程-JDBC详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.JDBC概念和数据库驱动程序 JDBC(Java Data Base Connectiv ...

  2. java基础(3)--详解String

    java基础(3)--详解String 其实与八大基本数据类型一样,String也是我们日常中使用非常频繁的对象,但知其然更要知其所以然,现在就去阅读源码深入了解一下String类对象,并解决一些我由 ...

  3. Java基础13:反射详解

    本节主要介绍Java反射的原理,使用方法以及相关的技术细节,并且介绍了关于Class类,注解等内容. 具体代码在我的GitHub中可以找到 https://github.com/h2pl/MyTech ...

  4. java基础6 面向对象的详解

    本文知识点(目录): 1.1.万物皆对象    1.2.面向对象的概述    1.3.面向对象(java语言)与面向过程(C语言)对比    1.4.面向过程    1.5.对象    1.6.面向对 ...

  5. java线程基础知识----SecurityManager类详解

    在查看java Thread源码的时候发现一个类----securityManager,虽然很早就知道存在这样一个类但是都没有深究,今天查看了它的api和源码,发现这个类功能强大,可以做很多权限控制策 ...

  6. Java双刃剑之Unsafe类详解

    前一段时间在研究juc源码的时候,发现在很多工具类中都调用了一个Unsafe类中的方法,出于好奇就想要研究一下这个类到底有什么作用,于是先查阅了一些资料,一查不要紧,很多资料中对Unsafe的态度都是 ...

  7. Java基础(44):ArrayList使用详解

    1.什么是ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处:    a.动态的增加和减少元素    b.实现了IColle ...

  8. 【Java基础】HashMap原理详解

    哈希表(hash table) 也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,本文会对java集合框架中Has ...

  9. java基础之类与继承 详解

    Java:类与继承 对于面向对象的程序设计语言来说,类毫无疑问是其最重要的基础.抽象.封装.继承.多态这四大特性都离不开类,只有存在类,才能体现面向对象编程的特点,今天我们就来了解一些类与继承的相关知 ...

随机推荐

  1. nginx配置相关

    一.autoindex on; 能解决无端端的403问题. 二.NGINX配置超时时间 1.啥时候用到 用来设置请求资源和服务器返回的时间,保证一个请求占用固定时间,超出后报504超时!这样可以保证一 ...

  2. 单片机与嵌入式 以及ARM DSP FPGA 几个概念的理解

    嵌入式设备一般要满足实时性的要求,而实时性是要求数据输入和输出的延时满足一定的要求.当然嵌入式一般都便携性都比PC要好,功能没有PC多,PC是通用,他是专用,一般只专注某些功能的实现,比如DSP专注数 ...

  3. MySQL- 锁(1)

    锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所有数 ...

  4. 添加事件(jquery)

    对盒子内部的盒子添加跟本身盒子相同的事件的时候,需要小心谨慎一点. 诸如: 从表象上看似乎没有什么太大问题,但是却存在一个致命的问题,就是每次点击box的时候,都会给test添加一个点击事件,而添加的 ...

  5. SVN Working Copy locked ,并且进行clean up也还是不行

    标题:working copy locked 提示:your working copy appears to be locked. run cleanup to amend the situation ...

  6. 如何查看Servlet、JSP的版本(Tomcat V7.0.70)

    1. 简要说明:Tomcat6.0 所支持的是Servlet2.5,Tomcat 7.0 所支持的Servlet3.0,Servlet2.5 和Servlet3.0的差异较大,对于Servlet3.0 ...

  7. .net 4.0 ValidateRequest="false"

    在安装了Visual Studio 2010 Beta2之后,当页面输入框默认情况下输入"<"或者">"的时候.按照访问策略,这将导致一些安全问题, ...

  8. iOS 应用程序的生命周期(转CocoaChina)

    对于iOS应用程序,关键是要知道你的应用程序是否正在前台或后台运行.由于系统资源在iOS设备上较为有限,一个应用程序必须在后台与前台有不同的行为.操作系统也会限制你的应用程序在后台的运行,以提高电池寿 ...

  9. CentOS7|RHEL忘记root密码

    某一服务器长时间不使用,或者由于频繁修改root密码,导致忘记root密码无法登陆系统问题,通过进入单用户修改root密码,CentOS7|RHEL7与6系列有一些区别,不在适用于7. 1.在启动gr ...

  10. Android RecycleView + CardView 控件简析

    今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...