1.什么是异常?

异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。

比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;

如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出 java.lang.ArithmeticException 的异常。

用户输入了非法数据。

要打开的文件不存在。

网络通信时连接中断,或者JVM内存溢出。

检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。

运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。

错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

2.常见的Exception 类的层次

输入输出异常:IOException

算术异常类:ArithmeticExecption

空指针异常类:NullPointerException

类型强制转换异常:ClassCastException

操作数据库异常:SQLException

文件未找到异常:FileNotFoundException

数组负下标异常:NegativeArrayException

数组下标越界异常:ArrayIndexOutOfBoundsException

违背安全原则异常:SecturityException

文件已结束异常:EOFException

字符串转换为数字异常:NumberFormatException

方法未找到异常:NoSuchMethodException

3.异常处理方式

3.1 通过try、catch捕获异常

try
{
可能会发生的异常
}catch(异常类型 异常名(变量)){
针对异常进行处理的代码
}catch(异常类型 异常名(变量)){
针对异常进行处理的代码
}...
[finally{

释放资源代码;

}]
packageexception;importjava.io.IOException;/***
* @ClassName: TestException
* @Description: TODO
* @Auther: chujiu
* @Date: 2020/4/13 7:15
*@version: V1.0*/
public classTestException {public intmethod(){try{int i = 5 / 0; //算术异常
System.out.println("无异常");return 1;
}catch(Exception e) {
e.printStackTrace();
System.out.println("有异常");return 2;
}finally{
System.out.println("执行fianlly");return 3;
}
}public static voidmain(String[] args){
TestException te= newTestException();
System.out.println(te.method());
}
}

catch 不能独立于 try 存在。

在 try/catch 后面添加 finally 块并非强制性要求的。

try 代码后不能既没 catch 块也没 finally 块。

try, catch, finally 块之间不能添加任何代码。

首先一个不容易理解的事实:在 try块中即便有return,break,continue等改变执行流的语句,finally也会执行。

finally中的return 会覆盖 try 或者catch中的返回值。

finally中的return或异常会抑制(消灭)前面try或者catch块中的异常。

3.2 throw关键字抛出异常

指的是在方法中人为抛出一个异常对象(这个异常对象可能是自己实例化或者抛出已存在的);用于抛出异常。

3.3 通过throws抛出异常

用在方法签名中,用于声明该方法可能抛出的异常。主方法上也可以使用throws抛出。如果在主方法上使用了throws抛出,就表示在主方法里面可以不用强制性进行异常处理,如果出现了异常,就交给JVM进行默认处理,则此时会导致程序中断执行。

packageexception;importjava.io.IOException;/***
* @ClassName: TestException1
* @Description: TODO
* @Auther: chujiu
* @Date: 2020/4/13 7:17
*@version: V1.0*/
public classTestException1 {public static void method2() throwsIOException {int i = 0;if (i == 0) {throw new IOException("除以0错误");
}int x = 5 /i;
System.out.println("无异常");
}public static voidmethod1() {try{
method2();
}catch(IOException e) {
e.printStackTrace();
System.out.println("有异常");
}finally{
System.out.println("执行fianlly");
}
}public static voidmain(String[] args) {
method1();}
}

4.自定义异常

自定义的异常应该总是包含如下的构造函数:

一个无参构造函数

一个带有String参数的构造函数,并传递给父类的构造函数。

一个带有String参数和Throwable参数,并都传递给父类构造函数

一个带有Throwable 参数的构造函数,并传递给父类的构造函数。

IOException类的完整源代码:

packagejava.io;public class IOException extendsException {static final long serialVersionUID = 7818375828146090155L;publicIOException() {super();
}publicIOException(String message) {super(message);
}publicIOException(String message, Throwable cause) {super(message, cause);
}publicIOException(Throwable cause) {super(cause);
}
}
packageexception;importjava.util.Scanner;/***
* @ClassName: DemoRegisterException
* @Description: TODO
* @Auther: chujiu
* @Date: 2020/4/13 7:17
*@version: V1.0*/
public classDemoRegisterException {//1.使用数组保存已经注册过的用户名(数据库)
static String[] usernames = {"张三", "李四", "王五"};public static void main(String[] args) /*throws RegisterException*/{//2.使用Scanner获取用户输入的注册的用户名(前端,页面)
Scanner sc = newScanner(System.in);
System.out.println("请输入您要注册的用户名:");
String username=sc.next();
checkUsername(username);
}//3.定义一个方法,对用户输入的中注册的用户名进行判断
public static void checkUsername(String username) /*throws RegisterException*/{//遍历存储已经注册过用户名的数组,获取每一个用户名
for(String name : usernames) {//使用获取到的用户名和用户输入的用户名比较
if(name.equals(username)) {//true:用户名已经存在,抛出RegisterException异常,告知用户"亲,该用户名已经被注册";
try{throw new RegisterException("亲,该用户名已经被注册");
}catch(RegisterException e) {
e.printStackTrace();return; //结束方法
}
}
}//如果循环结束了,还没有找到重复的用户名,提示用户"恭喜您,注册成功!";
System.out.println("恭喜您,注册成功!");
}
}//异常类
class RegisterException extends /*Exception*/RuntimeException {//添加一个空参数的构造方法
publicRegisterException() {super();
}/*添加一个带异常信息的构造方法
查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息*/
publicRegisterException(String message) {super(message);
}
}