异常
异常的概述:
异常,就是不正常的意思。在⽣活中:医⽣说,你的身体某个部 位有异常,该部位和正常相⽐有点不同,该部位的功能将受影响. 在程序中的意思就是:
异常:指的是程序在执⾏过程中,出现的⾮正常的情况, 最终会导致JVM的⾮正常停⽌。
注意:在Java等⾯向对象的编程语⾔中,异常本身是⼀个类, 产⽣异常就是创建异常对象并抛出了⼀个异常对象。Java处理 异常的⽅式是中断处理。
异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行
异常体系
异常机制其实是帮助我们找到程序中的问题,异常的根类是java.lang.Throwable,其下有两个子类:java.lang.Error与java.lang.Exception,平常所说的异常指java.lang.Exception
Throwable体系:
- Errot:严重错误Error, ⽆法通过处理的错误,只能事先避免,好比绝症
- Exception:表示异常,异常产⽣后程序员可以通过代码的⽅式纠正,使程序继续运⾏,是必须要处理的。好⽐感冒、阑尾炎。
我们平常说的异常就是指 Exception ,因为这类异常⼀旦出 现,我们就要对代码进⾏更正,修复程序。 异常 (Exception) 的分类 : 根据在编译时期还是运⾏时期去检查 异常?异常分类
- 编译时期异常 :checked 异常。在编译时期 , 就会检查 , 如果没 有处理异常, 则编译失败。 ( 如⽇期格式化异常 )
- 运⾏时期异常 :runtime 异常。在运⾏时期 , 检查异常 . 在编译 时期, 运⾏异常不会编译器检测 ( 不报错 ) 。 ( 如数学异常 )
代码:
package yichang;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Excepito01 {
public static void main(String[] args) throws ParseException {
//method1();如果调用异常的方法,谁调用就要解决或者跟着抛出异常交给JVM
int [] arr={1,2,3};
int num =method2(4,arr);
System.out.println(num);
}
public static void method(){
System.out.println("1");
//自己掉自己运行时会出现异常
method();
}
public static void method1() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//编译异常,会抛出异常
Date date = sdf.parse("2000.02.02");
}
//下标越界异常
public static int method2(int i,int[]arr){
//对给定的数组通过给定的角标获取元素 ArrayIndexOutOfBoundsException
int a = arr[i];
return a;
}
}
先运⾏下⾯的程序,程序会产⽣⼀个数组索引越界异常 ArrayIndexOfBoundsException。我们通过图解来解析下异 常产⽣的过程。异常的产生过程解析
public class Test {
public static void main(String[] args) {
int[] arr = { 34, 12, 67 };
int num = getElement(arr, 4);
System.out.println("num=" + num);
System.out.println("over");
}
// 对给定的数组通过给定的⻆标获取元素。
public static int getElement(int[] arr, int
index) {
int element = arr[index];
return element;
}
}
异常的产生和处理
异常的产生
throw关键字:
在java中,提供了⼀个throw关键字,它⽤来抛出⼀个指定的 异常对象。throw⽤在⽅法内,⽤来抛出⼀个异常对象,将这 个异常对象传递到调⽤者处,并结束当前⽅法的执⾏。
throw关键字的使用格式:
throw new 异常类名(参数);
例如:
throw new NullPointerException ( " 要访问的 arr 数组不 存在 " ); throw new ArrayIndexOutOfBoundsException ( " 该索引 在数组中不存在,已超出范围 " );
代码:
public class Excepito02 {
public static void main(String[] args) throws Exception {
System.out.println(aaa(-1));
}
public void aaa(int age) {
if (age>=0){
this.age= age;
}else {
//如果年龄是负数,就让他报错
throw new RuntimeException("年龄不能是"+age);
}
}
}
声明处理异常
声明处理概述:
声明处理异常:使⽤throws关键字将异常标识出来, 表示当前 ⽅法不处理异常,⽽是提醒给调⽤者, 让调⽤者来处理....最终 会到虚拟机,虚拟机直接结束程序,打印异常信息。
声明处理异常格式:
修饰符 返回值类型 ⽅法名 ( 参数 ) throws 异常类名 1 , 异常类 名 2… { // 可以抛出⼀个 , 也可以多个 }
代码:
public class Demo {
public static void main(String[] args)
throws IOException{
method1();
}
public static void method3(int num) throwsException {
if(num == 1) {
throw new IOException("IO异常");//创建了⼀个编译异常,并通过throw抛出这个编译异常
}else{
throw new ParseException("解析异常",1);
}
}
捕获处理异常try…catch
捕获处理异常:对异常进行捕获处理,处理完后程序可以正常向下执行
try { 编写可能会出现异常的代码 } catch ( 异常类型 e ){ 处理异常的代码 // 记录⽇志 / 打印异常信息 / 继续抛出异常 } 执⾏步骤 : 1. ⾸先执⾏ try 中的代码 , 如果 try 中的代码出现了异常 , 那么 就直接执⾏ catch () ⾥⾯的代码 , 执⾏完后 , 程序继续往下执⾏ 2. 如果 try 中的代码没有出现异常 , 那么就不会执⾏ catch () ⾥⾯的代码 , ⽽是继续往下执⾏ 注意: 1. try 和 catch 都不能单独使⽤ , 必须连⽤。 2. try 中的代码出现了异常 , 那么出现异常位置后⾯的代码 就不会再执⾏了 3. 捕获处理异常 , 如果程序出现了异常 , 程序会继续往下执 ⾏ 声明处理异常, 如果程序出现了异常 , 程序就不会继续往下 执⾏代码:
public class Demo {
public static void main(String[] args) {
try {
SimpleDateFormat sdf = newSimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("1999年10⽉12⽇");
System.out.println(date);
}catch (Exception e){
System.out.println("出现了异常....");
}
System.out.println("结束");
}
}
获取异常信息
Throwable类中定义了一些查看方法:
- public String getMessage() : 获取异常的描述信息 , 原 因( 提示给⽤户的时候 , 就提示错误原因。
- public void printStackTrace() : 打印异常的跟踪栈信 息并输出到控制台。
- public String toString() : 获取异常的类型和异常描述 信息( 不⽤ ) 。
代码:
public class Excepito03 {
public static void main(String[] args) {
//try要放出现的代码异常
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse("2000.12.12");
System.out.println(date);
}
//如果try出现了异常就会直接执行catch
catch (Exception e){
//我们就可以给他个提示
//System.out.println("出现了异常");
//获取异常的描述信息(原因)
System.out.println(e.getMessage());
//获取异常的类型和异常描述信息
//System.out.println(e.toString());
//打印异常的跟踪栈信息并输出到控制台
//e.printStackTrace();
}
System.out.println("结束");
}
}
finally代码块
概述:
finally :有⼀些特定的代码⽆论异常是否发⽣,都需要执 ⾏。另外,因为异常会引发程序跳转,导致有些语句执⾏不 到。⽽finally 就是解决这个问题的,在 finally 代码块中存放的 代码都是⼀定会被执⾏的。 语法格式:try { 可能会出现异常的代码 } catch ( 异常的类型 变量名 ){ 处理异常的代码或者打印异常的信息 } finally { ⽆论异常是否发⽣ , 都会执⾏这⾥的代码 ( 正常情况 , 都会执 ⾏ finally 中的代码 , ⼀般⽤来释放资源 ) } 执⾏步骤 : 1. ⾸先执⾏ try 中的代码 , 如果 try 中的代码出现了异常 , 那么 就直接执⾏ catch () ⾥⾯的代码 , 执⾏完后会执⾏ finally 中的 代码 , 然后程序继续往下执⾏ 2. 如果 try 中的代码没有出现异常 , 那么就不会执⾏ catch () ⾥ ⾯的代码 , 但是还是会执⾏ finally 中的代码 , 然后程序继续往下 执⾏
public class Excepito04 {
public static void main(String[] args) {
try {
int i = 10/0;
} catch (Exception e) {
e.printStackTrace();
System.out.println("出现了异常");
}
//不能单独使用,无论异常是否发生都会执行这里代码,一般用来释放资源
finally {
System.out.println("关闭");
}
}
}
异常注意事项
- 运⾏时异常被抛出可以不处理。即不捕获也不声明抛出。
- 如果⽗类的⽅法抛出了多个异常 , ⼦类覆盖 ( 重写 ) ⽗类⽅法时, 只能抛出相同的异常或者是他的⼦集
- ⽗类⽅法没有抛出异常,⼦类覆盖⽗类该⽅法时也不可抛出异常。此时⼦类产⽣该异常,只能捕获处理,不能声明抛出
- 当多异常分别处理时,捕获处理,前边的类不能是后边类的⽗类
- 在 try/catch 后可以追加 finally 代码块,其中的代码⼀定会被执⾏,通常⽤于资源回收
多个异常使用捕获又该如何处理呢?
- 多个异常分别处理
- 多个异常⼀次捕获,多次处理。
- 多个异常⼀次捕获⼀次处理。
try { 编写可能会出现异常的代码 } catch ( 异常类型 A e ){ 当 try 中出现 A 类型异常 , 就⽤该 catch 来捕获 . 处理异常的代码 // 记录⽇志 / 打印异常信息 / 继续抛出异常 } catch ( 异常类型 B e ){ 当 try 中出现 B 类型异常 , 就⽤该 catch 来捕获 . 处理异常的代码 // 记录⽇志 / 打印异常信息 / 继续抛出异常 } 注意 : 这种异常处理⽅式,要求多个 catch 中的异常不能 相同,并且若 catch 中的多个异常之间有⼦⽗类异常的 关系,那么⼦类异常要求在上⾯的 catch 处理,⽗类异 常在下⾯的 catch 处理。1.多个异常一次捕获一次处理
public static void method01(int n) {
//多个异常一次捕获一次处理
try {
if (n == 1) {
throw new IOException("IO异常");
} else {
throw new ParseException("解析异常", 1);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("出现异常");
}
}
2.多个异常一次捕获多次处理
public static void method02(int n) {
//多个异常一次捕捉多次处理
try {
if (n == 1) {
throw new IOException("IO异常");
} else {
throw new ParseException("解析异常", 1);
}
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
3.多个异常分别处理
public static void method03(int n) {
//多个异常分别处理
if (n == 1) {
try {
throw new IOException("IO异常");
} catch (IOException e) {
e.printStackTrace();
}
} else {
try {
throw new ParseException("解析异常",1);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
自定义异常
概述:
为什么需要⾃定义异常类:我们说了Java中不同的异常类,分别表示着某⼀种具体的异常情况,那么在开发中总是有些异常情况是SUN没有定义好的,例如年龄负数问题,考试成绩负数问题.这些异常在JDK中没有定义过,此时我们根据⾃⼰业务的异常情况来定义异常类。
什么是⾃定义异常类:在开发中根据⾃⼰业务的异常情况来定义异常类, ⾃定义⼀个业务逻辑异常 : RegisterException 。⼀个注册异 常类。异常类如何定义:
- ⾃定义⼀个编译期异常: ⾃定义类 并继承于java.lang.Exception。
- ⾃定义⼀个运⾏时期的异常类 :⾃定义类 并继承于java.lang.RuntimeException 。
public class Excpito05 {
private static String[] names = {"张三","李四","王五" };
public static void main(String[] args) {
try {
checkUsername("张三",names);
//如果录入一个不存在的名字就会注册成功
// boolean a= checkUsername("kl",names);
// System.out.println(a);
// System.out.println("注册成功");
}catch (Exception e){
e.printStackTrace();
}
}
public static boolean checkUsername(String username,String [] str) throws Exception {
for (String name : str) {
if (name.equals(username)) {
throw new RegisterException("该账户已经被注册");
}
}
return true;
}
}



