简述
异常就是程序中出现的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的
三种类型异常
- 编译时被检查的异常
最具代表的检查性异常是用户错误或问题引起的异常,这是程序员引起的异常。例如打开一个不存在的异常时,一个异常就发生了,这些异常在编译时不能被简单地忽略(只要Exceptio 及其子类都是编译时被检测的异常)
- 运行时异常
运行时异常时可能被程序员避免的异常,与检查性异常相反运行时异常可以在编译时被忽略(Exception有一个特殊的子类RuntimeException,以及它的子类是运行异常,也就是说这个异常时编译时不被检查的异常)
区别:
编译时被检查的异常在函数内被抛出,函数必须要声明,否则编译失败
声明的原因:是需要调用者对该异常进行处理
运行时异常如果在函数内抛出,在函数上不需要声明
不声明的原因:不需要调用者处理,运行时异常发生,已经无法再让程序继续运行,所以不让调用处理的,直接让程序停止,由调用者对代码进行修正
注意:
错误不是异常,而是脱离程序员控制的问题,错误在代码中通常被忽略,例如当栈溢出时,一个错误就发生了,他们在编译也检查不到
自定义异常
当不满足业务逻辑要求时,可以主动抛出异常(当一个地方种sh)使用throw抛出异常时,就应当在dang当前方法上使用throws声明该异常的抛出,通知当前要处理的异常(RunTimeException除外)否则编译不通过
public class Person {
private int age;
public int getAge() {
return age;
}
public void setAge(int age)throws IllegalAgeException {
if(age<0||age>100) {
/*
* 当不满足业务逻辑要求时,可以主动抛出异常
*
* 当一个地方种使用throw抛出一个异常时,就应当在当前方法上使用throws声明该异常的抛出
* 通知调用当前的方法时要处理异常(RunTimeException除外)否则编译不通过
*/
//当不满足业务逻辑要求时,可以主动抛异常
throw new IllegalAgeException("年龄不合法");
}
this.age = age;
}
}
package exception;
/**
* 年龄不合法异常
*
* 自定义异常通常用来说明某些业务逻辑错误
*
* @author liuyanyan
*
*/
public class IllegalAgeException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
//默认生成的构造方法
public IllegalAgeException() {
super();
}
public IllegalAgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public IllegalAgeException(String message, Throwable cause) {
super(message, cause);
}
public IllegalAgeException(String message) {
super(message);
}
public IllegalAgeException(Throwable cause) {
super(cause);
}
public static void main(String[] args) {
}
}
public class ThrowDemo {
public static void main(String[] args) {
System.out.println("程序开始了");
Person p = new Person();
// try {
// /*
// * 当调用一个含有throws声明异常抛出的方法时,编译器要求必须处理这个异常
// * 而处理的方式有两种
// * 1:使用try-catch处理该异常
// * 2:在当前方法上继续声明throws将该异常抛出
// * 具体如何处理,结合实际业务需求而定
// *
//
// p.setAge(1000);
// } catch (Exception e) {
// e.printStackTrace();
// }
try {
p.setAge(1000);
} catch (IllegalAgeException e) {
e.printStackTrace();
}
System.out.println("此人年龄:"+p.getAge());
System.out.println("程序结束了");
}
}
异常处理方式
- try:
try{
需要被检测的代码;
}catch(异常类 变量名){
异常处理代码;
}finally{
一定要执行的代码
}
public static void main(String[] args) {
System.out.println("程序开始了");
/*
* 当JVM执行代码时遇到异常时,会实例化该异常的一个实例,然后设置好代码执行的过程,并将该异常抛出
* 如果抛出异常的代码所在方法没有处理异常的能力,异常会抛到方法之外,由调用当前方法的代码片段去处理
*/
try {
/*
* try代码片段中出错的代码之后的内容都不会执行
*/
String str = "a";
System.out.println(str.length());
System.out.println("break up");
System.out.println(str.charAt(0));
System.out.println(Integer.parseInt(str));
/*
* catch可以定义多个,针对不同的异常有不同处理手段时,可以分别捕获这些异常
*/
/*
* 应当有一个好习惯,在最后一个catch中捕获Exception,尽量避免因为一个未捕获的异常导致程序中断
*
* 捕获顺序应当子类型异常在上面先捕获,父类型异常在后面捕获
*/
}catch(NullPointerException e) {
System.out.println("出现了空指针异常");
}catch (StringIndexOutOfBoundsException e) {
System.out.println("出现了字符串下标越界异常");
}catch(Exception e) {
System.out.println("反正就是出了个错");
}
System.out.println("程序结束了");
}
package exception;
/**
* finally块时异常捕获机制中最后一块
* finally可以直接跟在try后面或者最后一个catch之后
* finally可以保证只要程序执行到try语句块中,无论try语句块中的代码是否抛出异常,finally块中的代码都必定执行
* 通常会将无论是否出现异常都要运行的代码放在finally中确保运行,比如io操作中的关闭流
* @author liuyanyan
*
*/
public class FinallyDemo {
public static void main(String[] args) {
System.out.println("程序开始了");
try {
String str = "";
System.out.println(str.length());
return;
} catch (Exception e) {
System.out.println("程序出错了");
}finally {
System.out.println("finally中的代码执行了");
}
System.out.println("finally中的代码执行了");
System.out.println("程序结束了");
}
}
package exception;
import java.io.FileInputStream;
import java.io.IOException;
/**
* 异常处理机制在io中的使用
* @author liuyanyan
*
*/
public class FinallyDemo2 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis= new FileInputStream("fos.txt");
int d = fis.read();
System.out.println(d);
} catch (IOException e) {
e.printStackTrace();
}finally {
/*try {
if(fis!=null) {
fis.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}*/
}
}
}
package exception;
import java.io.FileInputStream;
import java.io.IOException;
/**
* Jdk1.7之后推出了一个新特性 :自动关闭
* @author liuyanyan
*
*/
public class FinallyDemo3 {
public static void main(String[] args) {
try(
/*
* 只有实现了AutoCloseable接口的可以定义在这里
* 该特性是编译器认可,最终编译器还是会将代码改为在finally中关闭流
*/
FileInputStream fis = new FileInputStream("fos.txt");
){
int d = fis.read();
System.out.println(d);
}catch(IOException e){
e.printStackTrace();
}
}
}
异常处理时什么时候定义try什么时候使用throws
功能内部如果出现异常,如果内部可以处理就用try
如果功能内部处理不了,就必须声明出来,让调用者处理,使用throws抛出 ,交给调用者处理。谁调用了这个功能谁就是调用者