有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java避免空值、不变性、对象状态

我喜欢不变性的概念。我也喜欢无Null的概念(如果可能的话,也可以不使用NullDesignPattern,不使用NullObjects…尽可能多)

但是下面的场景呢

我有一个对象User,它有两个字段:birthdaydateInLifeMarried(可以是任何类似的字段;重要的是,一开始这个字段是null,并且在对象生命中的某个时刻发生变化)

因为它是不可变的,所以我希望两个字段都在构造函数中:

public User(birthday, dateInLifeMarried)

现在:

  1. 我不想把null传递给第二个参数
  2. 我不想添加setter,因为它是不变的
  3. 我不想用NullObjectPattern而不是null调用构造函数

我是在自相矛盾,还是有一种优雅的方式让我拥有自己没有想到的东西


共 (4) 个答案

  1. # 1 楼答案

    不要只是为了避免空值而避免空值。想想null的意思,然后在有意义的地方使用它。值null表示未知未定义未指定值。如果你有意识地使用null,你可以使你的代码更容易使用,更可读,同时防止null指针异常

    在您的示例中,结婚日期可以是未指定的,因此您应该允许null。但是,您不希望未指定生日,因此不允许在那里使用null。可以这样指定构造函数:

    User(LocalDate birthday)
    {
        this(birthday, null);
        // That's it! Nothing more to do here.
    }
    
    User(LocalDate birthday, LocalDate marriageDate)
    {
        if (birthday == null)
            throw new IllegalArgumentException();
        // Use it...
    }
    

    现在你(或任何使用你的代码的人)可以做这样的事情:

    LocalDate marriageDate = getMarriageDateOrNull();
    User user = new User(birthday, marriageDate);
    

    看到了吗?更干净的代码,因为你增强了你的能力,而不是回避它

  2. # 2 楼答案

    第二个构造函数呢

    User(birthday)
    

    这就叫第一次

    this(birthday, null)
    

    ?

  3. # 3 楼答案

    <>你需要考虑你想表达的是什么——而不仅仅是构造函数签名。我怀疑您需要为字段使用空引用(或至少类似的引用)。但是你可以有两个构造器:

    User(birthday)               // Unmarried user
    User(birthday, marriageDate) // Married user; marriageDate must not be null
    

    作为一个API的用户,我不确定我是否真的喜欢它——我想我宁愿允许marriageDate为空。尤其是,必须写以下内容会让人恼火:

    LocalDate marriageDate = getMarriageDateOrNull();
    User user = marriageDate == null ? new User(birthday)
                                     : new User(birthday, marriageDate);
    

    或者,由于人们可以结婚不止一次,所以您可以始终使用Iterable<LocalDate> marriageDates,那么从未结婚的用户将有一个空序列:) (你需要考虑结婚,然后离婚,结婚,然后寡居的用户。模拟现实生活是困难的。)p>

  4. # 4 楼答案

    您可以使用继承:

    public abstract class User{}
    public class UnMarriedUser extends User{}
    public class MarriedUser extends User{}
    

    但是,面对许多排列,这种模式变得越来越糟糕和脆弱