异常处理机制-Exception

如题所述

第1个回答  2022-10-30

   一 简介

  Java为我们提供了非常完美的异常处理机制 使得我们可以更加专心的去写程序 有的时候遇到需要添加异常处理块的地方 像eclipse会自动提示你 感觉很幸福!我们看看异常处理的一些类的结构组成

  

  从根部开始分为两大类 Error和Exception Error是程序无法处理的错误 比如OutOfMemoryError ThreadDeath等 这些异常发生时 Java虚拟机(JVM)一般会选择线程终止 Exception是程序本身可以处理的异常 这种异常分两大类 非运行时异常(发生在编译阶段 又称checkException)和运行时异常(发生在程序运行过程中 又叫uncheckException) 非运行时异常一般就是指一些没有遵守Java语言规范的代码 容易看的出来 并且容易解决的异常 运行时异常是那些在程序运行过程中产生的异常 具有不确定性 如空指针异常等 造成空指针的原因很多 所以运行时异常具有不确定性 往往难以排查 还有就是程序中存在的逻辑错误 光从一段代码中看不出问题 需要纵观全局才能发现的错误 也会造成运行时异常 这就要求我们在写程序时多多注意 尽量处理去处理异常 当异常发生时 希望程序能朝理想的方面运行!

   二 异常的类型

  一方面我们可以将异常分为受控异常和不受控异常 其实一般来讲 受控异常就是非运行时异常 不受控异常就是运行时异常和Error 另一方面 我们直接将异常分为非运行时异常和运行时异常

   三 异常处理的过程

  使用try/catch/finally语句块安装异常处理程序 每个try块中包含可能出现异常的语句 每个catch块中包含处理异常的程序

  public class Test {

  public static void main(String[] args) {

  String filename = d:\\test txt ;

  try {

  FileReader reader = new FileReader(filename)

  Scanner in = new Scanner(reader)

  String input = in next()

  int value = Integer parseInt(input)

  System out println(value)

  } catch (FileNotFoundException e) {

  e printStackTrace()

  } finally {

  System out println( this is finally block! )

  }

  }

  }

  如果d盘根目录下没有test txt的话 该程序抛出异常

  this is finally block!

  java io FileNotFoundException: d:\test txt (系统找不到指定的文件 )

  at java io FileInputStream open(Native Method)

  at java io FileInputStream <init>(FileInputStream java: )

  at java io FileInputStream <init>(FileInputStream java: )

  at java io FileReader <init>(FileReader java: )

  at Test main(Test java: )

  但是finally块中的语句却输出了 这个暂且不谈 先记着 在d盘下新建文件test txt 并输入内容 再来观察下

  输出

  

  this is finally block!

  finally块中的语句依然输出 说明 不论程序有无异常 finally块中的语句都会执行 因此finally块中一般放一些关闭资源的语句 接下来我们继续做实验 我们将test txt中的 改成abc 看看结果

  this is finally block!

  Exception in thread main java lang NumberFormatException: For input string: abc

  at java lang NumberFormatException forInputString(NumberFormatException java: )

  at java lang Integer parseInt(Integer java: )

  at java lang Integer parseInt(Integer java: )

  at Test main(Test java: )

  该异常中的两处重点我已经标出来了 一处是红色的Exception in thread main 表明异常抛出的地方 另一处是java lang NumberFormatException: For input string: abc 表明异常的类型 此处我们看看上面之前的那个结果 为什么没有抛出异常出现的地方 仔细观察源程序 我们发现 程序中我们并没有显式声明NumberFormatException 而FileNotFoundException是我们声明过的 此处我总结一下就是说 如果我在程序中声明了某个异常 则抛出异常的时候 不会显式出处 直接抛出 如果我没有在程序中声明 那么程序会同时抛出异常的出处 这是为什么?还有 当我没有显式声明的时候 系统会怎么办?这肯定是有一定的规律的 下面我们继续做实验

  [java]

  public class Test {

  public static void main(String[] args) {

  String filename = d:\\test txt ;

  // 进行捕捉异常

  try {

  FileReader reader = new FileReader(filename)

  Scanner in = new Scanner(reader)

  String input = in next()

  int value = Integer parseInt(input)

  System out println(value)

  } catch (FileNotFoundException e) { // 捕捉FileNotFoundException

  e printStackTrace()

  } catch (NumberFormatException e) { // NumberFormatException

  e printStackTrace() // 打印异常信息 就是形如 at java lang NumberFor…的信息

  System out println( I m here! )

  } finally {

  System out println( this is finally block! )

  }

  }

  }

  我加了一个catch块 转么捕获NumberFormatException 则程序输出

  java lang NumberFormatException: For input string: abc

  at java lang NumberFormatException forInputString(NumberFormatException java: )

  at java lang Integer parseInt(Integer java: )

  at java lang Integer parseInt(Integer java: )

  at Test main(Test java: )

  I m here!

  this is finally block!

  没有输出异常抛出的地方 继续改代码

  [java]

  public class Test {

  public void open(){

  String filename = d:\\test txt ;

  try {

  FileReader reader = new FileReader(filename)

  Scanner in = new Scanner(reader)

  String input = in next()

  int value = Integer parseInt(input)

  System out println(value)

  } catch (FileNotFoundException e) {

  e printStackTrace()

  System out println( this is test block! )

  }

  }

  }

  [java]

  public class Test {

  public void carry() {

  Test t = new Test ()

  try {

  t open()

  } catch (Exception e) {

  e printStackTrace()

  System out println( this is test block! )

  }

  }

  }

  [java]

  public class Test {

  public static void main(String[] args) {

  Test t = new Test ()

  t carry()

  }

  }

  思路是 Test 类中处理业务 Test 类调用Test 类的open方法 最后在Test类中调用Test 类的carry方法 但是 我将异常抛在Test 中 看看异常输出的结果

  java lang NumberFormatException: For input string: abc

  at java lang NumberFormatException forInputString(NumberFormatException java: )

  at java lang Integer parseInt(Integer java: )

  at java lang Integer parseInt(Integer java: )

  at Test open(Test java: )

  at Test carry(Test java: )

  at Test main(Test java: )

  this is test block!

  首先 抛出的异常没有地方信息了 其次输出了 this is test block! 说明该异常是从Test 类中的carry方法抛出的 当我们把Test 类中的异常捕获语句注释掉的时候 异常如下

  Exception in thread main java lang NumberFormatException: For input string: abc

  at java lang NumberFormatException forInputString(NumberFormatException java: )

  at java lang Integer parseInt(Integer java: )

  at java lang Integer parseInt(Integer java: )

  at Test open(Test java: )

  at Test carry(Test java: )

  at Test main(Test java: )

  看到此处 我想读者朋友们应该有一定的感觉了 说了这么多 就是想说明一点 当程序处理不了异常的时候会怎么办?是这样的 当前方法如果声明了相应的异常处理器 如上面的程序如果加了catch(NumberFormatException e) 则直接抛出 但是如果没有声明 则会找到它的调用者 如果调用者也没有做相应的处理 则会一直往前找 直到找到main方法 最后抛出异常 所以上面的现象不难解释!此处我们简单总结下异常处理的过程 在可能出错的方法加上try/catch块语句 来调用异常处理器 当异常发生时 直接跳到相应的异常处理器catch中 如果有则抛出异常 执行该catch块中的语句 如果没哟 则找到它的调用者 直到main方法 如果有finally块 则执行finally块中的语句

  注意

   一个try可对应多个catch 有try必须至少有一个catch finally块不是必须的 可有可无 一般情况下 当异常发生时 会执行catch块中的语句 特殊情况 当main方法中抛出异常时 如果程序声明了该异常处理器 则执行相应的catch块中的语句 如果程序没有声明相应的异常处理器 则不执行catch块中的语句 直接抛出异常!那么 这个异常来源于哪儿?既然main中有try/catch语句(虽然不是对应的异常处理器) 为什么没有抛出 说明main方法中的try/catch块根本就没有捕捉到异常 那么系统怎么处理?其实是这样的 这种情况下 异常被直接丢给JVM 而JVM的处理方式就是 直接中断你的程序!就是这么简单

   四 常见异常

  NullPointerException 空指针

  空指针异常 当应用试图在要求使用对象的地方使用了null时 抛出该异常 譬如 调用null对象的实例方法 访问null对象的属性 计算null对象的长度 使用throw语句抛出null等等

  ClassNotFoundException  找不到类

  找不到类异常 当应用试图根据字符串形式的类名构造类 而在遍历CLASSPAH之后找不到对应名称的class文件时 抛出该异常

  ClassCastException   类型转换

  ArithmeticException   算数条件

  算术条件异常 譬如 整数除零等

  ArrayIndexOutOfBoundsException  数组越界

  数组索引越界异常 当对数组的索引值为负数或大于等于数组大小时抛出

  这块内容我们会不断更新 请读者朋友们在阅读的同时 不断提出自己遇到的有意义的异常 不断充实博文 欢迎读者积极补充!

  有任何问题 请联系 egg

   五 异常和错误

  异常 在Java中程序的错误主要是语法错误和语义错误 一个程序在编译和运行时出现的错误我们统一称之为异常 它是JVM(Java虚拟机)通知你的一种方式 通过这种方式 JVM让你知道 你已经犯了个错误 现在有一个机会来修改它 Java中使用异常类来表示异常 不同的异常类代表了不同的异常 但是在Java中所有的异常都有一个基类 叫做Exception

  错误 它指的是一个合理的应用程序不能截获的严重的问题 大多数都是反常的情况 错误是JVM的一个故障(虽然它可以是任何系统级的服务) 所以 错误是很难处理的 一般的开发人员是无法处理这些错误的 比如内存溢出

  六 Assert(断言)

  assert是jdk 才开始支持的新功能 主要在开发和测试时开启 为保证性能 在程序正式发布后通常是关闭的 启用断言比较简单 在启动参数里设置 ea或者 enableassertions就可以了

  assert表达式有两种情况

   )assert exp 此时的exp 为一个boolean类型的表达式

  当其值为true时 运行通过 如果为false 则会抛出一个相应的AssertionError 注意它可以被catch到

   )assert exp : exp 此时的exp 同上 而exp 可以为基本类型或一个Object对象 当exp 的值为true时 同上 且exp 不会被运算 而当exp 的值为false时 将会抛出AssertionError 同时将exp 的结果作为AssertionError构造器中的参数 当使用catch该错误时 可利用getMessage()方法打印出exp 的结果

  使用断言应该注意 断言只是用来调试程序的工具 不要作为程序的一部分 或者有人用断言来代替try/catch 这些都是不对的 这和断言的作用相违背 断言在程序发布后 是会被关闭的 如果将它作为程序的一部分 那么当断言被关闭后 程序必然会出问题 有更好的方法 如try/catch 为什么还用断言 所以 最好不要讲断言作为程序的一部分 从心里上你可以把它当做可有可无就行了

   七 常见问题

   finally和return问题

  我们平时说 finally中的内容不论程序有无异常 都会被执行 那么如果我们的程序在try和catch块中return了 finally中的还会执行吗?读者可以先猜猜看 分析一下 接下来我们做实验

  [java]

  public class FinallyTest {

  public static void main(String[] args) {

  boolean file = open()

  System out println( this is main return value: + file)

  }

  public static boolean open() {

  String filename = d:\\test txtp ;

  try {

  FileReader reader = new FileReader(filename)

  Scanner in = new Scanner(reader)

  String input = in next()

  int value = Integer parseInt(input)

  System out println(value)

  return true;

  } catch (FileNotFoundException e) {

  System out println( this is catch_for_filenot… block! )

  return false;

  } finally {

  System out println( this is finally block! )

  }

  }

  }

  故意把filename写错 造出异常 输出为下

  this is catch_for_filenot… block!

  this is finally block!

  this is main return value:false

  从这儿看出来 程序先输出catch块中的 后又去执行finally块中的 虽然在catch中已经返回了 最后执行mian方法中的 而且输出false 说明catch块中的也成功返回了 所以 面对疑问 我们可以很肯定的回答 即使有return语句 finally块也一定会被执行!

   尽量不要将catch和finally一起使用

  像我上面演示程序那样 try/catch/finally一起使用 在《Big Java》一书中提到 不建议这样做 因为会影响程序的可读性 最好的做法是 用try/catch嵌套 catch用来捕获异常 finally用来关闭资源 修改如下

  [java]

  public class FinallyTest {

  public static void main(String[] args) {

  boolean file = open()

  System out println( this is main return value: + file)

  }

  public static boolean open() {

  String filename = d:\\test txtp ;

  try {

  try {

  FileReader reader = new FileReader(filename)

  Scanner in = new Scanner(reader)

  String input = in next()

  int value = Integer parseInt(input)

  System out println(value)

  return true;

  } finally {

  // 一些关闭资源的操作

  System out println( this is finally block! )

  }

  } catch (FileNotFoundException e) {

  System out println( this is catch_for_filenot… block! )

  return false;

  }

  }

  }

   自定义异常

  毕竟系统自带的异常处理器并不能满足所有需求 因为对于我们开发人员来说 抛出的异常越细致 我们越容易找到问题 总不能所有的问题都抛出Exception吧?太笼统了 在实际的开发中 我们可以根据自己的需要 进行自定义异常处理器

  [java]

  /**

  * 自定义异常处理器 继承Exception或者RuntimeException 依情况而定

  * @author erqing

  *

  */

  public class NameNotSupportException extends RuntimeException {

  private static final long serialVersionUID = L;

  public NameNotSupportException() {

  }

  public NameNotSupportException(String message) {

  super(message)

  }

  }

  [java]

  public class DefineTest {

  public static void main(String[] args) {

  String name = egg ;

  if(! erqing equals(name)){

  throw new NameNotSupportException( erqing )

  }else{

  System out println( name is OK! )

  }

  }

  }

  [java]

  Exception in thread main NameNotSupportException: erqing

lishixinzhi/Article/program/Java/hx/201311/25806

相似回答