2

I like the concept of immutability. I also like the concept of no nulls (and if possible also no NullDesignPattern, no NullObjects... as much as possible).

But what about the following scenario:

I have an object User, which has two fields: birthday and dateInLifeMarried (could be any similar field; the important thing is that at first this field is null and changes at some point in object life).

As it's immutable I want both fields to be in the constructor:

public User(birthday, dateInLifeMarried)

Now:

  1. I don't want to pass null to the second parameter
  2. I don't want to add a setter becuase its immutable
  3. i don't want to call the constructor with NullObjectPattern instead of null

Am i just contradicting myself or is there an elegant way to have it which i'm not thinking of?

Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
Jas
  • 14,493
  • 27
  • 97
  • 148
  • Perhaps this can give you some ideas: [Java support default parameters?][1] [1]: http://stackoverflow.com/questions/997482/does-java-support-default-parameter-values – radarbob Feb 21 '13 at 00:37

4 Answers4

13

Well you need to consider what you want the representation to be - not just the constructor signature. I suspect you will need to use a null reference (or at least something similar) for the field. But you could then have two constructors:

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

As the user of an API, I'm not sure that I'd really like that though - I think I'd rather allow marriageDate to be null. In particular, it would be annoying to have to write:

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

Alternatively, as people can get married more than once, you could always take an Iterable<LocalDate> marriageDates, then a never-married user would have an empty sequence :) (You'd need to consider married-then-divorced and married-then-widowed users though. Modelling real life is hard.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    +1 - For the idea of a list of marriage dates with it empty by default. On the topic of modelling life being hard, bigamy/polygamy may be difficult too. – OldCurmudgeon Feb 20 '13 at 10:51
1

What about a second constructor

User(birthday)

that calls the first

this(birthday, null)

?

Michael Simons
  • 4,640
  • 1
  • 27
  • 38
1

Don't just avoid null for the sake of avoiding it. Think about what null means and then use it where it makes sense. The value null represents an unknown, undefined or unspecified value. If you use null consciously you can make your code easier to use and more readable, and at the same time prevent null pointer exceptions.

In your example the marriage date can be unspecified, and therefore you should allow null. However, you don't want the birthday to be unspecified, so you don't allow null there. You could specify the constructors like this:

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...
}

Now you (or anyone that uses your code) can do stuff like this:

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

See? Cleaner code because you empower null instead of avoiding it.

Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
0

You could use inheritance:

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

But this model grows poor and weak in the face of many permutations.

Chris Knight
  • 24,333
  • 24
  • 88
  • 134