程序出错返回啥? (设计模式)
函数出错应该返回什么
关于函数出错返回类型,我们总结了4种情况,他们分别时错误吗,NULL 值,空对象,异常对象。
1. 返回错误码
2. 返回NULL
在多数的编程语言种,我们用NULL 来标识不存在这种语义,不过网上很多人不建议函数返回NULL 值,这是一种不好的设计思路,
如果某个函数可能返回NULL 值,我们在使用它的时候,忘记了做NULL 值判断,就可能会抛出空指针异常,
如果我们定义了很多返回值可能为NULL 的函数,那么代码种就会充斥这大量的NULL 值得判断,一方面写起来比较繁琐,另一方面和业务耦合在一起,会影响代码得可读性。
public class UserService { private UserRepo userRepo; // 依赖注入 public User getUser(String telephone) { // 如果用户不存在,则返回null return null; } } // 使用函数getUser() User user = userService.getUser("18917718965"); if (user != null) { // 做NULL值判断,否则有可能会报NPE String email = user.getEmail(); if (email != null) { // 做NULL值判断,否则有可能会报NPE String escapedEmail = email.replaceAll("@", "#"); }
那我们是否可以用异常来代替NULL ,在查找用户不存在的时候,让函数paochuUserNotFoundExcption 异常?
我个人觉得,尽管返回了NULL 有很多弊端,但是对于get find selet search query 等单词开头的查询函数来说,数据不存在,并非是一种异常情况,这是一种正常的行为,所以,返回代表不存在语义的NULL 值比返回异常合理。
不过,话说回来,刚刚讲的这个理由,并不是特别有说服力,对于数据不存在的情况,函数到底改用努力了,还是异常,有一个比较重要的参考标准是,看项目种其他类似的查找函数都是如何定义的,只要整个项目遵从统一的约定即可,如果项目从0 开始并没有统一的约定,那你两者中的任何一个都剋。你只需要在函数定义的地方注解清楚。 让调用者清晰的知道数据不存在的时候会返回什么就可以了。
在补充说明一点, 对于查找函数, 处理返沪数据队形之外,有的还会返回下标的位置, 比如java 中的indexOf,用来实现在某个字符中的位置,这个时候null -1 比较合适。
刚刚我们讲到,返回 NULL 值有各种弊端。应对这个问题有一个比较经典的策略,那就是 应用空对象设计模式(Null Object Design Pattern)。关于这个设计模式,我们在后面章 节会详细讲,现在就不展开来讲解了。不过,我们今天来讲两种比较简单、比较特殊的空对 象,那就是空字符串和空集合。
3. 抛出异常
尽管前面讲了很多函数出错的返回数据类型但是,最常用的函数出错的方式就是抛出异常。异常可以携带更多的错误信息,比如函数的调用栈信息,除此之外,异常可以讲正常逻辑和异常逻辑的处理分离开来这样代码的可读性会更高。
异常有运行时异常和编译时异常,
对于运行时异常,我们爱编写代码的时候,可以不用主动的try catch . 编译器在扁你的时候,并不糊检测代码是否有对运行时异常做处理,相反对有编译时异常我们在编写代码的时候,需要主动的try-catch 或者在含义定义中申明,所以运行时异常也叫非受检异常,编译时异常也叫受检异常
什么时候做运行时异常,什么时候编译时异常
对于bug ,以及不可恢复的异常,比如数据库连接失败。即使我们捕获了,也做不了太多的时候,所以我们倾向于非受检异常。对于可以回复的异常,业务异常,比如体现静儿大于余额的异常,哦我们更讲倾向于使用受检的异常,明确的告知调用者需要捕获处理。
我们举一个列子,redis 地址没有设置的时候,我们直接是哦那个默认地址,当redis 地址格式不正确的时候,我们希望程序能fail-fast.这种情况我们当成不可回复异常,直接抛出运行时异常,讲程序终止掉。
实际上,Java啊支持的受检异常一直被人诟病,很多人主张,所有的一次样都是用非受检异常。
因为,有异常处理,代码会显的非常冗余,2,违反了开闭原则,如果某个函数新增了一个异常,所有的调用者都要新增这个异常。 3.影响可读性。
不过非受检异常也有弊端,它的优点就是它的缺点,它过于灵活,我们需要看代码才能知道它抛出了那些异常。 他们并没有哪个更好,哪个供不好。