《阿里巴巴 Java 开发手册 》二、异常日志

本贴最后更新于 2227 天前,其中的信息可能已经时移俗易

(一)异常处理  

1.【强制】Java 类库中定义的一类 RuntimeException可以通过预先检查进行规避,而不应该通过 catch 来处理

比如:IndexOutOfBoundsException,NullPointerException 等等。  

说明:无法通过预检查的异常除外,如在解析一个外部传来的字符串形式数字时,通过 catch NumberFormatException 来实现。  

正例:if (obj != null) {...}  

反例:try { obj.method() } catch (NullPointerException e) {...}  

2.【强制】异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。  

3.【强制】对大段代码进行 try-catch,这是不负责任的表现。

catch 时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的 catch 尽可能进行区分异常类型,再做对应的异常处理。  

4.【强制】捕获异常是为了处理它

捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。  

5.【强制】有 try块放到了事务代码中,catch异常后,如果需要回滚事务,一定要注意手动回滚事务。  

6.【强制】finally块必须对资源对象、流对象进行关闭,有异常也要做 try-catch。  

说明:如果 JDK7 及以上,可以使用 try-with-resources 方式。  

7.【强制】不能在 finally块中使用 return

finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 return 语句。  

8.【强制】捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛异常的父类。  

说明:如果预期对方抛的是绣球,实际接到的是铅球,就会产生意外情况。  

9.【推荐】方法的返回值可以为 null

方法的返回值可以为 null,不强制返回空集合,或者空对象等,必须添加注释充分说明什么情况下会返回 null 值。调用方需要进行 null 判断防止 NPE 问题。  

说明:本手册明确防止 NPE 是调用者的责任。即使被调用方法返回空集合或者空对象,对调用者来说,也并非高枕无忧,必须考虑到远程调用失败、序列化失败、运行时异常等场景返回 null 的情况。  

10.【推荐】防止 NPE,是程序员的基本修养,注意 NPE产生的场景:  

1)返回类型为基本数据类型,return 包装数据类型的对象时,自动拆箱有可能产生 NPE。  

反例:public int f() { return Integer 对象}, 如果为 null,自动解箱抛 NPE。 

2) 数据库的查询结果可能为 null。  

3) 集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null。  

4) 远程调用返回对象时,一律要求进行空指针判断,防止 NPE。  

5) 对于 Session 中获取的数据,建议 NPE 检查,避免空指针。  

6) 级联调用 obj.getA().getB().getC();一连串调用,易产生 NPE。  

正例:使用 JDK8 的 Optional 类来防止 NPE 问题。  

11.【推荐】定义时区分 unchecked/checked 异常

定义时区分 unchecked/checked 异常,避免直接抛出 newRuntimeException(),更不允许抛出 Exception 或者 Throwable,应使用有业务含义的自定义异常。推荐业界已定义过的自定义异常,如:DAOException / ServiceException 等。  

12.【参考】在代码中使用“抛异常”还是“返回错误码”

对于公司外的 http/api 开放接口必须使用“错误码”;而应用内部推荐异常抛出;跨应用间 RPC 调用优先考虑使用 Result 方式,封装 isSuccess()方法、“错误码”、“错误简短信息”。  

说明:关于 RPC 方法返回方式使用 Result 方式的理由:  

1)使用抛异常返回方式,调用方如果没有捕获到就会产生运行时错误。  

2)如果不加栈信息,只是 new 自定义异常,加入自己的理解的 error message,对于调用端解决问题的帮助不会太多。如果加了栈信息,在频繁调用出错的情况下,数据序列化和传输的性能损耗也是问题。  

13.【参考】避免出现重复的代码(Don’t Repeat Yourself),即 DRY原则。  

说明:随意复制和粘贴代码,必然会导致代码的重复,在以后需要修改时,需要修改所有的副本,容易遗漏。必要时抽取共性方法,或者抽象公共类,甚至是组件化。  

正例:一个类中有多个 public 方法,都需要进行数行相同的参数校验操作,这个时候请抽取:  

private boolean checkParam(DTO dto) {...}  

(二)日志规约  

1.【强制】应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架SLF4J中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。  

import org.slf4j.Logger;  

import org.slf4j.LoggerFactory;  

private static final Logger logger = LoggerFactory.getLogger(Abc.class);  

2.【强制】日志文件推荐至少保存 15天,因为有些异常具备以“周”为频次发生的特点。  

3.【强制】应用中的扩展日志(如打点、临时监控、访问日志等)命名方式:  

appName_logType_logName.log。

logType:日志类型,推荐分类有 stats/desc/monitor/visit 等;

logName:日志描述。这种命名的好处:通过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。  

正例:mppserver 应用中单独监控时区转换异常,如:  

mppserver_monitor_timeZoneConvert.log  

说明:推荐对日志进行分类,如将错误日志和业务日志分开存放,便于开发人员查看,也便于通过日志对系统进行及时监控。  

4.【强制】对 trace/debug/info级别的日志输出,必须使用条件输出形式或者使用占位符的方式。  

说明:logger.debug("Processing trade with id:"+id +"and symbol:"+symbol);  

如果日志级别是 warn,上述日志不会打印,但是会执行字符串拼接操作,如果 symbol 是对象,会执行 toString()方法,浪费了系统资源,执行了上述操作,最终日志却没有打印。  

正例:(条件)  

if (logger.isDebugEnabled()) {  

logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);  

}

正例:(占位符)  

logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);  

5.【强制】避免重复打印日志,浪费磁盘空间,务必在 log4j.xml中设置 additivity=false。  

正例:  

6.【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字 throws往上抛出。  

正例:logger.error(各类参数或者对象 toString + "_" + e.getMessage(), e);  

7.【推荐】谨慎地记录日志。

生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘  撑爆,并记得及时删除这些观察日志。  

说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。记录日志时请  

思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?  

8.【参考】可以使用 warn日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适从。

注意日志输出的级别,error 级别只记录系统逻辑出错、异常等重要的错误信息。如非必要,请不要在此场景打出 error 级别。

  • 阿里巴巴

    阿里巴巴网络技术有限公司(简称:阿里巴巴集团)是以曾担任英语教师的马云为首的 18 人,于 1999 年在中国杭州创立,他们相信互联网能够创造公平的竞争环境,让小企业通过创新与科技扩展业务,并在参与国内或全球市场竞争时处于更有利的位置。

    43 引用 • 221 回帖 • 159 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3170 引用 • 8209 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

    4 引用 • 3 回帖 • 18 关注
  • App

    App(应用程序,Application 的缩写)一般指手机软件。

    91 引用 • 383 回帖
  • Kafka

    Kafka 是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是现代系统中许多功能的基础。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。

    35 引用 • 35 回帖 • 5 关注
  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    131 引用 • 1114 回帖 • 143 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    7474 引用 • 33980 回帖 • 197 关注
  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    209 引用 • 2031 回帖
  • Sym

    Sym 是一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)系统平台。

    下一代的社区系统,为未来而构建

    524 引用 • 4599 回帖 • 700 关注
  • CentOS

    CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux 依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。两者的不同在于 CentOS 并不包含封闭源代码软件。

    238 引用 • 224 回帖
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 623 关注
  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    23 引用 • 32 回帖
  • Google

    Google(Google Inc.,NASDAQ:GOOG)是一家美国上市公司(公有股份公司),于 1998 年 9 月 7 日以私有股份公司的形式创立,设计并管理一个互联网搜索引擎。Google 公司的总部称作“Googleplex”,它位于加利福尼亚山景城。Google 目前被公认为是全球规模最大的搜索引擎,它提供了简单易用的免费服务。不作恶(Don't be evil)是谷歌公司的一项非正式的公司口号。

    49 引用 • 192 回帖
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    36 引用 • 37 回帖 • 526 关注
  • Oracle

    Oracle(甲骨文)公司,全称甲骨文股份有限公司(甲骨文软件系统有限公司),是全球最大的企业级软件公司,总部位于美国加利福尼亚州的红木滩。1989 年正式进入中国市场。2013 年,甲骨文已超越 IBM,成为继 Microsoft 后全球第二大软件公司。

    104 引用 • 126 回帖 • 426 关注
  • Linux

    Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 Unix 的多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 Unix 工具软件、应用程序和网络协议,并支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

    927 引用 • 937 回帖 • 1 关注
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    164 引用 • 492 回帖
  • 快应用

    快应用 是基于手机硬件平台的新型应用形态;标准是由主流手机厂商组成的快应用联盟联合制定;快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台;以平台化的生态模式对个人开发者和企业开发者全品类开放。

    15 引用 • 127 回帖 • 4 关注
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 417 关注
  • Shell

    Shell 脚本与 Windows/Dos 下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比 Windows 下的批处理更强大,比用其他编程程序编辑的程序效率更高,因为它使用了 Linux/Unix 下的命令。

    122 引用 • 73 回帖
  • Sphinx

    Sphinx 是一个基于 SQL 的全文检索引擎,可以结合 MySQL、PostgreSQL 做全文搜索,它可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索。

    1 引用 • 196 关注
  • 前端

    前端技术一般分为前端设计和前端开发,前端设计可以理解为网站的视觉设计,前端开发则是网站的前台代码实现,包括 HTML、CSS 以及 JavaScript 等。

    247 引用 • 1347 回帖
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖
  • 微信

    腾讯公司 2011 年 1 月 21 日推出的一款手机通讯软件。用户可以通过摇一摇、搜索号码、扫描二维码等添加好友和关注公众平台,同时可以将自己看到的精彩内容分享到微信朋友圈。

    130 引用 • 793 回帖
  • 书籍

    宋真宗赵恒曾经说过:“书中自有黄金屋,书中自有颜如玉。”

    77 引用 • 390 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3170 引用 • 8209 回帖
  • Notion

    Notion - The all-in-one workspace for your notes, tasks, wikis, and databases.

    5 引用 • 26 回帖
  • PostgreSQL

    PostgreSQL 是一款功能强大的企业级数据库系统,在 BSD 开源许可证下发布。

    22 引用 • 22 回帖 • 2 关注
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖 • 1 关注