【问题标题】:Does Java have a wrapper type for Null?Java 是否有 Null 的包装器类型?
【发布时间】:2022-01-19 17:53:57
【问题描述】:

我需要区分具有空值的属性和根本不存在的属性。我可以使用地图,但出于性能原因,我尝试使用固定大小的数组。

在数组中,我可以使用null 来指示某个属性何时根本不存在。但是,对于确实存在且值为 null 的属性,是否有一种标准方法可以在数组中表示它?

我想保留一个静态成员,例如

class MyClass {

    private static final Object NULL = new Object();   // null wrapper
    
    private Object[] m_arr = new Object[10];

    // 'i' represents the index of a property in the array

    boolean exists(int i) {
        return m_arr[i] != null;
    }

    Object value(int i) {
        if( !exists(i) ) throw new NullPointerException();   // does not exist
        if( m_arr[i] == NULL ) return null;

        // ... handling for other data types ...
    }
}

表示 null 的另一种可能性可能是枚举?

class MyClass {
      ...
      enum Holder {
            NULL
      }
      ...
      // to check for a null value use m_arr[i] == Holder.NULL
}

【问题讨论】:

  • 没有。您重视的NULL 很好(它也是私有的)。 Optional.empty() 也可能是一个很好的候选者,因为它是一个全局单例(我希望,对吧?)——这样你就可以简单地让你的 NULL 指向 Optional.empty() 而甚至不创建一个愚蠢的新对象。此外,抛出NullPointerException 可能不是一个很好的选择:NoSuchElementException 更适合这里。
  • 听起来你把事情复杂化了。你确定这不是XY Problem
  • 无法理解这个陈述,因为“存在”和“空”是相反的......“但是,对于确实存在且为空的属性......”
  • 只要保持一致(“nulling code”在哪里??),随心所欲! :):) 可能一个“地图”或(至少)两个数组(一个带有“属性”,一个带有“值”)会更好......适合(无论您尝试完成什么)
  • 没关系:OP 可以看到的差异就像 JavaScript 中 null 之间的差异(我们知道它没有价值,比如 OP 的 Optinal.empty()NULL)和 @987654334 @(我们根本不知道它是什么,因为它可能也不存在,null 用于 OP)。 OP 实际上是在做一个标记对象,表示保存在 Optional.of 盒子上的空值对象(只要它是私有实现就可以了)。

标签: java null wrapper


【解决方案1】:

Java 是否有 Null 的包装器类型?

没有。

但是我如何解决这个问题意味着您不需要包装器:只需维护一组表示“显式”空值的索引。

class MyClass {
    private Object[] m_arr = new Object[10];
    private Set<Integer> presentButNullIndices = new HashSet<>();

    // 'i' represents the index of a property in the array

    Object value(int i) {
        if (m_arr[i] == null && !presentButNullIndices.contains(i)) {
            throw new NullPointerException();
        }
        // ... handling for other data types ...
    }

    // just an example of how to maintain the set
    void insert(int i, Object value) {
        if (value == null) {
             presentButNullIndices.add(i);
        }
        else {
             presentButNullIndices.remove(i);
        }
        m_arr[i] = value;
    }
}

在最坏的情况下,空间复杂度会翻倍,但这仅适用于大量使用空值的客户端。 contains 在集合上是 O(1)

我也会考虑首先禁止空值。一些地图实现可以做到这一点,而我从未发现自己处于我希望他们没有做到的情况。

【讨论】:

    【解决方案2】:

    Apache commons ObjectUtils 有一个 NULL 字段用于此目的,如果您不想定义自己的。

    【讨论】:

    • 不知道这个字段。谢谢!
    【解决方案3】:

    使用Optional,例如

    private Optional<String> myField;
    

    共有三种状态。以下是处理它们的方法:

    myfield = Optional.of("foo"); // attribute has non-null value
    myfield = Optional.empty();   // attribute is present, but null
    myfield = null;               // attribute is not present
    

    Jackson(即 Spring boot)json 反序列化支持开箱即用,这对于处理需要区分指定但 null 和未指定的 json 键的 PATCH 方法非常方便。

    【讨论】:

    • Optional 的设计者不鼓励Optional 类型的字段和参数。并且Optional 的集合值得所有它肯定会收到的嘲笑。空对象模式是更好的选择。
    • @erickson Optional 适用于所有情况,其意图很明确。我已经在一家大型银行的 PATCH 端点的 DTO 中实现了可选字段,它运行完美,并通过了我们可以想象的所有功能和性能。
    • 这是对可选 IMO 的滥用。大多数开发人员的期望是对 Optional 的引用本质上是不可可为空的。在调用 Optional 方法之前,您永远不必检查对 Optional 的引用是否为 null。
    • @erickson 我现在明白了一点。我最初只是回应你的评论。由于我已经说明的原因,我仍然强烈不同意“不要将Optional 用作字段或集合中”的建议。但是,是的,我倾向于同意您的观点,即包含 nullOptionalOptional 本身就是 null 是可憎的。你在这方面提出了一个很好的观点。 “不要同时使用Optionalnull”是一个合理的指导方针。
    • @Michael 你说得很好——必须检查 Optional 是否为空是不直观的; Optional 的目的是不必进行空检查。为了公平起见,当我使用它时,我编写了一个实用方法来用补丁有效负载覆盖存储的对象,尊重字段的 3 种状态。完成该操作后,DTO 将被丢弃。这种方法包含一个地方的怪异之处,该地方经过了彻底的单元测试,并且在项目其他地方工作的开发人员没有接触到这种非常规的 Optional 用法。
    【解决方案4】:

    不...但是,Java 现在有Optional,可以视为相同。您还可以创建一个类来表示一个空对象,这可以按照“空对象模式”来完成。我在博客中写过这个:https://www.professorfontanez.com/2020/04/the-beauty-of-null-object-pattern.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      相关资源
      最近更新 更多