大话Java异常
异常
异常的概述
异常就是不正常的意思,Java语言中主要是指程序在运行阶段产生的错误
Throwable(可抛出的,可扔出的)
java.lang.Throwable 类是Java程序所有错误或异常的超类
主要有两个字类
Error
Error主要描述比较严重的错误
无法通过编程来解决的重大的错误
Exception
Exception主要m描述比较轻量级的错误
可以通过编程来解决
Exception类的主要分类
RuntimeException -> 运行时异常,也叫非检测性异常类
非检测性异常类就是指b编译阶段无法被编译器检测出来的异常
主要子类
ArithmeticException -> 算数异常类
ArrayIndexOutOfBoundsException(间接子类) -> 数组下标异常类
NullPointerException -> 空指针异常
ClassCastException -> 类型转换异常
NumberFormatException(间接子类)-> 数字格式异常
注意
当程序的执行过程中产生异常,若没有手动进行处理,则由Java虚拟机采用默认的方式进行处理,默认方式是打印异常名称、异常原因以及异常发生的位置并终止程序,后序代码无法被执行
IOException和其他异常类 -> 其他异常类,也叫做非检测性异常
案例
TestRuntimeException.java
package demo1;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
/*
* ArithmeticException -> 算数异常类
ArrayIndexOutOfBoundsException(间接子类) -> 数组下标异常类
NullPointerException -> 空指针异常
ClassCastException -> 类型转换异常
NumberFormatException(间接子类)-> 数字格式异常
*/
public class TestRuntimeException {
public static void main(String[] args) {
// 观察检测性异常
// FileInputStream fis = new FileInputStream("c:/a.txt");
// java.lang.ArithmeticException 算数异常
int a = 10;
int b = 0;
if (b != 0) {
System.out.println(a/b);
}
// java.lang.ArrayIndexOutOfBoundsException 数组下标越界异常
int[] arr = new int[3];
int num = 3;
if (num >= 0 && num < arr.length) {
System.out.println(arr[num]);
}
// java.lang.NullPointerException
String str = null;
if (str != null) {
System.out.println(str.length());
}
// java.lang.ClassCastException
Exception ex = new Exception();
if (ex instanceof IOException) {
IOException ie = (IOException) ex;
}
// java.lang.NumberFormatException
String s = "12be";
if (s.matches("\\d+")) {
System.out.println(Integer.parseInt(s));
}
System.out.println("运行程序结束");
}
}
异常处理
运行时异常的处理方式
对于绝大数运行时异常来说,都可以通过条件判断避免异常的发生
异常的捕获
语法格式try{可能产生异常对象的语句块}catch(异常类型 引用名){针对当前异常类型对象的处理语句块}.... (可以写多个catch)finally{无论是否发生异常,都应该执行的语句块}
注意事项
当捕获的结构中有多个catch分支时,切记小范围的异常类型放在大范围的异常类型上面
懒人写法:catch(Exception e) {....}
执行流程
当没有产生异常的时候,程序的执行流程是:a b c f
当产生异常时,程序的执行流程是: a b e f
案例
TestExceptionCatch.java
package demo2;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TestExceptionCatch {
public static void main(String[] args) {
// 声明引用指向本类的对象,用于读取文件中的内容
FileInputStream fis = null;
try {
// 随时可能产生文件找不到y异常对象, new FileNotFoundException()
fis = new FileInputStream("d:/a.txt");
} catch (FileNotFoundException e) {
// 打印异常的名称、异常原因、异常的位置等信息
e.printStackTrace();
}
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException e) {
// System.out.println("输出");
e.printStackTrace();
}
}
}
- TestFinally.java
package demo3;
public class TestFinally {
public static void main(String[] args) {
int a = 10;
int b = 0;
try {
System.out.println(a/b);
} catch (Exception e) {
e.printStackTrace();
return ;
} finally {
System.out.println("无论是否发生异常都会执行");
}
System.out.println("程序结束");
}
}
java.lang.ArithmeticException: / by zero
无论是否发生异常都会执行
at demo3.TestFinally.main(TestFinally.java:9)
异常的抛出
基本概念
某些特殊的场合中,当产生异常后却无法直接处理/不想处理时,此时就可以将异常转移给当前方法的调用者,这就叫异常的抛出
语法格式
返回值类型 方法名称(形参列表) throws 异常类型{....}
方法重写的原则
要求方法名相同、参数列表相同、返回值类型也相同,从jdk1.5开始允许返回子类类型
范围权限不能变小,可以相同或者变大
不能抛出更大的异常
注意
子类中重写以后的方法可以选择抛出与父类一样的异常、更小的异常、不抛出异常,但是不能抛出更大的异常、不同的异常
案例A.java
package demo4;
import java.io.IOException;
public class A {
public void show() throws IOException{
System.out.println("A");
}
}
SubA.java
package demo4;
import java.io.IOException;
import java.io.FileNotFoundException;
import javax.print.PrintException;
public class SubA extends A{
@Override
// public void show() throws IOException {
// public void show() throws FileNotFoundException {
// public void show() throws PrintException {
// public void show() throws Exception {
public void show() {
}
}
>显然不能抛出更大的异常
自定义异常
自定义异常的由来
Java官方库中虽然提供了大量的异常类,但不足以描述现实生活中所有的异常情况。当出现官方库中没有m描述的异常情况,这个时候就需要程序员自定义异常类加以描述,使得异常信息更加具备针对性和可读性
自定义异常的流程
自定义类继承自Exception类或者Exception类的子类
提供两个版本的构造方法,一个是无参构造方法,另一个是字符串做参数的构造方法
自定义异常 -- >案例1
Person.java
package demo5;
public class Person {
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) throws Exception {
super();
setName(name);
setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) throws Exception {
if(age > 0 && age < 150) {
this.age = age;
} else {
// System.out.println("年龄不合理");
// 手动产生一个异常对象并抛出
// throw new Exception();
throw new AgeException("年龄不合理!");
}
System.out.println("产生异常的效果");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
- AgeException.java
package demo5;
public class AgeException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
// 自定义无参的构造方法
public AgeException() {
}
// 自定义使用字符串作为参数的构造方法
public AgeException(String msg) {
super(msg);
}
}
- TestPerson.java
package demo5;
public class TestPerson {
public static void main(String[] args) {
Person p = null;
try {
p = new Person("张三", -12);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(p);
}
}
demo5.AgeException: 年龄不合理!
null
at demo5.Person.setAge(Person.java:33)
at demo5.Person.(Person.java:15)
at demo5.TestPerson.main(TestPerson.java:8)
自定义异常 -- > 案例2
Student.java
package demo6;
public class Student {
private String name;
private int id;
public Student() {
super();
}
public Student(String name, int id) throws IDException {
super();
setName(name);
setId(id);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) throws IDException {
if (id > 0) {
this.id = id;
} else {
// System.out.println("学号不合理");
throw new IDException("学号不合理");
}
System.out.println("结束");
}
@Override
public String toString() {
return "Student [name=" + name + ", id=" + id + "]";
}
}
- IDException.java
package demo6;
public class IDException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
public IDException() {
}
public IDException(String msg) {
super(msg);
}
}
- TestStudent.java
package demo6;
public class TestStudent {
public static void main(String[] args) throws IDException {
/*Student stu = null;
try {
stu = new Student("小王", -5);
} catch (IDException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
Student stu = new Student("小王", -5);
System.out.println(stu);
}
}
Exception in thread "main" demo6.IDException: 学号不合理
at demo6.Student.setId(Student.java:30)
at demo6.Student.(Student.java:14)
at demo6.TestStudent.main(TestStudent.java:14)
此处有一点要注意,在案例一的TestPerson中,在main函数中,我们使用try....catch语句,异常由内部进行处理,会打印后面的语句而在案例二的TestStudent中,我们将异常直接交给main函数处理,也就是交给虚拟机处理,所以并不会执行后面的语句
异常对象的抛出
throw new 异常类型()
例如:
throw new Exception()
最后简单介绍一下throws和throw的区别
throws和throw的区别
throws
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常
throw
用在方法体内,跟的异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句实现
throw则是抛出了异常,执行throw则一定抛出了某种异常