JAVA中的异常

一、异常的背景

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

  • 代码少了一个分号
System.out.println("he")
//执行结果
Error:(5, 33) java: 需要';'
  • 除以 0
System.out.println(10 / 0);
//执行结果
Exception in thread "main" java.lang.ArithmeticException: / by zero
  • 数组下标越界
int[] arr = {123};
system.out.print1n(arr[100]);
//执行结果
Exception in thread "main" java.1ang.ArrayIndexoutofBoundsException: 100

异常发生的原因有很多,通常包含以下几大类:

  • 用户输入了非法数据。
  • 要打开的文件不存在。
  • 网络通信时连接中断,或者JVM内存溢出。

异常的三种类型:

  • 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
  • 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
  • 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

二、防御式编程

LBYL: (Look Before You Leap)在操作之前就做充分的检查。
例如:

boolean ret = login();
if (!ret) {
//登陆失败的处理
return;
}
ret = startMatch();
if (!ret) {
//处理匹配失败
return;
}
ret = enterRoom();
if (!ret) {
//处理进入房间失败
return;
}
ret = chooseHero();
if (!ret) {
//处理选择英雄失败
return;
}

EAFP:(lt’s Easier to Ask Forgiveness than Permission)“事后获取原谅比事前获取许可更容易”。也就是先操作,遇到问题再处理。
例如:

try {
    登陆游戏();
    开始匹配();
    游戏确认();
    选择英雄();
    载入游戏画面();
   ...
} catch (登陆游戏异常) {
    处理登陆游戏异常;
} catch (开始匹配异常) {
 处理开始匹配异常;
} catch (游戏确认异常) {
 处理游戏确认异常;
} catch (选择英雄异常) {
 处理选择英雄异常;
} catch (载入游戏画面异常) {
 处理载入游戏画面异常; }
......

三、捕获异常

使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。

try/catch代码块中的代码称为保护代码,使用 try/catch 的语法如下:

try{ 
 有可能出现异常的语句 ; 
}[catch (异常类型 异常对象) {
} ... ]
[finally {
 异常的出口
}]

Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查。

如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。

1、示例1:如果代码中出现了异常,并且没有使用try catch 异常就会由JVM自己来处理,程序就会被直接终止。

public class Exception {
    public static void main(String[] args) {
        System.out.println(10 / 0);
    }
}
//执行结果
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at homework.Exception.main(Exception.java:5)

Process finished with exit code 1

2、示例2:代码中可以使用try把可能抛出异常的代码给包裹起来,使用catch来处理这样的异常。

public class Exception {
    public static void main(String[] args) {
       try{
           double ret;
           ret = 10 / 0;
           System.out.println(ret);
       }catch(ArithmeticException e){
           System.out.println("除数不能为0.");
       }
    }
}
//执行结果
除数不能为0.

注意:try catch 的执行顺序:
(1)先执行try 中的代码(按顺序执行);
(2)执行try 代码的过程中,如果出现异常,就会进入到catch执行,try中剩下的代码就不再执行了;
(3)当catch 也执行完毕之后,就会继续执行后续的代码,程序没有异常终止。

3、示例3:catch 中的异常的类型需要和抛出的异常类型匹配,才能够正确的处理,否则执行不到catch中的逻辑。

public class Exception {
    public static void main(String[] args) {
        try {
            int[] a= {1,2,3};
            System. out. println(a[100]);
            }catch (NullPointerException e){
                System. out. println("catch中的代码");
            }
            System.out.println("hello" );
        }
}
//执行结果
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100
	at homework.Exception.main(Exception.java:8)

注意:

  • 如果try 中抛出的异常的类型和catch 中声明的类型不匹配,此时catch 中的代码就不会被执行到。
  • 使用try catch的时候,必须要非常明确的知道,,try中都会抛出哪些异常。

4、示例4:如果 try 中可能抛出多种异常的话,也就需要多个catch 语句来进行处理。

public class Exception {
    public static void main(String[] args) {
        try {
            int[] a = {1, 2, 3};
            System.out.println(a[10]);
            System.out.println("try中异常之后的代码");
        }catch (NullPointerException e) {
                    System.out.println("catch空指针异常");
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println("catch下标越界异常");
        }
    }
}

5、示例5:可以使用一个catch语句来捕获多个异常。

public class Exception {
    public static void main(String[] args) {
        try {
            int[] a = {1, 2, 3};
            System.out.println(a[10]);
            System.out.println("try中异常之后的代码");
        }catch (NullPointerException |ArrayIndexOutOfBoundsException e) {
                    System.out.println("catch异常");
        }
    }
}

6、示例6:finally表示最后的善后工作,例如释放资源。

public class Exception {
    public static void main(String[] args) {
        try {
            int[] a = {1, 2, 3};
            System.out.println(a[10]);
            System.out.println("try中异常之后的代码");
        }catch (NullPointerException |ArrayIndexOutOfBoundsException e) {
                    System.out.println("catch异常");
        }finally {
            System.out.println("finally code");
        }
    }
}

注意:无论是否存在异常,finally 中的代码一定都会执行到。

7、示例7 使用 try 负责回收资源

try (Scanner sc = new Scanner(System.in)) {
    int num = sc.nextInt();
    System.out.println("num = " + num);
} catch (Exception e) {
    e.printStackTrace();
}

8、示例8:如果本方法中没有合适的处理异常的方式,就会沿着调用栈向上传递。

public static void main(string[] args) {
	try {
		func();
	}catch (ArrayIndexOutOfBoundsException e) {
		e.printstackTrace(;
	}
		System.out.println("after try catch") ;
	}
public static void func(){
	int[]arr = {1,2,3};
	System.out.println(arr[100]);
}
//直接结果
java. lang.ArrayIndexoutofBoundsException : 100

9、示例9:如果向上一直传递都没有合适的方法处理异常, 最终就会交给 JVM 处理, 程序就会异常终止(和我们最开始未使用 try catch 时是一样的)。

四、抛出异常

throw主动抛出异常,被抛出的异常,其实就是一个对象。

public class Exception {
    public static void main(String[] args) {
            System.out.println(divide(10,0));
        }
        public static int divide(int x,int y) {
            if (y == 0) {
                throw new ArithmeticException("抛出除О异常");
            }
            return x / y ;
    }
}

五、异常体系

在这里插入图片描述

  • 所有的异常类是从 java.lang.Exception 类继承的子类。
  • Exception 类是 Throwable 类的子类。除了Exception类外,Throwable还有一个子类Error 。
  • Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。
  • Error 用来指示运行时环境发生的错误。例如,JVM 内存溢出。一般地,程序不会从错误中恢复。
  • 异常类有两个主要的子类:IOException 类和 RuntimeException 类。
  • 受查异常:如果某个方法中抛出了这个异常,那么就必须对这个异常进行显式的处理(显式处理包含两种方案:1、直接try catch,2、使用throws声明可能会抛出这个异常)
  • 非受查异常:(Error、RuntimeException)可以不显式处理。

六、异常方法

方法说明
public String getMessage()返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。
public Throwable getCause()返回一个Throwable 对象代表异常原因。
public String toString()使用getMessage()的结果返回类的串级名字。
public void printStackTrace()打印toString()结果和栈层次到System.err,即错误输出流。
public StackTraceElement [] getStackTrace()返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。
public Throwable fillInStackTrace()用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。

七、自定义异常

实现一个简单的控制台版用户登陆程序, 程序启动提示用户输入用户名密码. 如果用户名和密码出错, 使用自定义异常的方式来处理:

package homework.exception;

import java.util.Scanner;

public class Login {
    public static String username;
    public static String password;
    public static void main(String[] args) throws PasswordException, NameException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = scanner.next();
        System.out.println("请输入密码:");
        String password = scanner.next();
        login(username,password);
        System.out.println("登陆成功!");
    }

    public static void login(String username, String password) throws PasswordException, NameException {
        if(!Login.username.equals("hello")){
            throw new NameException("用户名错误!");
        }
        if(!Login.password.equals("abc")){
            throw new PasswordException("密码错误");
        }
    }
}
package homework.exception;

public class NameException extends Exception {
    public NameException(String message){
        super(message);
    }
}
package homework.exception;

public class PasswordException extends Exception{
    public PasswordException(String message){
        super(message);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值