Avoiding constructors with parameters of same type

This tiny tip shows how to prevent problems with the usage of your constructors.

Please take a look at the following negative example first:

package demo;

import java.util.Arrays;
import java.util.List;

public class Tip0011 {

 private static class Person {
  private String firstname;
  private String middlename;
  private String surname;

  public Person(String firstname, String middlename, String surname) {
   this.firstname = firstname;
   this.surname = surname;
  }

  public String getFirstname() {
   return firstname;
  }

  public void setFirstname(String firstname) {
   this.firstname = firstname;
  }

  public String getMiddlename() {
   return middlename;
  }

  public void setMiddlename(String middlename) {
   this.middlename = middlename;
  }

  public String getSurname() {
   return surname;
  }

  public void setSurname(String surname) {
   this.surname = surname;
  }

 }

 public static void main(String[] args) {
  List<Person> persons = Arrays.asList(
    new Person("Robert", "C.", "Martin"),
    new Person("John", "R. R.", "Tolkien"));

  persons.forEach(person -> System.out.println(person.getSurname() + ", " + person.getFirstname() + " " + person.getMiddlename()));

 }

}

How easily can a 'Person' be created in the following way:

Person person = new Person("Washington", null, "George");

The same problem often occurs with tabular data as well:

private class TableData {
  public TableData(int nColumns, int nRows) {
  …
  }
   public reset(int nRows, int nColumns) {
  …
  }
}

At least the constructors' parameters where named well.

One possible solution would be, to omit the constructor:

package demo;

import java.util.Arrays;
import java.util.List;

public class Tip0011b {

 private static class Person {
  private String firstname;
  private String middlename;
  private String surname;

  public String getFirstname() {
   return firstname;
  }

  public void setFirstname(String firstname) {
   this.firstname = firstname;
  }

  public String getMiddlename() {
   return middlename;
  }

  public void setMiddlename(String middlename) {
   this.middlename = middlename;
  }

  public String getSurname() {
   return surname;
  }

  public void setSurname(String surname) {
   this.surname = surname;
  }

 }

 public static void main(String[] args) {

  Person uncleBob = new Person();
  uncleBob.setFirstname("Robert");
  uncleBob.setMiddlename("C.");
  uncleBob.setSurname("Martin");

  Person lotr = new Person();
  lotr.setFirstname("John");
  lotr.setMiddlename("R. R.");
  lotr.setSurname("Tolkien");
  List<Person> persons = Arrays.asList(
    uncleBob,
    lotr);

  persons.forEach(person -> System.out.println(person.getSurname() + ", " + person.getFirstname() + " " + person.getMiddlename()));

 }

}

It's clear that the source code is now getting longer and more difficult to read.

From time to time one can find solutions wtith Wrapper -Classes like

public  class Surname {}
public  class Firstname {}
public  class Middlename {}

public class TableDimension {
public int nColumns;
public int nRows;
}

The class TableDimension may not have a constructor with two parameters. Otherwise, the problem would just be postponed.

Overall we will get a lot of classes.

We suggest that you should use the Builder design pattern:

package demo.person;

import java.util.Arrays;
import java.util.List;

public class Person {
 private String firstname; 
 private String middlename;
 private String surname;

 public String getFirstname() {
   return firstname;
  }

  void setFirstname(String firstname) {
   this.firstname = firstname;
  }

  public String getMiddlename() {
   return middlename;
  }

  void setMiddlename(String middlename) {
   this.middlename = middlename;
  }

  public String getSurname() {
   return surname;
  }

  void setSurname(String surname) {
   this.surname = surname;
  }

}
package demo.person;

public class PersonBuilder {
  private Person person = new Person();

  public PersonBuilder firstname(String name) {
   person.setFirstname(name);
   return this;
  }

  public PersonBuilder surname(String name) {
   person.setSurname(name);
   return this;
  }

  public PersonBuilder middlename(String name) {
   person.setMiddlename(name);
   return this;
  }

  public Person build() {
   return person;
  }
 }
package demo;

public class Tip0011c {
 public static void main(String[] args) {

  List<Person> persons = Arrays.asList(
    new PersonBuilder().firstname("Robert")
      .middlename("C.")
      .surname("Martin")
      .build(),
    new PersonBuilder().firstname("John")
      .middlename("R. R.")
      .surname("Tolkien")
      .build());

  persons.forEach(person -> System.out.println(person.getSurname() + ", " + person.getFirstname() + " " + person.getMiddlename()));

 }

}

Please note, that we introduced package demo.person and declared the Setter s package-private .

You can find implementations in which the class gets Person Setter-like methods, which return the Person -Object (this). In this case the class has two responsibilities: data transportation and building. That is ok, but it violates the Single-Responsibilty principle. See also S OLID .