Java:异常

目录

一、异常

1.常见异常

2.防御式编程

二、异常的基本用法

1、捕获异常

(1)基本语法

(2)不处理异常及使用捕获异常对比

(3)使用注意

2、异常处理流程

3、自定义异常类

自定义异常类示例:用户登陆功能.


一、异常

所谓异常指的就是程序在 运行时 出现错误时通知调用者的一种机制。

关键字 :"运行时"有些错误是这样的, 例如将 System.out.println 拼写错了, 写成了 system.out.println. 此时编译过程中就会出错, 这是 "编译期" 出错

而运行时指的是程序已经编译通过得到 class 文件了, 再由 JVM 执行过程中出现的错误。

1.常见异常

1、算术异常(ArithmeticException)

例1:除以0
System.out.println(10 / 0);
// 执行结果:Exception in thread "main" java.lang.ArithmeticException: / by zero

2、数组下标越界(ArrayIndexOutOfBoundsException)

例2:
int[] arr = {1, 2, 3};
System.out.println(arr[100]);
// 执行结果:Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100

3、空指针异常NullPointerException

例3:访问 null 对象
public class Test {
    public int num = 10;
    public static void main(String[] args) {
        Test t = null;
        System.out.println(t.num);
   }
}// 执行结果:Exception in thread "main" java.lang.NullPointerException

2.防御式编程

错误在代码中是客观存在的,因此我们要让程序出现问题的时候及时通知程序猿;我们有两种主要的方式:

 LBYL: Look Before You Leap. 在操作之前就做充分的检查.                                                                 EAFP: It's Easier to Ask Forgiveness than Permission. "事后获取原谅比事前获取许可更容易". 也就是先操作, 遇到 问题再处理.

  • 异常的核心思想就是 EAFP.

二、异常的基本用法

1、捕获异常

(1)基本语法

try{
 有可能出现异常的语句 ;
}[catch (异常类型 异常对象) {
} ... ]
[finally {
 异常的出口
}]
  • 注:
  • try 代码块中放的是可能出现异常的代码.
  • catch 代码块中放的是出现异常后的处理行为.
  • finally 代码块中的代码用于处理善后工作, 会在最后执行.
  • 其中 catch 和 finally 都可以根据情况选择加或者不加.

(2)不处理异常及使用捕获异常对比

(1)不处理异常

若不处理异常,一旦出现异常, 程序立刻终止,异常处之后不再运行;

        int[] arr = {1, 2, 3};
        System.out.println("语句1");
        System.out.println(arr[100]);//发生异常处
        System.out.println("语句2");
//运行结果:
语句1
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100
	at exception.TestDemo.main(TestDemo.java:7)

(2)使用 try catch 后

一旦 try 中出现异常, 那么 try 代码块中 从异常处 开始就不会执行, 而是交给 catch 中的代码来执行,catch 执行完毕会继续往下执行。

        int[] arr = {1, 2, 3};
        try {
            System.out.println("语句1");
            System.out.println(arr[100]);//异常出现处
            System.out.println("语句2");
        } catch (ArrayIndexOutOfBoundsException e) {//与上面异常匹配的catch
            
        }
        System.out.println("语句3");
//  语句1
    语句3

(3)使用注意

① 在catch中可以打印出现异常的调用栈,可以得知异常类型,如下:

   e.printStackTrace();

② catch 只能处理对应种类的异常;如下 catch 语句不能捕获到算术异常,因为异常类型不匹配,语句3也不能输出。

      try {
            System.out.println("语句1");
            System.out.println(10/0);//异常处,算术异常
            System.out.println("语句2");
        } catch (ArrayIndexOutOfBoundsException e) {
            // 打印出现异常的调用栈
            e.printStackTrace();
        }
        System.out.println("语句3");
//语句1
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at exception.TestDemo.main(TestDemo.java:8)

③ catch 可以有多个;

一段代码可能会抛出多种不同的异常, 不同的异常有不同的处理方式. 因此可以搭配多个 catch 代码块。

int[] arr = {1, 2, 3};
        try {
            System.out.println("语句1");
            System.out.println(arr[100]);
            System.out.println("语句2");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("这是个数组下标越界异常");
            e.printStackTrace();
        } catch (NullPointerException e) {
            System.out.println("这是个空指针异常");
            e.printStackTrace();
        }
        System.out.println("语句3");
//语句1
这是个数组下标越界异常
语句3
java.lang.ArrayIndexOutOfBoundsException: 100
	at exception.TestDemo.main(TestDemo.java:8)

如果多个异常的处理方式是完全相同, 也可以写成这样

catch (ArrayIndexOutOfBoundsException | NullPointerException e) {
 ...//相同的处理方式
}

④ finally 表示最后的善后工作, 例如释放资源

  • 建议一定不要在finally中 return!!!

如下:无论是否存在异常, finally 中的代码一定都会执行到,保证最终一定会执行到 Scanner 的 close 方法。

int[] arr = {1, 2, 3};
try {
    System.out.println("before");
    arr = null;
    System.out.println(arr[100]);
    System.out.println("after");
} catch (Exception e) {
    e.printStackTrace();
} finally {
    System.out.println("finally code");
}
// 执行结果
before
java.lang.NullPointerException
 at demo02.Test.main(Test.java:12)
finally code

⑤ 使用 try 负责回收资源

刚才的代码可以有一种等价写法, 将 Scanner 对象在 try 的 ( ) 中创建, 就能保证在 try 执行完毕后自动调用 Scanner 的 close 方法

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

⑥如果本方法中没有合适的处理异常的方式, 就会沿着调用栈向上传递,如果向上一直传递都没有合适的方法处理异常, 最终就会交给 JVM 处理, 程序就会异常终止(和我们最开始 未使用 try catch 时是一样的)。

2、异常处理流程

  • 程序先执行 try 中的代码;
  • 如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配;
  • 如果找到匹配的异常类型, 就会执行 catch 中的代码;
  • 如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者;
  • 无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行);
  • 如果上层调用者也没有处理的了异常, 就继续向上传递;
  • 一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止。

3、自定义异常类

 1.自定义异常通常会继承自 Exception 或者 RuntimeException;

2.继承自 Exception 的异常默认是受查异常(编译时);

3.继承自 RuntimeException 的异常默认是非受查异常(运行时)。 

代码示例1:继承 RuntimeException 的异常

class MyException extends RuntimeException{//继承之后就是一个运行时异常
    public MyException(String message) {
        super(message);
    }
}
public class Test {
    public static void main(String[] args) {
        try {
            throw new MyException("exception");
        }catch (MyException e){
            e.printStackTrace();
        }
    }
}

运行结果:

代码示例2:继承 Exception 的异常

     

自定义异常类示例:用户登陆功能.

自定义两个异常,处理用户名出错和密码出错的问题:

接着是处理异常的两种情况:throw是声明异常,try-catch是处理异常,

1、login中声明,在main中进行异常的处理(右图);

2、login中处理异常,main中直接调用(左图)。

       

图左登录示例:

import java.util.Scanner;

class UserException extends Exception {//处理用户名出错
    public UserException(String message) {
        super(message);
    }
}
class PasswordException extends Exception {//处理密码出错
    public PasswordException(String message) {
        super(message);
    }
}
public class Test {
    private static String userName = "August";
    private static String password = "0802";

    public static void login(String userName, String password)  {
        if (!Test.userName.equals(userName)) {
            try {
                throw new UserException("用户名错误");
            } catch (UserException userException) {
                userException.printStackTrace();
            }
        }
        if (!Test.password.equals(password)) {
            try {
                throw new PasswordException("密码错误");
            } catch (PasswordException passwordException) {
                passwordException.printStackTrace();
            }
        }
        if(Test.userName.equals(userName)&&Test.password.equals(password)){
            System.out.println("登陆成功");
        }

    }
    public static void main(String[] args) {
        String name;
        String key;
        Scanner sc=new Scanner(System.in);
        System.out.print("请输入用户名:");
        name=sc.nextLine();
        System.out.print("请输入密码:");
        key=sc.nextLine();
        login(name, key);

    }
}

运行结果示例(三次):

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值