【问题标题】:java null /empty-list return vs throw exception in code rethinking best practices in rest worldjava null /empty-list return vs throw exception in code rethinking best practice in rest world
【发布时间】:2016-06-10 19:15:03
【问题描述】:

重新思考具有 null /empty 处理场景的设计模式

类似下面的函数

  function(customerid){
      customer=findcustomerbyId(customerid)-->findcustomer
      list<Transactions> accounts=getNewTransactions(customer)-->findtransactions
      foreach{if(transaction.isGasTransaction()){send(event)..if()sendevent()}}-->send events
    }

现在的问题是,每当我们期望一个函数的返回值时,它应该是一个空值吗?或者如果数据库找不到值应该抛出异常。

抛出空值会迫使您编写代码来处理空值/空列表。这将增加 if-else 块,并且您的 junit 案例也会增加(成正比)。抛出异常将迫使您采用不同的编程风格,并且您需要一些预期异常的测试用例。

类似 spring-jdbc 模板 queryForObject 如果 db 中没有值则抛出异常。(预期为 1 但得到 0)

这里的正确方向是什么。更多例外?或像其他 null 替代品一样使用 Optionsljava-8 或使用 nulls?

我们可以在不同的场景中平衡这些风格:)

所以对于一个 rest-api 项目,我认为抛出异常会很好,如果你有一个全局异常处理程序(如控制器建议)的原因,你可以在你的代码中处理异常而不用担心方法堆栈处理空检查/空检查,因为异常在通知级别被捕获并相应地传播。

***这是思考一个方向而不是讨论哪个最好*****

【问题讨论】:

  • 您的问题似乎是一个风格或最佳实践问题。设计模式是完全不同的、更具体的东西。
  • 是的,我同意风格与最佳实践,我确实在这个项目中选择了例外风格,但是新的 ppl 加入呢,这是一个最佳实践,让 ppl 很容易理解。正如我解释的那样,在我的场景中不需要 try catch,因为我有一个全局异常处理程序来返回自定义的 e.message 作为服务的响应。以便稍后进行调试
  • 在我看来,您想使用异常来进行流量控制/信令。但是,恕我直言,异常应该按原样使用:异常,表示出现问题。如果在测试期间缺少数据意味着确实有问题,那么在我看来抛出异常是可以的。但通常您应该重新审视您的设计,并考虑在什么情况下应该返回哪些方法,尤其是 null 值对您意味着什么。在某些情况下,空对象也可以。想想什么会减少对代码的污染。同样使用全局异常处理程序看起来像是一种设计气味
  • 这是一项严肃的基础工作,需要深思熟虑:P 在我的工作场所,我们也在为此苦苦挣扎,因为人们对此有不同的看法。如果您在团队中编程:与他们交谈并讨论每种方法的利弊。做出决定并坚持下去!如果您认为在任何地方使用异常都可以,那没关系,只要您不中途改变主意并开始使用空对象即可。
  • 我明白了这一点,这在我的团队中进行了长时间的辩论。我倾向于例外,因为我的这种情况没有意义。使用空数据作为逻辑中的下一步将不会执行如果有空值。(90% 的时间 ppl 不期望空值,例如:- 带有 id 的 getCustomer,验证信用卡密码等)。任何空值检查都是好的,但不是必需的,因为这只是为了增加 junit 覆盖率和如果某些值为空,服务调用将不会达到此级别

标签: java design-patterns junit nullpointerexception


【解决方案1】:

问问自己“当有人试图访问一个不存在的条目时,我希望发生什么?”

如果您想向用户显示一条消息,您可以抛出一个已处理的Exception 以通知下一级出现了问题,从而允许您显示某种错误消息在catch 块中。

如果您不想发生任何事情,请使用 null 对象,这样您的线程就不会崩溃。用户不会被告知为什么什么都没发生,这被认为是不好的做法。

如果缺少条目导致程序无法正常运行,将使用Runtime 异常。 NullPointerException 不详细。 NPE 可能发生在忘记初始化变量(通常在现代语言的编译时捕获)而不是访问某种数据结构中不存在的元素(通常在现代语言中导致 NoSuchElementException),所以最好将 NPE 包装在另一个异常中,其中包含有关该问题的更多信息。

【讨论】:

  • 返回Optional怎么样?
  • 是的,这就是为什么我有一个定制的异常处理程序来捕获这些并转换为对用户有意义的东西。 null 不好:) 并且 optional 并不能简单地解决,因为那样你就会遇到 null 处理场景的另一面。但是是的,可选仍然比 null 好
  • @dnault Optional 如果他想在不可用的情况下创建丢失的数据,这将很有用。向用户显示错误消息不应该是数据处理程序的责任 - 它应该是负责数据处理程序的对象(它可能会在链上更进一步传播)或错误处理程序的责任。在我看来,Optional 损害了模块化。在这种情况下,最好的办法是抛出某种异常,让更高层知道存在问题,这样它就可以添加数据、显示数据或将其发送到某个错误处理程序。
  • 是的,谢谢你帮了很多忙。我也在做同样的事情。抛出运行时异常,因为无论如何它是一个休息服务,并且 ppl 调用它不在乎,除非,如果输入中存在问题,无论哪种情况结束,我都会查看日志并查看发生了什么。大多数错误应该在开发期间解决(集成/单元测试)我不想处理 n-null 检查以获得 1 个结果。(处理 if/else 块只会增加看起来难看的测试):)
【解决方案2】:

如果数据库找不到值 - 这是灾难还是正常情况?考虑以下两种情况:

public void createUser(String userName){
boolean thisUsernameIsUsed = checkIfUsernameAlreadyExistsSQLRequest(userName);
    if(!thisUsernameIsUsed){
        //create a new user
    }
}

public String whoMessedUpTheDatabase(database database){
    return database.getLastEditedBySQLRequest();
}

在第一种情况下,数据库中没有用户名是可以的。所以,使用空值。在第二种情况下,我们希望获得最后一个编辑人的姓名,因此 null 确实是一个例外。

【讨论】:

  • 布尔标志将返回真/假,因此不为空。并且还创建用户类型的操作,如果它不能,总是抛出异常,但我明白了,如果你想发生其他事情,你说如果为 null,则返回 null,否则抛出异常。但我觉得 null 是一个错误,以某种方式在编程语言中结束
  • 当然,布尔值是真/假,不是异常,不是空值。我的观点是——如果空白回复是一场戏剧——使用例外。如果没问题 - 返回 null。
猜你喜欢
  • 2022-12-02
  • 2017-10-02
  • 2022-12-27
  • 2023-03-26
  • 2012-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-30
相关资源
最近更新 更多