Constructor rules: initialize fields only in constructor

I saw this situation in every project in every company I worked for. People initialize some fields in a constructor, some leave as default and some are assigned at the moment of declaration. While such code works it’s far from being optimal. It puts unnecessary mental burden on developers because it is unreadable and inconsistent.

Let’s see an example class which exposes the problem:

 1public class Train {
 2  private int seats;
 3  private int carriages = 0;
 4  private final Engine engine;
 5  private final Manufacturer manufacturer;
 6  
 7  public Train(Engine engine, Manufacturer manufacturer) {
 8    this.engine = engine;
 9    this.manufacturer = manufacturer;
10  }
11  
12  //other methods
13}

At first glance it seems there’s nothing wrong with the class’ functionality. All fields are initialized one way or another and objects of this class will be ready to use after construction. They will also be consistently initialized so there are no logical errors also. But I’d argue this code should look much better.

To default or not to default

Java has quite sensible default values for fields - numbers are initialized to 0, booleans to false, objects to null. If we want to initialize them with any other value we must do so explicitly. A lot of developers would rely on those defaults and never initialize field ??? And if we’re talking about the field declaration I agree! Let’s see how the class would look like now:

 1public class Train {
 2  private int seats;
 3  private int carriages;
 4  private final Engine engine;
 5  private final Manufacturer manufacturer;
 6  
 7  public Train(Engine engine, Manufacturer manufacturer) {
 8    this.engine = engine;
 9    this.manufacturer = manufacturer;
10  }
11  //other methods
12}