亿达科技完成近亿元A轮融资,SIG海纳亚洲独家投资,
06-18
Java异常处理的9个原则在Java编程中,合理有效地处理异常对于保证程序的稳定性和可维护性至关重要。充分发挥异常的优势,可以提高程序的可读性、可靠性、可维护性。
本文基于《Effective Java Exception》章节摘要 9 异常处理原则 仅在异常情况下使用异常。不要使用异常来控制程序流程。
仅在异常情况下使用异常。不主动判断数组下标是否越界。
使用异常控制流程的反例: 代码语言:java copy int[] ints = {1, 2, 3, 4, 5};整数索引 = 0;尝试{ while (true) { System.out.println(ints[index++]); } } catch ( ArrayIndexOutOfBoundsException e) { } 对于可恢复情况使用检查异常,对于编程错误使用运行时异常。种类繁多的异常都是指Throwable,它可以分为三类异常: 检查型异常 CheckException:需要在编译时处理(catch/throw)的异常(如 IOException 等) 运行时异常 RuntimeException:抛出的异常程序运行不正确时(如NullPointerException、非法参数等) Error:运行时虚拟机中发生的错误(如OOM等) 处理检查异常 当你想“捕获”或“抛出”进行处理时恢复”,捕获时可以重试。
如果要自定义非检查异常(编译时不需要处理),则需要对运行时异常代码语言进行子类化: java copy class MyException extends RuntimeException 错误一般不会在代码中进行处理。当发生错误时,需要调查根本原因并修改代码。
API设计如下:对于可恢复的情况抛出检查异常,对于程序错误抛出运行时异常,以及不确定性是否可以从抛出未检查异常中恢复(未检查异常可以视为运行时异常)?如果在最外层(最接近用户)返回用户可以理解的错误消息,请避免不必要地使用检查异常。需要检查异常 手动处理往往可以带来可靠性,但是多个检查异常会让API变得难以使用,调用者将直接面临处理时的痛苦~?? 代码语言:java copy try { } catch (SQLException se) { // 处理数据库相关异常 } catch (IOException ioe) { // 处理文件读写相关异常 } catch (ClassNotFoundException cnfe) { // 处理类未找到异常,该异常可能在加载驱动时出现 }这个时候,为了偷懒的话,可以直接使用Exception进行统一处理~代码语言:java copy try { } catch (Exception e) { //偷懒} 如果不使用catch处理,则抛出受检查的异常直接地。
如果无法恢复,则抛出未经检查的异常。 ,通常是自定义业务异常。
如果呼叫失败,请稍后重试。记得带上异常信息,防止后续打印日志导致异常信息丢失。
代码语言:java copy try {} catch(IOException e) { throw new MyException("请稍后重试", e);} 优先使用标准异常,重用标准异常,例如非法参数、数组下标 out-of - 限制异常。业务开发更多的是重用自定义的业务异常~重用现有的异常。
异常,如果不满足,则自定义一个新的异常,抛出抽象对应的异常。在抽象层面设计方法时,要关注抽象层面的异常,而不是底层具体实现的异常。
ArrayList的迭代器获取下一个元素时,如果越界,会抛出NoSuchElementException 代码语言:java copy public E next() { checkForCommodification(); int i = 光标; if (i >= size) 抛出新的 NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) 抛出新的 ConcurrentModificationException();光标 = i + 1; return (E) elementData[lastRet = i];}AbstractSequentialList在实现get获取元素时捕获NoSuchElementException, throws IndexOutOfBoundsException 代码语言:java copy public E get(int index) { try { return listIterator(index).next(); } } catch (NoSuchElementException exc) { throw new IndexOutOfBoundsException("索引:"+index); } }抽象级别在实现级别捕获NoSuchElementException异常,并抛出根据抽象级别解释的异常IndexOutOfBoundsException。必须记录每个方法引发的所有异常。
如果该方法要抛出异常,请在文档中使用@throw来说明在什么情况下会发生。抛出该异常的代码语言:java copy/** * @throws IOException * 如果发生I/O错误 */避免抛出Exception,Throwable。
想要抛出更具体异常的方法的 throws 仅指示可能抛出的已检查对象。异常@throw应该记录在什么情况下可能抛出检查异常和运行时异常。
异常信息中会保留关键信息。异常中会存储字符串,以保留当时与异常相关的现场信息。
这些信息对于我们的故障排除非常重要。更容易地保留这些关键信息是非常有利的。
自定义异常时可以编写方便排查问题的构造代码语言: java copy public class IndexOutOfBoundsException extends RuntimeException { //lower limit private final int lowerBound; //上限 private Final int upperBound; //当前越界下标 private Final int index; public IndexOutOfBoundsException(int lowerBound, int upperBound, int index) { //关键信息 super(String.format(“下限:%d,上限:%d,索引:%d”,lowerBound,upperBound,index)); this.lowerBound = lowerBound; this.upperBound = upperBound; this.index = 索引; }}例如:越界下标包含上下界以及当前下标位置,可以给出关键信息。尽量保持失败的原子性。
在某些情况下,异常可能会导致失败,从而导致对象的状态不一致,从而导致数据不一致。发生这种情况后,如果使用数据不一致的Object就会导致错误。
在实现方法时,当异常发生并失败时,您应该努力保持原子性。失败的调用方法应该使对象保持先前的状态。
有 5 种方法可以确保原子性: 使用不可变对象:即使失败会导致错误。只要对象没有被创建/替换,该对象就是不可变的。
使用前检查输入参数,提前抛出异常。例如,ArrayList.remove方法应该在获取下标之前检查输入参数。
代码语言:java copy public E remove(int index) { rangeCheck(index); modCount++; //如果不检查输入参数,会抛出下标越界异常,导致modCount数据不一致。 E oldValue = elementData(索引); int numMoved = 大小 - 索引 - 1; if (numMoved > 0) System.arraycopy(elementData, 索引, elementData, 索引, numMoved);元素数据[--大小] = null;返回旧值; }调整处理顺序,使可能导致程序失败的步骤发生在更改数据操作之前(类似于Second类型)。
例如,TreeSet需要内部元素来实现比较器。如果没有实现比较器或者元素类型不同,就会发生类型错误。
转换异常,使得抛出异常并且不执行添加操作来复制源对象。如果发生异常错误,可以检索源对象(或者直接使用复制的对象进行处理)。
对列表进行排序时,会先复制一个数组,然后执行排序代码。语言:java copy default void sort(Comparator super E> c) { //复制Object[] a = this.toArray(); Arrays.sort(a, (比较器) c); //排序后设置ListIterator< E> i = this.listIterator(); for (Object e : a) { i.next(); i.set((E) e); } } 提供回滚操作。
当发生异常错误时使用回滚操作。对象的状态是一致的。
不要忽视异常情况。当异常发生时(catch块为空)不要忽略异常。
代码语言:java copy try{ }catch{ //如果为空则忽略} 忽略异常会导致程序继续执行,可能会导致错误。当发生错误时,排查和处理异常也会变得困难。
您可以打印日志并保留异常堆栈信息。如果要抛出,就不要再打印日志了。
如果你想忽略它,可以写评论来解释原因。仅在异常情况下使用异常。
不要使用异常来编程。过程控制中的广泛异常分为检查异常、运行时异常(非检查异常)和错误。
通常只联系前两者,而后者仅在排除虚拟机错误时才会联系。在运行恢复的情况下会抛出检查异常。
当程序错误或不确定是否允许恢复时,会引发运行时异常。必须处理受检异常,这可以带来可靠性,但过多会导致复杂性。
如果没有捕获已检查的异常,则可以直接抛出它们并重用现有的异常。当标准异常不能满足要求再自定义抽象级方法时,关注抽象级异常而不是具体实现异常。
通过捕获具体的实现异常,然后抛出抽象级别的异常,方法文档需要描述可能抛出的异常。不要抛出异常。
当你想抛出特定的异常并自定义异常时,尽量构造方便排查问题的关键信息。异常失败可能会导致对象状态不一致。
您可以使用不可变对象、检查输入参数、调整执行顺序、复制对象以及实现回滚。等待解决方案来解决问题而忽略异常,会导致程序继续执行并导致错误,导致排查困难。
tive Java,有兴趣的同学可以继续关注。本文的笔记和案例已收录在 Gitee-CaiCaiJava 和 Github-CaiCaiJava 中。
有兴趣的同学可以继续关注stat下。如果有任何疑问,可以在评论区交流。
版权声明:本文内容由互联网用户自发贡献,本站不拥有所有权,不承担相关法律责任。如果发现本站有涉嫌抄袭的内容,欢迎发送邮件 举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。
标签:
相关文章
06-08
06-17
06-18
最新文章
【玩转GPU】ControlNet初学者生存指南
【实战】获取小程序中用户的城市信息(附源码)
包雪雪简单介绍Vue.js:开学
Go进阶:使用Gin框架简单实现服务端渲染
线程池介绍及实际案例分享
JMeter 注释 18 - JMeter 常用配置组件介绍
基于Sentry的大数据权限解决方案
【云+社区年度征文集】GPE监控介绍及使用