DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Building Scalable Real-Time Apps with AstraDB and Vaadin
Register Now

Trending

  • Getting Started With the YugabyteDB Managed REST API
  • Top 10 Pillars of Zero Trust Networks
  • Operator Overloading in Java
  • How To Approach Java, Databases, and SQL [Video]

Trending

  • Getting Started With the YugabyteDB Managed REST API
  • Top 10 Pillars of Zero Trust Networks
  • Operator Overloading in Java
  • How To Approach Java, Databases, and SQL [Video]
  1. DZone
  2. Coding
  3. Languages
  4. Optional Parameters Handling Strategy in Java

Optional Parameters Handling Strategy in Java

A detailed comparison of six different ways of handling optional parameters in Java.

Shamik Mitra user avatar by
Shamik Mitra
·
Aug. 28, 16 · Tutorial
Like (20)
Save
Tweet
Share
28.69K Views

Join the DZone community and get the full member experience.

Join For Free

Often we face a situation where we need to design an object that expects a lot of parameters from the client. Some parameters are required and some are optional. In this article, we will focus on various strategies by which we can design such objects, as well as their pros and cons.

Strategy 1. Telescopic Constructors

To design such objects, we can use a chain of overloading constructors. First, a minimal constructor is taking only the required parameters, then delegate calls another constructor, which takes an optional parameter.

Then this constructor calls another one, which takes another optional parameter until all optional parameters are covered. When calling another constructor, it can pass the default value for an optional parameter.

Pros

  • For a small number of parameters, this is a good way to design objects.
  • Very easy to implement.

Cons

  • For a large number of parameters, it creates problems. The developer often confuses passing parameters.
  • If two adjacent parameters have the same datatype, and a developer can unintentionally swap values. The compiler won't complain, but it creates a genuine problem at runtime and is very hard to track.

Example

package com.example.builder;

public class EmployeeTelescopic {

       private String name;
       private Integer empId;
       private String company;
       private Integer passport;
       private String tempAddress ;    

       public EmployeeTelescopic(String name,Integer empId,String company)
       {
              this(name,empId,company,0);
       }

       public EmployeeTelescopic(String name,Integer empId,String company,int passport)
       {
              this(name,empId,company,passport,"NA");
       }

       public EmployeeTelescopic(String name,Integer empId,String company,Integer passport,String tempAddress)
       {
           this.name=name;
           this.empId=empId;
           this.company=company;
           this.passport=passport;
           this.tempAddress=tempAddress;                        
       }

       @Override
       public String toString() {
              return "EmployeeTelescopic [name=" + name + ", empId=" + empId
                           + ", company=" + company + ", passport=" + passport
                           + ", tempAddress=" + tempAddress + "]";
       }
       public static void main(String[] args) {            
              EmployeeTelescopic emp = new EmployeeTelescopic("Shamik",100,"IBM");
              EmployeeTelescopic emp1 = new EmployeeTelescopic("Akash",101,"IBM",1234,"1,bangalore");
              System.out.println(emp);
              System.out.println(emp1);
       }
}


Strategy 2:  By Getters and Setters

Create a class and expose every property through getters and setters. The client will set the property using a setter, and access it via getters.

Pros

  • Easy to implement.
  • In setters, you can set validation or pass a default value for optional parameters.

Cons

  • If an object is shared between multiple threads, it is possible that one thread will just create the object and try to set properties, while another thread accesses the object. As its properties have not been set, an exception can occur.
  • Properties are exposed through getters and setters, and extra care is needed to make this object immutable.

Strategy 3: Using Varargs

Create a constructor like  Employee(Object… args). The client can pass variable length parameters. A constructor then checks the type of each parameter by using an instanceof operator.

If a type is same as a bean property, set a value. Otherwise, throw an IllegalArgument Exception.

Pros

  • None

Cons

  • For each property, you need to check the type so it loses static type checking.

  • There is a conditional block for each property, which increases cyclomatic complexity.

Strategy 4: Using Map

Same as varargs, but instead of varargs we use a map.

Pros

  • None

Cons

  • For each property, you need to check type so it loses static type checking.

  • There is a conditional block for each property, which increases cyclomatic complexity.

Example

package com.example.builder;

import java.util.HashMap;
import java.util.Map;

public class EmployeeMap {
       private String name;
       private Integer empId;
       private String company;
       private Integer passport;
       private String tempAddress ;
      public  EmployeeMap(Map<String,Object> map) throws IllegalArgumentException
       {
              if(!(map.containsKey("name") && map.containsKey("empId") && map.containsKey("company")))
              {
                     thrownew IllegalArgumentException("Required  Parameter missing");
              }
              if((map.get("name")==null || map.get("empId")==null ||  map.get("company")==null))
              {
                     thrownew IllegalArgumentException("Required  Parameter missing");
              }             
              if(map.get("name") instanceof String)
              {
                     this.name =(String) map.get("name") ;
              }
              else{
                     thrownew IllegalArgumentException("name Parameter  type is wrong");
              }             
              if(map.get("empId") instanceof Integer)
              {
                     this.empId =(Integer) map.get("empId") ;
              }
              else{
                     thrownew IllegalArgumentException("enpId Parameter  type is wrong");
              }
              if(map.get("company") instanceof String)
              {
                     this.company =(String) map.get("company") ;
              }
              else{
                     thrownew IllegalArgumentException("company Parameter  type is wrong");
              }                          
              if(map.containsKey("passport") && (map.get("passport") instanceof Integer))
              {
                     this.passport = (Integer)map.get("passport");
              }
              else
              {
                     this.passport =0;
              }            
              if(map.containsKey("tempAddress") && (map.get("tempAddress") instanceof String))
              {
                     this.tempAddress = (String)map.get("tempAddress");
              }
              else
              {
                     this.tempAddress="NA";
              }
       }     

       @Override
       public String toString() {
              return "EmployeeMap [name=" + name + ", empId=" + empId + ", company="
                           + company + ", passport=" + passport + ", tempAddress="
                           + tempAddress + "]";
       }

       public static void main(String[] args) {             
              try
              {
              Map map = new HashMap<String,Object>();
              map.put("name", "Shamik");
              map.put("empId", 100);
              map.put("company", "IBM");
              EmployeeMap emp = new EmployeeMap(map);

              Map map1 = new HashMap<String,Object>();
              map1.put("name", "Akash");
              map1.put("empId", 101);
              map1.put("company", "IBM");
              map1.put("passport", "1234");
              map1.put("tempAddress", "1,bangalore");
              EmployeeMap emp1 = new EmployeeMap(map1);

              System.out.println(emp);
              System.out.println(emp1);

              }
              catch(IllegalArgumentException ex)
              {
                     ex.printStackTrace();
              }
       }
}


Strategy 5: Null values

Here, the client pass optional value as null, and the constructor checks if value is null, then sets a default value for optional parameters. If a parameter is required and null, the constructor throws an exception.

Pros

  • For a small number of parameters this is good way to design objects.
  • Very easy to implement.

Cons

  • For large number of parameters, it creates problems. Developer has to pass null value for optional parameters.
  • If two adjacent parameters have the same datatype and developer can unintentionally swap values. Compilers do not complain, but it creates a genuine problem at runtime, and it is very hard to track.

Example

package com.example.builder;
public class EmployeeNull {

       private String name;
       private Integer empId;
       private String company;
       private Integer passport;
       private String tempAddress;


       public EmployeeNull(String name,Integer empId,String company,Integer passport,String tempAddress) throws IllegalArgumentException
       {
              if(name ==null || empId==null || company==null)
              {
                     thrownew IllegalArgumentException("Required  Parameter missing");
              }

              this.name=name;
             this.empId=empId;
            this.company=company;
              this.passport= passport != null?passport:0;
              this.tempAddress = tempAddress !=null? tempAddress:"NA";
       }
       @Override
       public String toString() {
              return "EmployeeNull [name=" + name + ", empId=" + empId + ", company="
                           + company + ", passport=" + passport + ", tempAddress="
                           + tempAddress + "]";
       }


       public static void main(String[] args) throws IllegalAccessException {

              EmployeeNull emp = new EmployeeNull("Shamik",100,"IBM",null,null);
              EmployeeNull emp1 = new EmployeeNull("Akash",101,"IBM",1234,"1,blore");
              System.out.println(emp);
              System.out.println(emp1);

       }


}


Strategy 6: Builder Pattern

Use a nested static class, which acts as a builder of this bean. The Builder takes required parameters as its constructor arguments, and for each optional parameter there will be a helper method which sets the value and returns a Builder instance itself. So we can invoke another helper method for a parameter. The builder pattern maintains a fluent interface pattern (Channeling of methods).  At last, build() method returns an Immutable bean object.

Pros

  • Immutability is achieved easily, so Objects are thread-safe by design.
  • To set optional parameters, the parameter position is not necessary, as each parameter has a helper method client can invoke them. It offers fluidity by a chain of methods pattern.

Cons

  • Complex to implement.

Example

package com.example.builder;
public class Employee {

       private String name;
       private Integer empId;
       private String company;
       private Integer passport;
       private String tempAddress ;

       private Employee()
       {

       }
       privatestaticclass EmployeeBuilder
       {
              private String name;
              private Integer empId;
              private String company;
              private Integer passport;
              private String tempAddress ;
              public EmployeeBuilder(String name,Integer empId,String company)
              {
                    this.name=name;
                    this.empId=empId;
                    this.company=company  ;                
              }

              public EmployeeBuilder setPassport(Integer passport)
              {
                    this.passport=passport;
                     return this;

              }

              public EmployeeBuilder setTempAddress(String address)
              {
                     this.tempAddress=address;
                     return this;

              }

              public Employee build()
              {
                     Employee emp = new Employee();

                     emp.name=this.name;
                     emp.empId=this.empId;
                     emp.company=this.company;
                     emp.passport=this.passport!=null?this.passport:0;
                     emp.tempAddress=this.tempAddress!=null?this.tempAddress:"NA";
                     return emp;
              }





       }



       @Override
       public String toString() {
              return "Employee [name=" + name + ", empId=" + empId + ", company="
                           + company + ", passport=" + passport + ", tempAddress="
                           + tempAddress + "]";
       }
       public static void main(String[] args) {

              Employee emp = new Employee.EmployeeBuilder("Shamik", 100, "IBM").build();
              Employee emp1 = new Employee.EmployeeBuilder("Akash", 101, "IBM").setPassport(1234).setTempAddress("1,bangalore").build();
              System.out.println(emp);
              System.out.println(emp1);
       }

}

Comparison: Please see the picture below.

Image title

Conclusion: For fewer parameters, four or less, use the Telescopic constructor pattern.

For a larger number of parameters use the Builder pattern.

Object (computer science) Property (programming) Java (programming language)

Published at DZone with permission of Shamik Mitra, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Trending

  • Getting Started With the YugabyteDB Managed REST API
  • Top 10 Pillars of Zero Trust Networks
  • Operator Overloading in Java
  • How To Approach Java, Databases, and SQL [Video]

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: