[java] Best way to handle multiple constructors in Java

I've been wondering what the best (i.e. cleanest/safest/most efficient) way of handling multiple constructors in Java is? Especially when in one or more constructors not all fields are specified:

public class Book
{

    private String title;
    private String isbn;

    public Book()
    {
      //nothing specified!
    }

    public Book(String title)
    {
      //only title!
    }

    ...     

}

What should I do when fields are not specified? I've so far been using default values in the class so that a field is never null, but is that a "good" way of doing things?

This question is related to java constructor field

The answer is


You should always construct a valid and legitimate object; and if you can't using constructor parms, you should use a builder object to create one, only releasing the object from the builder when the object is complete.

On the question of constructor use: I always try to have one base constructor that all others defer to, chaining through with "omitted" parameters to the next logical constructor and ending at the base constructor. So:

class SomeClass
{
SomeClass() {
    this("DefaultA");
    }

SomeClass(String a) {
    this(a,"DefaultB");
    }

SomeClass(String a, String b) {
    myA=a;
    myB=b;
    }
...
}

If this is not possible, then I try to have an private init() method that all constructors defer to.

And keep the number of constructors and parameters small - a max of 5 of each as a guideline.


I would do the following:

public class Book
{
    private final String title;
    private final String isbn;

    public Book(final String t, final String i)
    {
        if(t == null)
        {
            throw new IllegalArgumentException("t cannot be null");
        }

        if(i == null)
        {
            throw new IllegalArgumentException("i cannot be null");
        }

        title = t;
        isbn  = i;
    }
}

I am making the assumption here that:

1) the title will never change (hence title is final) 2) the isbn will never change (hence isbn is final) 3) that it is not valid to have a book without both a title and an isbn.

Consider a Student class:

public class Student
{
    private final StudentID id;
    private String firstName;
    private String lastName;

    public Student(final StudentID i,
                   final String    first,
                   final String    last)
    {
        if(i == null)
        {
            throw new IllegalArgumentException("i cannot be null"); 
        }

        if(first == null)
        {
            throw new IllegalArgumentException("first cannot be null"); 
        }

        if(last == null)
        {
            throw new IllegalArgumentException("last cannot be null"); 
        }

        id        = i;
        firstName = first;
        lastName  = last;
    }
}

There a Student must be created with an id, a first name, and a last name. The student ID can never change, but a persons last and first name can change (get married, changes name due to losing a bet, etc...).

When deciding what constrructors to have you really need to think about what makes sense to have. All to often people add set/get methods because they are taught to - but very often it is a bad idea.

Immutable classes are much better to have (that is classes with final variables) over mutable ones. This book: http://books.google.com/books?id=ZZOiqZQIbRMC&pg=PA97&sig=JgnunNhNb8MYDcx60Kq4IyHUC58#PPP1,M1 (Effective Java) has a good discussion on immutability. Look at items 12 and 13.


Several people have recommended adding a null check. Sometimes that's the right thing to do, but not always. Check out this excellent article showing why you'd skip it.

http://misko.hevery.com/2009/02/09/to-assert-or-not-to-assert/


It might be worth considering the use of a static factory method instead of constructor.

I'm saying instead, but obviously you can't replace the constructor. What you can do, though, is hide the constructor behind a static factory method. This way, we publish the static factory method as a part of the class API but at the same time we hide the constructor making it private or package private.

It's a reasonably simple solution, especially in comparison with the Builder pattern (as seen in Joshua Bloch's Effective Java 2nd Edition – beware, Gang of Four's Design Patterns define a completely different design pattern with the same name, so that might be slightly confusing) that implies creating a nested class, a builder object, etc.

This approach adds an extra layer of abstraction between you and your client, strengthening encapsulation and making changes down the road easier. It also gives you instance-control – since the objects are instantiated inside the class, you and not the client decide when and how these objects are created.

Finally, it makes testing easier – providing a dumb constructor, that just assigns the values to the fields, without performing any logic or validation, it allows you to introduce invalid state into your system to test how it behaves and reacts to that. You won't be able to do that if you're validating data in the constructor.

You can read much more about that in (already mentioned) Joshua Bloch's Effective Java 2nd Edition – it's an important tool in all developer's toolboxes and no wonder it's the subject of the 1st chapter of the book. ;-)

Following your example:

public class Book {

    private static final String DEFAULT_TITLE = "The Importance of Being Ernest";

    private final String title;
    private final String isbn;

    private Book(String title, String isbn) {
        this.title = title;
        this.isbn = isbn;
    }

    public static Book createBook(String title, String isbn) {
        return new Book(title, isbn);
    }

    public static Book createBookWithDefaultTitle(String isbn) {
        return new Book(DEFAULT_TITLE, isbn);
    }

    ...

}

Whichever way you choose, it's a good practice to have one main constructor, that just blindly assigns all the values, even if it's just used by another constructors.


Another consideration, if a field is required or has a limited range, perform the check in the constructor:

public Book(String title)
{
    if (title==null)
        throw new IllegalArgumentException("title can't be null");
    this.title = title;
}

Consider using the Builder pattern. It allows for you to set default values on your parameters and initialize in a clear and concise way. For example:


    Book b = new Book.Builder("Catcher in the Rye").Isbn("12345")
       .Weight("5 pounds").build();

Edit: It also removes the need for multiple constructors with different signatures and is way more readable.


You need to specify what are the class invariants, i.e. properties which will always be true for an instance of the class (for example, the title of a book will never be null, or the size of a dog will always be > 0).

These invariants should be established during construction, and be preserved along the lifetime of the object, which means that methods shall not break the invariants. The constructors can set these invariants either by having compulsory arguments, or by setting default values:

class Book {
    private String title; // not nullable
    private String isbn;  // nullable

    // Here we provide a default value, but we could also skip the 
    // parameterless constructor entirely, to force users of the class to
    // provide a title
    public Book()
    {
        this("Untitled"); 
    }

    public Book(String title) throws IllegalArgumentException
    {
        if (title == null) 
            throw new IllegalArgumentException("Book title can't be null");
        this.title = title;
        // leave isbn without value
    }
    // Constructor with title and isbn
}

However, the choice of these invariants highly depends on the class you're writing, how you'll use it, etc., so there's no definitive answer to your question.


A slightly simplified answer:

public class Book
{
    private final String title;

    public Book(String title)
    {
      this.title = title;
    }

    public Book()
    {
      this("Default Title");
    }

    ...
}

Some general constructor tips:

  • Try to focus all initialization in a single constructor and call it from the other constructors
    • This works well if multiple constructors exist to simulate default parameters
  • Never call a non-final method from a constructor
    • Private methods are final by definition
    • Polymorphism can kill you here; you can end up calling a subclass implementation before the subclass has been initialized
    • If you need "helper" methods, be sure to make them private or final
  • Be explicit in your calls to super()
    • You would be surprised at how many Java programmers don't realize that super() is called even if you don't explicitly write it (assuming you don't have a call to this(...) )
  • Know the order of initialization rules for constructors. It's basically:

    1. this(...) if present (just move to another constructor)
    2. call super(...) [if not explicit, call super() implicitly]
    3. (construct superclass using these rules recursively)
    4. initialize fields via their declarations
    5. run body of current constructor
    6. return to previous constructors (if you had encountered this(...) calls)

The overall flow ends up being:

  • move all the way up the superclass hierarchy to Object
  • while not done
    • init fields
    • run constructor bodies
    • drop down to subclass

For a nice example of evil, try figuring out what the following will print, then run it

package com.javadude.sample;

/** THIS IS REALLY EVIL CODE! BEWARE!!! */
class A {
    private int x = 10;
    public A() {
        init();
    }
    protected void init() {
        x = 20;
    }
    public int getX() {
        return x;
    }
}

class B extends A {
    private int y = 42;
    protected void init() {
        y = getX();
    }
    public int getY() {
        return y;
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B();
        System.out.println("x=" + b.getX());
        System.out.println("y=" + b.getY());
    }
}

I'll add comments describing why the above works as it does... Some of it may be obvious; some is not...


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to constructor

Two constructors Class constructor type in typescript? ReactJS: Warning: setState(...): Cannot update during an existing state transition Inheritance with base class constructor with parameters What is the difference between using constructor vs getInitialState in React / React Native? Getting error: ISO C++ forbids declaration of with no type undefined reference to 'vtable for class' constructor Call asynchronous method in constructor? Purpose of a constructor in Java? __init__() missing 1 required positional argument

Examples related to field

String field value length in mongoDB Javascript - removing undefined fields from an object Set field value with reflection How to add additional fields to form before submit? jquery how to empty input field Add new field to every document in a MongoDB collection How to remove leading and trailing whitespace in a MySQL field? jQuery - Detect value change on hidden input field disable all form elements inside div SSRS Field Expression to change the background color of the Cell