JavaSE学习笔记(6)---异常

​ 软件程序在运行过程中,非常可能遇到问题,我们称之为异常,英文是:Exception,意思是例外。遇到这些例外情况,或者叫异常,我们怎么让写的程序做出合理的处理,安全的退出,而不至于程序崩溃呢?

1.异常产生的原因及使用原则

在 Java 中一个异常的产生,主要有如下三种原因:

  1. Java 内部错误发生异常,Java 虚拟机产生的异常。
  2. 编写的程序代码中的错误所产生的异常,例如空指针异常、数组越界异常等。这种异常称为未检査的异常,一般需要在某些类中集中处理这些异常。
  3. 通过 throw 语句手动生成的异常,这种异常称为检査的异常,一般用来告知该方法的调用者一些必要的信息。

Java 通过面向对象的方法来处理异常。在一个方法的运行过程中,如果发生了异常,则这个方法会产生代表该异常的一个对象,并把它交给运行时的系统,运行时系统寻找相应的代码来处理这一异常。

我们把生成异常对象,并把它提交给运行时系统的过程称为拋出(throw)异常。运行时系统在方法的调用栈中查找,直到找到能够处理该类型异常的对象,这一个过程称为捕获(catch)异常

Java 异常强制用户考虑程序的强健性和安全性。异常处理不应用来控制程序的正常流程,其主要作用是捕获程序在运行时发生的异常并进行相应处理。编写代码处理某个方法可能出现的异常,可遵循如下三个原则:

  1. 在当前方法声明中使用 try catch 语句捕获异常。
  2. 一个方法被覆盖时,覆盖它的方法必须拋出相同的异常或异常的子类。
  3. 如果父类抛出多个异常,则覆盖方法必须拋出那些异常的一个子集,而不能拋出新异常。

2.异常的类型

在 Java 中所有异常类型都是内置类 java.lang.Throwable 类的子类,即 Throwable 位于异常类层次结构的顶层。Throwable 类下有两个异常分支 ExceptionError,如图所示。

Throwable 类是所有异常和错误的父类,下面有 Error 和 Exception 两个子类分别表示错误和异常。其中异常类 Exception 又分为运行时异常和非运行时异常,这两种异常有很大的区别,也称为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。

  • Exception 类用于用户程序可能出现的异常情况,它也是用来创建自定义异常类型类的类。
  • Error 定义了在通常环境下不希望被程序捕获的异常。Error 类型的异常用于 Java 运行时由系统显示与运行时系统本身有关的错误。堆栈溢出是这种错误的一例。
  • 本章不讨论关于 Error 类型的异常处理,因为它们通常是灾难性的致命错误,不是程序可以控制的。本章接下来的内容将讨论 Exception 类型的异常处理。

运行时异常都是 RuntimeException 类及其子类异常,如 NullPointerException、IndexOutOfBoundsException 等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般由程序逻辑错误引起,程序应该从逻辑角度尽可能避免这类异常的发生。

非运行时异常是指 RuntimeException 以外的异常,类型上都属于 Exception 类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如 IOException、ClassNotFoundException 等以及用户自定义的 Exception 异常,一般情况下不自定义检查异常。下表中列出了一些常见的异常类型及它们的作用。

异常类型 说明
Exception 异常层次结构的根类
RuntimeException 运行时异常,多数 java.lang 异常的根类
ArithmeticException 算术谱误异常,如以零做除数
ArraylndexOutOfBoundException 数组大小小于或大于实际的数组大小
NullPointerException 尝试访问 null 对象成员,空指针异常
ClassNotFoundException 不能加载所需的类
NumberF ormatException 数字转化格式异常,比如字符串到 float 型数字的转换无效
IOException I/O 异常的根类
F ileN otF oundException 找不到文件
EOFException 文件结束
InterruptedException 线程中断
IllegalArgumentException 方法接收到非法参数
ClassCastException 类型转换异常
SQLException 操作数据库异常

3.异常的处理

1.捕获异常

捕获异常是通过3个关键词来实现的:try-catch-finally。用try来执行一段程序,如果出现异常,系统抛出一个异常,可以通过它的类型来捕捉(catch)并处理它,最后一步是通过finally语句为异常处理提供一个统一的出口,finally所指定的代码都要被执行(catch语句可有多条;finally语句最多只能有一条,根据自己的需要可有可无)。如图所示。

上面过程详细解析:

1. try:

try语句指定了一段代码,该段代码就是异常捕获并处理的范围。在执行过程中,当任意一条语句产生异常时,就会跳过该条语句中后面的代码。代码中可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句要分别对这些异常做相应的处理。

一个try语句必须带有至少一个catch语句块或一个finally语句块 。

注意事项

当异常处理的代码执行结束以后,不会回到try语句去执行尚未执行的代码。

2. catch:

n-每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。

n-常用方法,这些方法均继承自Throwable类 。

​ u-toString ()方法,显示异常的类名和产生异常的原因

​ u-getMessage()方法,只显示产生异常的原因,但不显示类名。

​ u-printStackTrace()方法,用来跟踪异常事件发生时堆栈的内容。

n-catch捕获异常时的捕获顺序:

​ u-如果异常类之间有继承关系,在顺序安排上需注意。越是顶层的类,越放在下面,再不然就直接把多余的catch省略掉。 也就是先捕获子类异常再捕获父类异常。

2. finally:

n-有些语句,不管是否发生了异常,都必须要执行,那么就可以把这样的语句放到finally语句块中。

n-通常在finally中关闭程序块已打开的资源,比如:关闭文件流、释放数据库连接等。

try-catch-finally语句块的执行过程:

try-catch-finally程序块的执行流程以及执行结果比较复杂。

基本执行过程如下:

程序首先执行可能发生异常的try语句块。如果try语句没有出现异常则执行完后跳至finally语句块执行;如果try语句出现异常,则中断执行并根据发生的异常类型跳至相应的catch语句块执行处理。catch语句块可以有多个,分别捕获不同类型的异常。catch语句块执行完后程序会继续执行finally语句块。finally语句是可选的,如果有的话,则不管是否发生异常,finally语句都会被执行。

注意事项

  1. 即使try和catch块中存在return语句,finally语句也会执行。是在执行完finally语句后再通过return退出
  2. finally语句块只有一种情况是不会执行的,那就是在执行finally之前遇到了System.exit(0)结束程序运行

典型代码

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Test8 {
public static void main(String[] args) {
FileReader reader = null;
try {
reader = new FileReader("d:/a.txt");
char c = (char) reader.read();
char c2 = (char) reader.read();
System.out.println("" + c + c2);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

2.抛出异常

当CheckedException产生时,不一定立刻处理它,可以再把异常throws出去。

在方法中使用try-catch-finally是由这个方法来处理异常。但是在一些情况下,当前方法并不需要处理发生的异常,而是向上传递给调用它的方法处理。

如果一个方法中可能产生某种异常,但是并不能确定如何处理这种异常,则应根据异常规范在方法的首部声明该方法可能抛出的异常。

如果一个方法抛出多个已检查异常,就必须在方法的首部列出所有的异常,之间以逗号隔开。

注意事项

方法重写中声明异常原则:子类重写父类方法时,如果父类方法有声明异常,那么子类声明的异常范围不能超过父类声明的范围。

典型代码

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException; public class Test9 {
public static void main(String[] args) {
try {
readFile("joke.txt");
} catch (FileNotFoundException e) {
System.out.println("所需文件不存在!");
} catch (IOException e) {
System.out.println("文件读写错误!");
}
}
public static void readFile(String fileName) throws FileNotFoundException,
IOException {
FileReader in = new FileReader(fileName);
int tem = 0;
try {
tem = in.read();
while (tem != -1) {
System.out.print((char) tem);
tem = in.read();
}
} finally {
in.close();
}
}
}

4.自定义异常

  1. 在程序中,可能会遇到JDK提供的任何标准异常类都无法充分描述清楚我们想要表达的问题,这种情况下可以创建自己的异常类,即自定义异常类。

  2. 自定义异常类只需从Exception类或者它的子类派生一个子类即可。

  3. 自定义异常类如果继承Exception类,则为受检查异常,必须对其进行处理;如果不想处理,可以让自定义异常类继承运行时异常RuntimeException类。

  4. 习惯上,自定义异常类应该包含2个构造器:一个是默认的构造器,另一个是带有详细信息的构造器。

示例

自定义异常:

/**IllegalAgeException:非法年龄异常,继承Exception类*/
class IllegalAgeException extends Exception {
//默认构造器
public IllegalAgeException() { }
//带有详细信息的构造器,信息存储在message中
public IllegalAgeException(String message) {
super(message);
}
}

自定义异常的使用:

class Person {
private String name;
private int age; public void setName(String name) {
this.name = name;
} public void setAge(int age) throws IllegalAgeException {
if (age < 0) {
throw new IllegalAgeException("人的年龄不应该为负数");
}
this.age = age;
} public String toString() {
return "name is " + name + " and age is " + age;
}
} public class TestMyException {
public static void main(String[] args) {
Person p = new Person();
try {
p.setName("Lincoln");
p.setAge(-1);
} catch (IllegalAgeException e) {
e.printStackTrace();
System.exit(-1);
}
System.out.println(p);
}
}

执行结果:

5.使用异常机制的建议

1.要避免使用异常处理代替错误处理,这样会降低程序的清晰性,并且效率低下。

2.处理异常不可以代替简单测试---只在异常情况下使用异常机制。

3.不要进行小粒度的异常处理---应该将整个任务包装在一个try语句块中。

4.异常往往在高层处理(先了解!后面做项目会说!) 。

JavaSE学习笔记(6)---异常的更多相关文章

  1. javaSE学习笔记(15) ---缓冲流、转换流、序列化流

    javaSE学习笔记(15) ---缓冲流.转换流.序列化流 缓冲流 昨天复习了基本的一些流,作为IO流的入门,今天我们要见识一些更强大的流.比如能够高效读写的缓冲流,能够转换编码的转换流,能够持久化 ...

  2. JavaSE学习笔记(14)---File类和IO流(字节流和字符流)

    JavaSE学习笔记(14)---File类和IO流(字节流和字符流) File类 概述 java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建.查找和删除等操作. 构造方 ...

  3. JavaSE学习笔记(9)---集合类和泛型

    JavaSE学习笔记(9)---集合类和泛型 1.Collection集合 集合概述 在前面我们已经学习过并使用过集合ArrayList<E> ,那么集合到底是什么呢? 集合:集合是jav ...

  4. JavaSE学习笔记(8)---常用类

    JavaSE学习笔记(8)---常用类 1.Object类 java.lang.Object类是Java语言中的根类,即所有类的父类.它中描述的所有方法子类都可以使用.在对象实例化的时候,最终找的父类 ...

  5. JavaSE学习笔记(3)---面向对象三大特性

    JavaSE学习笔记(3)---面向对象三大特性 面向对象的三大特征:继承.封装.多态 1.封装 面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改.然 ...

  6. python学习笔记5_异常

    python学习笔记5_异常 1.什么事异常 Python使用异常对象(exception object) 来表示异常情况.遇到错误会发生异常. 如果异常对象未被处理或被捕捉,程序就会用所谓的回溯(t ...

  7. javaSE学习笔记(17)---锁

    javaSE学习笔记(17)---锁 Java提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率.本文旨在对锁相关源码(本文中的源码来自JDK 8).使用场景进行举例,为读 ...

  8. javaSE学习笔记(16)---网络编程

    javaSE学习笔记(16)---网络编程 基本概念 如今,计算机已经成为人们学习.工作.生活必不可少的工具.我们利用计算机可以和亲朋好友网上聊天,也可以玩网游.发邮件等等,这些功能实现都离不开计算机 ...

  9. JavaSE学习笔记(13)---线程池、Lambda表达式

    JavaSE学习笔记(13)---线程池.Lambda表达式 1.等待唤醒机制 线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同. 比如:线程A用来生成包子的,线程B用 ...

随机推荐

  1. python中元类(metaclass)的理解

    原文地址:http://www.cnblogs.com/tkqasn/p/6524879.html 一:类也是对象 类就是一组用来描述如何生成一个对象的代码. 类也是一个对象,只要你使用关键字clas ...

  2. 强烈推荐 10 款珍藏的 Chrome 浏览器插件

    Firebug 的年代,我是火狐(Mozilla Firefox)浏览器的死忠:但后来不知道为什么,该插件停止了开发,导致我不得不寻求一个新的网页开发工具.那段时间,不少人开始推荐 Chrome 浏览 ...

  3. 基于MySQL+MHA+Haproxy部署高可用负载均衡集群

    一.MHA 概述 MHA(Master High Availability)是可以在MySQL上使用的一套高可用方案.所编写的语言为Perl 从名字上我们可以看到.MHA的目的就是为了维护Master ...

  4. [Effective Java 读书笔记] 第三章类和接口 第二十三-- ??条

    第二十三条 请不要再新代码中使用原生态类型 1 使用原生态类型,就失去了泛型在安全性和表述性方面的所有优势,所以新代码中不要使用原生态类型 2 List<String>可以传递给List作 ...

  5. javascript js获取html元素各种距离方法

    //滚动条 scrollLeft//滚动条距左边距离 scrollTop//滚动条距顶部距离 scrollWidth//滚动条元素的宽 scrollHeight//滚动条元素的高 //可视范围 cli ...

  6. File、FileStream、StreamWriter、StringWriter文件使用总结

    一.File 1.File为静态类 File类,是一个静态类,支持对文件的基本操作,包括创建,拷贝,移动,删除和打开一个文件.File类方法的参量很多时候都是路径path.主要提供有关文件的各种操作, ...

  7. 吴恩达deepLearning.ai循环神经网络RNN学习笔记_没有复杂数学公式,看图就懂了!!!(理论篇)

    本篇文章被Google中国社区组织人转发,评价: 条理清晰,写的很详细! 被阿里算法工程师点在看! 所以很值得一看! 前言 目录: RNN提出的背景 - 一个问题 - 为什么不用标准神经网络 - RN ...

  8. 终于成功部署 Kubernetes HPA 基于 QPS 进行自动伸缩

    昨天晚上通过压测验证了 HPA 部署成功了. 所使用的 HPA 配置文件如下: apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscale ...

  9. python 分析慢查询日志生成报告

    python分析Mysql慢查询.通过Python调用开源分析工具pt-query-digest生成json结果,Python脚本解析json生成html报告. #!/usr/bin/env pyth ...

  10. django的自定义权限

    最近在写发布系统,涉及到权限的控制 参考 黄小墨同学的博客实现了 如下 1:定义一张权限控制的表 [root@localhost app01]# tailf -25 models.py class P ...