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{
释放资源代码;
}]
package exception; import java.io.IOException; /*** * @ClassName: TestException * @Description: TODO * @Auther: chujiu * @Date: 2020/4/13 7:15 * @version : V1.0 */ public class TestException { public int method(){ 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 void main(String[] args){ TestException te = new TestException(); 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进行默认处理,则此时会导致程序中断执行。
package exception; import java.io.IOException; /*** * @ClassName: TestException1 * @Description: TODO * @Auther: chujiu * @Date: 2020/4/13 7:17 * @version : V1.0 */ public class TestException1 { public static void method2() throws IOException { int i = 0; if (i == 0) { throw new IOException("除以0错误"); } int x = 5 / i; System.out.println("无异常"); } public static void method1() { try { method2(); } catch (IOException e) { e.printStackTrace(); System.out.println("有异常"); } finally { System.out.println("执行fianlly"); } } public static void main(String[] args) { method1(); } }
4.自定义异常
自定义的异常应该总是包含如下的构造函数:
一个无参构造函数
一个带有String参数的构造函数,并传递给父类的构造函数。
一个带有String参数和Throwable参数,并都传递给父类构造函数
一个带有Throwable 参数的构造函数,并传递给父类的构造函数。
IOException类的完整源代码:
package java.io; public class IOException extends Exception { static final long serialVersionUID = 7818375828146090155L; public IOException() { super(); } public IOException(String message) { super(message); } public IOException(String message, Throwable cause) { super(message, cause); } public IOException(Throwable cause) { super(cause); } }
package exception; import java.util.Scanner; /*** * @ClassName: DemoRegisterException * @Description: TODO * @Auther: chujiu * @Date: 2020/4/13 7:17 * @version : V1.0 */ public class DemoRegisterException { // 1.使用数组保存已经注册过的用户名(数据库) static String[] usernames = {"张三", "李四", "王五"}; public static void main(String[] args) /*throws RegisterException*/ { //2.使用Scanner获取用户输入的注册的用户名(前端,页面) Scanner sc = new Scanner(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 { //添加一个空参数的构造方法 public RegisterException() { super(); } /* 添加一个带异常信息的构造方法 查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息 */ public RegisterException(String message) { super(message); } }