一、前言
本篇是Android SDK开发艺术探索系列的第二篇文章,介绍了Java/Android中的异常以及在SDK开发中是如何根据异常的特性进行融合设计的思考。注意,本篇并不涉及详细地异常介绍以及异常发生后代码执行地顺序问题,而是基于异常的基本特性与职责边界,结合业务开发的实际情况,试图探讨抛异常与错误码的选择。
系列文章:
Android SDK开发艺术探索(一)开篇与设计
二、异常的概念
首先,我们来认识一下异常:
异常是指在程序运行期间发生的意外事件,它会中断程序(当前方法或作用域)正常执行的流程。
- Checked Exception,比如最常见的IOException,这种异常是指需要调用处显式处理的类型,要么用try catch捕获,要么用 throw 再抛出去;
- Unchecked Exception指的是所有继承自Error(包含自身)或者RuntimeException(包含自身)的类,比如我们常见的NullPointerException就属于这类。这些异常不强制在调用处显式处理,但是也可以通过try
catch处理;- Throwable是Exception和Error的父类。
2.1、APP开发者看待异常的角度
在APP的开发中,似乎我们总是被动的根据编译器的提示编写异常代码,只是为了让编译器通过。为什么编译器跟我们过不去?因为这些提示都是因为对于的操作抛出了Checked类型的异常,需要手动显式进行处理。
在Java开发中,NullPointerException,有部分人简称NPE,是每个开发者都很熟悉的异常,也是让人深恶痛绝的异常。
Java程序员:要么正在debug NPE,要么就在debug NPE的路上。
2.2、SDK开发者看待异常的角度
在SDK开发中,除了要面临APP开发中那些对异常的处理,还需要充分考虑被异常中断了的那些逻辑对整体交互流程产生的影响。
SDK自身的逻辑与APP密不可分,假如因为SDK内部发生的异常,中断了SDK内部流程,而又未告知APP这显然是不可接受的。因此,我们必须谨慎处理SDK内部发生的异常,原则是不应该把异常内部消化,而应该向外抛出,以同样异常的形式或者自定义的返回码。
2.3、Exception or ErrorCode,这是一个问题
在SDK的逻辑设计中,既可以通过异常告知开发者,也可以通过返回码告知开发者,那么如何选择呢?下面我们通过两个例子来探索处理的方式
场景1:在SDK的入参中,需要APP传入手机号码,并校验参数合法性
场景2: 在SDK内部,需要获取APP ID并进行白名单校验
这两种场景下,都需要在SDK的调用流程中处理并反馈,而反馈可以通过返回码,也可以直接抛异常(系统内置异常或自定义异常)孰好孰坏?
笔者认为,在我们实际的SDK开发中,应该通过对相关错误进行分类,来决定采用异常交互还是返回码交互
自定义异常是一种比较“重”的告知方式,因为异常意味着中断。返回码是一种比较“轻”的告知方式,也是最不容易引起开发者重视的告知方式。
常见SDK开发者没有清晰的返回码对照表,亦常见APP开发者没有完整地处理全部返回情形。因此,不可逆转的错误建议采用异常处理机制,直接中断程序执行流程让问题彻底暴露出来,避免发生更多预期之外的错误。
具体概括为:
在与业务有关的逻辑且涉及用户(注意,非开发者,下同)可以重试的部分,应该采用返回码告知开发者,方便其进行后续处理。比如,用户输入了不符合手机号码规则的信息,就可以通过我们的自定义检查逻辑来返回对应的返回码,集成SDK的开发者针对处理即可。
在与业务无关的逻辑且一旦发生用户无法自行处理的部分,可以采用抛出自定义异常的处理方式。比如,SDK开发着对APP的包名校验,这是一个面向开发者的校验逻辑,因此不妨直接抛出自定义异常,坦然让APP崩溃,让开发者从错误堆栈信息中找到问题。这种情形,也许就是Unchecked Exception的使用场景吧。
Exception or ErrorCode,这个问题想必大家也有了一个感性认识,也欢迎耐心看至此处的读者发表自己的见解。
三、结语
本篇主要是回顾了一下异常的概念,探讨了异常在SDK开发中的使用处理问题。总结起来:
- 针对用户造成的无效参数等可重试的逻辑异常,应该通过返回码交互;
- 针对开发者未遵守约定造成的无法重试的专有异常,应该通过直接抛异常退出程序,因为此类型错误不应该让用户接触,也没有继续业务流程的必要;
接下来将继续探讨SDK开发中的初始化设计,包括初始化的几种方式,初始化对APP启动的影响,顺便介绍SDK开发历程中由于误入歧途而了解到的Java双重继承实现。
最后,如果本篇文档对您的开发有所帮助或启发,点赞/关注/分享三连就是对作者持续创作最好的激励,感谢支持!