【问题标题】:StringUtils vs != nullStringUtils vs != null
【发布时间】:2018-09-10 18:06:08
【问题描述】:

我经常遇到非常不同的字符串验证,我们都知道有新的库,例如 StringUtils。有人可以解释为什么StringUtils.isNotBlank(paymentTerm) 或多或少比paymentTerm != null 更受欢迎吗?

【问题讨论】:

  • 您指的是哪个StringUtils,为什么您认为这是一个很好的实现方式?
  • 例如因为StringUtils.isNotBlank 并不总是可用,它是一些 外部库。
  • 查看StringUtils.isNotBlank 的文档,它涵盖的不仅仅是空值。 Here is a link to the documentation
  • @Alexander:像“我仍然面对”和“老规矩”这样的表达意味着你认为编写像!= null 这样的代码本质上是错误的。以我的经验,"X sucks, amirite?" 形式的问题不是展开讨论的好方法:它们会引起情绪化、基于意见的回应,而不是事实答案,而且它们往往表明你对验证自己的观点更感兴趣而不是实际学习——这实际上也会阻止那些有不同意见的人提供他们的观点。

标签: java string validation nullpointerexception


【解决方案1】:

我觉得这个问题的前提已经不正确了。您不必在大多数地方检查空字符串——事实上,我认为您应该尽可能避免使用null,但尤其是,当存在另一个非空标记值时。而String已经有了一个很好的“空”值:空字符串("")!

如果""" " 需要折叠成相同的值,那么标准库中已经有一个非常好的方法:.trim()。但是,.trim() 作为String 上的实例方法,仅适用于非空字符串。这不一定是坏事!

如果null"" 对您来说意味着不同的东西,那么我认为您的数据模型太复杂了,您应该使用其他包装类而不是使用@987654332 @ 直接地。如果null"" 表示相同的意思,那么您应该选择其中一个,并始终如一地使用它。这可能意味着需要进行一些!= null 检查,但如果您发现自己在整个代码库中经常 需要isNullOrEmptyisNotBlank 辅助函数,我会说这是代码异味,并且您真的应该致力于解决底层数据模型问题,而不是担心一个微小的辅助函数。

这是什么意思?在Avoiding != null statements 问题中,投票最多的答案指出,实际上只有两种类型的值可以为 null:(1) null 是有效值,或者 (2) null 不是有效值价值。

案例 (2) 不是很有趣。 Null 不是一个有效值,所以我们不应该尝试处理它。如果有的话,我们只要遇到它就抛出一个异常。否则我们忽略它,让NullPointerException“自然”发生。它不应该为 null,因此根据定义,找到 null 是一种例外情况。

如果 null 一个有效值,那么它意味着 null 具有语义。这很可能意味着一个值“不存在”或“无效”。这里有两种子情况:(1a) null 表示与空字符串相同的意思,或者 (1b) 表示不同的意思。

如果您有案例 (1b),那么我认为您需要在域模型中添加一个新实体。例如,您可以创建一个像PaymentTerm 这样的类,它具有单独的.isValid().isPresent() 方法,以及一个.asString() 访问器来获取字符串值(如果存在)。 (创建PaymentTerm 类有很多可能的方法,有很多可能的权衡:重点不是您需要这种特定的形式,而是您需要一些东西 而不是原始的@ 987654345@,你可以挂起方法,因为这个东西现在是你领域模型中的一流实体。)

如果你有 case (1a),那么 null 和空字符串在语义上都是同一个意思。但是它们在语法上是非常不同的!空字符串已经有一个实例方法来检查它(.isEmpty()),并且可以安全地存储、传递、与其他字符串相比等。

所以情况 (1a) 有两种可能的解决方案:(1a.1) 你传递 null 和空字符串,并且在任何地方你都必须检查,或者 (1a.2) 你将 null 标准化为空字符串最快的机会,然后将 null 视为无效值,并在任何地方使用空字符串。根据您的输入格式,您甚至可以“免费”获得此行为(例如,空文本框自然会将空字符串作为值,而不是 null)。

我的论点是案例 (1a.1) 是代码异味。而不是同时传递 null 和空字符串,并经常检查两者(手动或使用 isNullOrEmptyisNotBlank 之类的方法),您应该尝试进入 case (2) 或 case (1a.2) .

请注意,这个答案实际上意味着 isNotBlank!= null 都不是最佳的!在一个结构良好的代码库中,您应该努力避免这两种情况,但我倾向于认为您应该更努力地避免像 isNotBlank 这样的东西。

也就是说,如何检查 null 或空字符串并不是非常重要。无论如何,JIT 几乎肯定会内联检查,并且在许多情况下,如果它可以用另一种方式证明零安全性,窥视孔优化器将完全忽略它们。要考虑的更重要的事情是null 在你的程序中是否是一个有效的值,如果是,它在语义上的含义意味着一个值是否为空。

【讨论】:

  • 您能否详细说明您认为这是代码异味的原因?
【解决方案2】:

您的问题是有效的,但您的提问方式可以更有礼貌。

答案是,视情况而定。 StringUtils 提供了很多不错的方法。 isNotBlank() 检查 null、empty 和一个或多个空格,它节省了一定量的手动检查。它还可以简化单元测试。另一方面,您的商店可能不想导入和依赖外部库。

一般来说,正确的方式,尤其是当你刚开始的时候,都是一样的。礼貌地询问技术负责人的意见,然后接受。

【讨论】:

  • 已编辑。谢谢。
  • 作为一个“前辈”,我完全没有觉得这有什么不礼貌的地方。只是说。
【解决方案3】:

paymentTerm != nullStringUtils.isNotBlank(paymentTerm) 不执行相同的操作。
如果您想检查String 对象的非空性,您不想使用isNotBlank(),而是使用!= null。所以使用!= null 可能仍然有意义。
请注意,作为替代方案,您也可以使用Object.nonNull(Object),但它通常更冗长(但在完全有意义的方法参考中:Object::nonNull)。

关于我们应该测试!= ""!= trimmed ""还是只测试!= null,这是一个需求问题。
即使isNotBlank() 包含!= null,您也只能在必需 的情况下使用它,因为执行更多必需的检查会误导代码。


以下是一些简单的示例,您可以从中看出每种方式都有其含义,并且您必须以某种方式使用它们(或不使用它们),以使它们的阅读自然而愉快。

1) 您想检查String 的长度大小。

if (myString != null && myString.length() == 8)

是你需要的。
isNotBlank() 做这件事很冗长,并且传达了两个非常具体的东西(不是空白和最小长度),而只有最后一个很重要。

if (StringUtils.isNotBlank(myString) && myString.length() == 8)

2) 您想检查String 是否包含一些字符。

if (myString != null && myString.contains("word"))

仍然是您所需要的。

if (String.isNotBlank(myString) && myString.contains("word"))  

使用isNotBlank() 执行此操作仍显示为噪音。

3) 您想检查String 是否等于另一个不能为null 或编译时常量表达式的值。

你想直接写:

if ("word".equals(myString))

4) 那么你想什么时候使用isNotBlank() 呢?
仅当您需要检查 String 不为空 并且 不只包含空格 (" ") 字符时。

if (StringUtils.isNotBlank("word"))

【讨论】:

    猜你喜欢
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多