目录
一、异常综述
Object — Throwable |— Error :错误(内存溢出、系统奔溃),无法处理,尽量避免。红色警报
|— Exception :异常,可以根据问题描述处理
|— 编译时期异常:必须处理
|— 运行时期异常(RuntimeException):一般会捕获处理,可以不处理默认交给JVM处理(不建议这么做,程序会终止)
|— NullPointerException :空指针异常
|— ArrayIndexOutOfBoundsException :超出数组下界
二、Java异常处理关键字
try catch,finally,throw,throws
1、try catch
try{
可能会出现异常的代码
}catch(异常类型 变量名){
处理异常的代码:记录日志、打印异常信息、继续抛出异常
}catch(异常类型 变量名){}
作用:捕获异常,尽量不要用JVM处理异常,因为程序会因此终止
注意:
1、try中可能抛出多个异常对象,可以使用多个catch处理异常信息
2、如果try中产生多个异常
2、finallly : 捕获异常后,进入这里
作用:不管发没发生异常都会执行finally中的内容都会被执行
注意:☆ 如果有返回值,finally里一般不写return语句,因为会把try catch块里的return语句效果给覆盖掉。
建议将return语句放在方法结尾
3、throw 关键字
作用:可以在方法中创建指定异常
使用格式:throw new 异常类名(参数)
注意:
3.1 throw关键字必须写在方法内部
3.2 throw关键字后面的new对象必须是异常
3.3 throw关键字后面创建的是指定的异常
— RuntimeException或是它的子类对象: 可以不处理,交于JVM处理
— 编译时异常,必须处理,不能交于JVM处理,确保程序正常运行(抛出或try catch)
3.4 先对入参进行细致的校验,如果产生问题,throw将问题描述类即异常抛出,将问题返回给该方法的调用者
调用者进行捕获处理try catch ; 或继续将问题抛出
4、throws关键字
异常处理的一种方式,在方法后面抛出异常,把异常交于别人处理
作用:当调用的方法抛出非运行时异常时,必须对这个异常进行处理
注意:
4.1 throws 关键字必须出现在方法的声明处
4.1 throws 关键字必须是Exception对象或者Exception的子类
4.3 方法内部如果有多个异常对象,那么throws后边必须也声明多个异常对象
若多个异常对象存在父子关系,只需抛出父类
4.4 调用者调用了一个声明异常的方法,可以选择不处理继续抛出,最终由JVM处理
如若不然调用者必须使用try catch处理
三、子类和父类异常情况
1 若父类抛出异常,子类重写父类方法时,抛出和父类相同的异常或其子类或不抛出异常
2 若父类没有抛出异常,子类重写父类方法时也不可抛出异常。此时子类产生的异常只能捕获处理(try catch),不能声明抛出(throws)
四、自定义异常
作用:根据具体业务的异常情况来定义。如年龄负数、考试负数等异常情况的处理
注意:
1 自定义一个异常类,类名必须以Exception结尾
2 如何自定义一个异常类
2.1 自定义一个编译器异常:继承java.lang.Exception
2.2 自定义一个运行期异常:继承java.lang.RuntimeException
五、代码示例
package com.bilibili.kegongchang.exceptions;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Objects;
public class DemoException extends Throwable{
/**
* 测试
* @param args
*/
public static void main(String[] args) /*throws IOException*/{
System.out.println("测试开始============================");
// ArithmeticException :
int i = 1;
int k = 0;
try {
k = 2;
k = 5;
k = i / 0;
k = 3;
} catch (Exception e) {
e.printStackTrace();//开发调试阶段:控制台打印异常的详细信息(异常的类型,异常的原因,异常出现的位置)
System.out.println(e.getMessage());//提示给用户:获取发生异常的
System.out.println(e.toString());//不用:获取异常的类型和异常描述的信息
} finally {
k = 1;
}
System.out.println(k);
System.out.println("try catch 后程序会继续进行=====================");
System.out.println("超出数组界限=====================");
// ArrayIndexOutOfBoundsException : 超出数组界限
//Exception-RuntimeException-IndexOutOfBoundsException-ArrayIndexOutOfBoundsException
int[] arr = {1, 2, 3};
int x = 0;
try {
x = getElement(arr, 3);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(x);
System.out.println("子类异常和父类异常=====================");
try {
//readFile("");
readFile("d:\\test\\FC10.xml");
}catch (NullPointerException e) {
e.printStackTrace();
}catch (FileNotFoundException e) {// 父类异常包含子类异常,所以需要先抛子类再抛父类
e.printStackTrace();
e.getMessage();
e.toString();
}catch (IOException e) {
e.printStackTrace();
}finally{
System.out.println("finally中的内容被执行了=========");
}
System.out.println("Object 空指针==========================================");
//Object obj = null;
Object obj = new Object();
Objects.requireNonNull(obj);
System.out.println(Objects.requireNonNull(obj));
System.out.println("Error:严重错误==========================================");
// Error:严重错误,无法处理。只能修改源码
// 内存溢出:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
int intArray[] = new int[1024*1024*1024];
System.out.println("== 无法继续进行== ");
}
/**
* 1、throw 先对入参进行校验,如果产生问题,throw将问题描述类即异常抛出,将问题返回给该方法的调用者
* 2、调用者:进行捕获处理try catch ; 或继续将问题抛出
* @param arr
* @param index
* @return 返回数组中对应下标的数字
*/
public static int getElement(int[] arr, int index){
if(arr == null){
throw new NullPointerException("传递的数组不能为null!");
}
if (index < 0 || index > arr.length - 1){
throw new ArrayIndexOutOfBoundsException("传递的数组索引越界!");
}
int element = arr[index];
return element;
}
/**
* Exception - IOException - FileNotFoundException
* FileNotFoundException因为是子类,所以只需要抛出父类
* @param fileName
*/
//public static void readFile(String fileName) throws FileNotFoundException,IOException{
public static void readFile(String fileName) throws IOException{
// 1、校验
// 1.1 校验名称不为空
if (fileName == null || fileName.length() == 0){
throw new NullPointerException("文件名称不能为空!");
}
// 1.2 校验文件是否存在
File file=new File(fileName);
if(!file.exists()){
throw new FileNotFoundException("对应的文件不存在!");
}
// 1.3 校验文件后缀
if (!fileName.endsWith(".txt")){
throw new IOException("文件名称的后缀不是.txt");
}
}
}
package com.bilibili.kegongchang.exceptions;
/**
* 自定义异常:
*/
public class RegisterException extends RuntimeException {
public RegisterException(){
super();
}
public RegisterException(String msg){
super(msg);
}
}
package com.bilibili.kegongchang.exceptions;
/**
* 要求:我们模拟注册操作,如果用户已存在,则抛出异常并提示:亲,改用户名已经被注册
* 分析:
* 1、使用数组保存已经注册过的用户名称
* 2、使用Scanner获取用户输入的注册用户名(web页面)
* 3、定义一个方法,对用户输入的信息进行判断
* 便利每个元素,获取用户名
* 若存在返回 true :用户已存在,抛出RegisterException异常
* 否则返回 false :继续遍历比较
*/
public class ExceptionTest {
static String[] users = {"Jack","Nancy","Rose"};
public static void main(String[] args) {
boolean flag = false;// 是否注册成功
try {
flag = checkUserName("Jack");
}catch (RegisterException e){
e.printStackTrace();
// 写入日志
}
try {
flag = checkUserName("Shelly");
}catch (RegisterException e){
e.printStackTrace();
}
if (flag == true){
System.out.println("ok");//去首页
}else {
System.out.println("no");//停留在注册页
}
System.out.println("程序继续====================");
}
public static boolean checkUserName(String userName){
boolean flag = false;
for(String user : users){
if (user.equals(userName)){
throw new RegisterException("亲,改用户名已经被注册!");
}
}
System.out.println("欢迎"+ userName +",注册成功!");
flag = true;
return flag;
}
}