异常、断言与日志

本文介绍了编程中的异常处理,包括非检查型异常如RuntimeException和检查型异常的区别,自定义异常的使用,以及try-catch-finally、try-with-resources和异常抛出的技巧。还提供了如StackWalker和assert的示例,以及日志在记录异常中的应用。
摘要由CSDN通过智能技术生成

异常

编程可能考虑不周,或偶然的外在因素会导致一般性问题,例如用户输入错误、空指针访问、试图读取不存在的文件、网络连接中断等。这时应该做到以下三点:

  • 向用户通知错误

  • 保存所有工作

  • 允许用户妥善地退出程序

异常分类

非检查型异常

RuntimeException

一般指编程时的逻辑错误,编译器无法检测,程序员应该尽量避免。

  1. ArithmeticExecption 算术异常

  2. NullPointerException 空指针异常

  3. ArrayIndexOutOfBoundsException 数组下标越界异常

  4. NumberFormatException 字符串转换为数字异常

  5. ClassCastException 强制转换类型异常

  6. IllegalArgumentException 非法参数异常

派生于Error类的异常

检查型异常

所有其他非检查型异常,如:IOException

自定义异常

自己设计的异常类可用于描述错误信息,实现业务逻辑

步骤

  1. 定义异常类名

  2. 继承RuntimeException(如果继承Exception,则属于编译异常,默认处理机制失效,不建议)

  3. 生成构造器

  4. 使用时new出对象,并输入相关错误信息

异常处理机制

try-catch-finally

try{
    //正常代码(可能有异常)
    //如果发生异常,则剩下的代码不再执行,直接进入catch块
}catch(Exception e){    //捕获到异常,并将其封装成Exception的对象e
    
    //程序员自己编写代码处理
    //若无异常,则不执行
}finally{
    //不管有没有异常都必须执行的代码,前面的return要让路
    //通常将释放资源的代码放在这
    //可以没有finally
}
  • 可以有多个catch,用以捕获不同的异常

  • 细分异常在前,大类异常在后

  • 异常只会匹配一个catch

  • 异常被捕获后,程序不会崩,会继续执行剩下的代码

  • try-finally:不捕获异常,若发生异常,则先执行相应代码再崩掉

try-with-resources

代码见“分析栈轨迹元素”的main方法

throws VS throw

throws

声明类或方法时用throws

  • 将异常抛出,交由调用者(方法)处理;若调用者不catch,则继续上抛。最顶级的调用者是JVM

  • try-catch-finally和throws二选一,运行异常默认选throws

  • 在声明方法时可以用throws声明抛出异常的列表。throws后面的异常类型可以是方法中产生的异常,也可以是其上级异常

  • 子类重写父类方法时,所抛出的异常不能比父类的更通用(子类方法可以抛出更特定的异常,或者根本不抛出)

throw

手动抛出异常对象时用throw

使用异常处理的技巧

1.异常处理不能代替简单的检查/测试

异常处理更耗时,故应只在异常情况下使用异常

2.不要过分细化异常

将正确处理和异常处理分开,避免代码膨胀

3.合理利用异常的层次结构

寻找合适的异常子类,或创建自己的异常类

4.不要压制异常

5.在检查错误时,“苛刻”要比放任好

6.不要羞于传递异常

更高层的方法通常可以更好地通知用户发生了错误,或者放弃不成功的命令

7.使用标准方法报告null指针异常和越界异常

Objects.requireNonNull(Object object);
Objects.checkIndex(int index, int data.length);

8.不要向最终用户显示栈轨迹

预防潜在攻击者

常用方法

Integer.parseInt()

将字符串转化为整数。若字符串的内容不是数字,则抛出NumberFormatException

分析栈轨迹元素

package com.exception;
​
import java.util.Scanner;
​
public class stackTrace
{
    public static void main(String[] args)
    {
        //try-with-resource
        try(Scanner scanner = new Scanner(System.in))
        {
            System.out.println("Enter n:");
            int n = scanner.nextInt();
            factorial(n);
        }
    }
​
    public static int factorial(int n)
    {
        System.out.println("factorial(" + n + ")");
​
        StackWalker walker = StackWalker.getInstance();
        walker.forEach(System.out::println);    //在每个栈帧完成给定动作
​
        //阶乘递归
        if(n > 1)
            n = n*factorial(n-1);
        else if(n <= 0)
            n = 1;
​
        //返回每一次阶乘的结构
        System.out.println("return " + n);
        return n;
    }
}

断言

assert

int[] a = null;
assert a == null;  //true

日志

日志的一个常见用途是记录意料之外的异常。

//调用得到日志记录器
Logger logger = Logger.getLogger("com.myCompany");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值