Java-32 异常
- 异常概念:异常就是Java程序在运行过程中出现的错误。
- 异常分类:
- java. lang. Throwable:类是Java语言中所有错误或异常的超类。
-
- Exception :编译期异常,进行编译(写代码)java程序出现的问题
-
-
- RuntimeException:运行期异常, java程序运行过程中出现的问题
-
异常就相当于程序得了一个小毛病(感冒,发烧),把异常处理掉,程序可以继续执行(吃点药,继续革命工作)
-
- Error:错误
错误就相当于程序得了一个无法治愈的毛病(非典,艾滋).必须修改源代码,程序才能继续执行
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /* Java中的异常:Throwable 严重的问题:Error,一般情况下,我们不处理,这样的问题一般都是很严重, 比如OOM,内存溢出问题。 问题:异常:Exception 运行时异常:RuntimeException,这样的问题我们也不处理,因为这种问题一般都是 你自己写代码出现的问题比如代码不够严谨 编译时异常: 除了不是RuntimeException都是编译时异常,必须要进行处理,如果你不处理, 程序编译就不通过,无法运行。 */ public class ExceptionDemo1 { public static void main(String[] args) { // int a = 10; // int b = 0; // System.out.println(a/b);//运行期异常 // System.out.println("你好世界");//异常不处理,后续代码无法执行 //Exception:编译期异常,进行编译写代码Java程序出现异常 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // Date data = sdf.parse("2021-1018");//表示这里可能会出现错误,但是你又没处理,所以不能编译 //对异常处理 Date date = null; try { date = sdf.parse("2021-1018"); } catch (ParseException e) { e.printStackTrace(); } System.out.println(date);//null System.out.println("后续代码");//异常处理,后续代码可以运行 } }
- 异常的处理过程图解:
- 异常处理方案
- throw关键字
- throw关键字
import java.util.Objects; public class ExceptionDemo2 { public static void main(String[] args) { /* 定义一个方法,获取数组指定索引处的元素 参数: int[] arr int index 以后工作中,我么首先必须对方法传递过来的参数进行合法性校验 如果参数不合法,那么我们就必须使用抛出异常的方法,告知方法使用者,传递参数有问题 例如用户注册重名问题 */ int[] arr = null; int[] arr1 = {1,5,9}; //int element = getElement(arr, 0); int element1 = getElement(arr1, 3); } public static int getElement(int[] arr,int index){ //对方法传递过来的参数进行合法性校验 //如果数组arr为null,那么我们就抛出空指针异常,告知调用者,传递参数出现问题 // if(arr == null){ // throw new NullPointerException("传递的数组值是null"); // //NullPointerException是运行期异常,我们不用处理,默认交给JVM处理,中断程序 // } //使用objects非空判断简化 Objects.requireNonNull(arr,"传递的数组值是null"); // Objects.requireNonNull(arr); //如果index范围不在索引范围内,我们就抛出数组索引越界 //告知方法调用者"传递的索引超出了数组的使用范围" //ArrayIndexOutOfBoundsException,我们不用处理,默认交给JVM处理,中断程序 if (index<0 || index >arr.length-1){ throw new ArrayIndexOutOfBoundsException("传递的索引超出了数组的使用范围"); } int ele = arr[index]; return ele; } }
-
使用objects非空判断简化
- throws关键字
/* throws关键字编译异常抛给jvm虚拟机处理,中断程序.后续代码不执行 */ import java.io.FileNotFoundException; public class ExceptionDemo3 { public static void main(String[] args) throws FileNotFoundException { readFile("D:\\a.tx"); } public static void readFile(String fileName) throws FileNotFoundException { //传参合法性校验 //编译错误 if (!fileName.equals("D:\\a.txt")){ throw new FileNotFoundException("传递文件路径不是D:\\a.txt"); } System.out.println("路径没有问题,读取文件"); } }
- throws和throw的区别:
- try-catch
注意事项:
1、try里面的代码尽量不要太多
2、catch里面必须要有内容,哪怕只是有一句简单提示语句
import java.io.FileNotFoundException; /* try-catch自己处理异常; 后续代码执行 */ public class ExceptionDemo4 { public static void main(String[] args) { try { readFile("D:\\a.tx"); } catch (FileNotFoundException e) { e.printStackTrace(); } try { readFile("D:\\a.txt"); } catch (FileNotFoundException e) { e.printStackTrace(); } System.out.println("这是后续代码"); } public static void readFile(String fileName) throws FileNotFoundException { //传参合法性校验 //编译错误 if (!fileName.equals("D:\\a.txt")) { throw new FileNotFoundException("传递文件路径不是D:\\a.txt"); } System.out.println("路径没有问题,读取文件"); } }
- Throwable中定义了3个异常处理方法
- finally代码块:
final,finally和finalize的区别:
final:最终的意思,可以修饰类,成员变量,成员方法
修饰类:类不能被继承
修饰成员变量:变量就是常量
修饰成员方法:方法不能被重写
finally:是处理异常的一部分,一般情况下用于释放资源的作用,一般来说都会执行
特殊情况下:在执行finally之前JVM就停了(System.exit(0))
finalize:是Object类中的一个方法,用于手动垃圾回收,但是不一定会立即回收
- 多个异常捕获处理问题:
- 多个异常分别处理
public static void fun2() { int a = 10; int b = 0; try { System.out.println(a / b); } catch (ArithmeticException a1) { System.out.println("出错啦 除数不能为0"); } int[] arr = {1, 2, 3, 4, 5}; //ArrayIndexOutOfBoundsException是运行时异常 try { System.out.println(arr[5]); } catch (ArrayIndexOutOfBoundsException a2) { System.out.println("数组下标越界啦 "); } // System.out.println(arr[5]); System.out.println("over");
-
- 多个异常一次捕获,多次处理
//平级的关系,多个catch异常没有前后顺序关系,谁在前谁在后无所谓 //一旦出现了父类继承的关系,父必须在后。 //一旦try里面的代码出现了问题,就会去匹配catch里面的异常,继续执行程序后面的代码, //但是try里面的代码就停在了出现问题的那一步。 public static void fun3() { int a = 10; int b = 0; try { System.out.println(a / b); int[] arr = {1, 2, 3, 4, 5}; System.out.println(arr[5]); } catch (ArithmeticException a1) { System.out.println("除数不能为0 "); } catch (ArrayIndexOutOfBoundsException a2) { System.out.println("数组下标越界了"); } System.out.println("over"); }
/* JDK7的新特性及注意事项 新特性处理多个异常 try{ 可能会出现问题的代码; }catch(异常类名1|异常类名2|... 变量名){ 处理异常的提示; } 注意: 1、处理方式是一致的,这个方法虽然比较简洁,但是不够好,针对多种类型的问题,只给出了一种 解决方案。 2、多个异常的类型之间必须是平级关系 */ public class ExceptionDemo4 { public static void main(String[] args) { fun(); } public static void fun(){ int a = 10; int b = 0; // try{ // System.out.println(a / b); // int[] arr = {1, 2, 3, 4, 5}; // System.out.println(arr[5]); // }catch (ArithmeticException a1){ // System.out.println("除数不能为0 "); // }catch (ArrayIndexOutOfBoundsException a2){ // System.out.println("数组下标越界了"); // } try{ System.out.println(a / b); int[] arr = {1, 2, 3, 4, 5}; System.out.println(arr[5]); }catch (ArithmeticException|ArrayIndexOutOfBoundsException a1){ // System.out.println("除数不能为0 "); System.out.println("出错了!!"); } System.out.println("over"); } }
-
- 多个异常一次捕获一次处理
public static void fun4(){ int a = 10; int b = 0; try { System.out.println(a / b); int[] arr = {1, 2, 3, 4, 5}; System.out.println(arr[5]); } catch (Exception e) { e.printStackTrace(); } System.out.println("over"); }
注意事项:
父类异常什么样,子类异常就是什么样
public class Fu { public void show1()throws NullPointerException,ClassCastException{}; public void show2()throws IndexOutOfBoundsException{}; public void show3()throws IndexOutOfBoundsException{}; public void show4(){}; } class Zi extends Fu{ //子类重写方法时,抛出和父类相同异常 @Override public void show1() throws NullPointerException, ClassCastException {} //子类重写父类方法时,抛出分类异常子类 @Override public void show2() throws ArrayIndexOutOfBoundsException {} //子类重写父类方法时不抛出异常 public void show3(){} //父类没有抛出异常,子类产生异常只能捕获和处理,不能抛出 public void show4(){ try { throw new Exception(); } catch (Exception e) { e.printStackTrace(); } } }
自定义异常类:
/* 自定义异常类 */ public class MyException extends Exception { //添加一个空参数的构造方法 public MyException(){ super(); }; /* 添加一个带异常信息的构造方法 查看源码我们发现所有的的异常类都会有一个带异常类信息的构造方法, 方法内部会调用父类异常信息的构造方法,让父类来处理这个异常信息 */ public MyException(String message){ super(message); } }
自定义异常类小练习:
public class MyException1 extends Exception{ public MyException1(){}; public MyException1(String message){ super(message); } }
import java.util.Scanner; class MyException2 extends RuntimeException{ public MyException2(){ super(); } public MyException2(String message){ super(message); } } public class Text { //使用数组保存已注册用户名(数据库) static String[] userName ={"张三","李四","王五"}; public static void main(String[] args) /*throws MyException1*/ { //创建键盘录入对象获取输入注册的用户名(前端,页面) Scanner sc = new Scanner(System.in); System.out.println("请输入您想注册的用户名:"); String name = sc.next(); checkname(name); } //定义一个方法,对输入用户名与已有用户名进行判断 public static void checkname(String name) /*throws MyException1*/ { //遍历存储已经注册用户名数组,获取每一个用户名 for (String s : userName) { //用户名进行比较 if (s.equals(name)){ //true:用户名已经存在,抛出自定义异常,告知信息 try { throw new MyException1("该用户名已经注册"); } catch (MyException1 myException1) { myException1.printStackTrace(); return; } } } //自定义类继承runtime运行异常,交给jvm虚拟机处理 // for (String s : userName) { // if (s.equals(name)){ // throw new MyException2("该用户已注册,注册失败"); // } // } //如果循环结束还没有找到,注册成功 System.out.println("恭喜你,注册成功"); } }