There are several ways to simulate optional parameters in Java.

Method overloading

Copyvoid foo(String a, Integer b) {
    //...
}

void foo(String a) {
    foo(a, 0); // here, 0 is a default value for b
}

foo("a", 2);
foo("a");

One of the limitations of this approach is that it doesn't work if you have two optional parameters of the same type and any of them can be omitted.

Varargs

a) All optional parameters are of the same type:

Copyvoid foo(String a, Integer... b) {
    Integer b1 = b.length > 0 ? b[0] : 0;
    Integer b2 = b.length > 1 ? b[1] : 0;
    //...
}

foo("a");
foo("a", 1, 2);

b) Types of optional parameters may be different:

Copyvoid foo(String a, Object... b) {
    Integer b1 = 0;
    String b2 = "";
    if (b.length > 0) {
      if (!(b[0] instanceof Integer)) { 
          throw new IllegalArgumentException("...");
      }
      b1 = (Integer)b[0];
    }
    if (b.length > 1) {
        if (!(b[1] instanceof String)) { 
            throw new IllegalArgumentException("...");
        }
        b2 = (String)b[1];
        //...
    }
    //...
}

foo("a");
foo("a", 1);
foo("a", 1, "b2");

The main drawback of this approach is that if optional parameters are of different types you lose static type checking. Furthermore, if each parameter has the different meaning you need some way to distinguish them.

Nulls

To address the limitations of the previous approaches you can allow null values and then analyze each parameter in a method body:

Copyvoid foo(String a, Integer b, Integer c) {
    b = b != null ? b : 0;
    c = c != null ? c : 0;
    //...
}

foo("a", null, 2);

Now all arguments values must be provided, but the default ones may be null.

Optional class

This approach is similar to nulls, but uses Java 8 Optional class for parameters that have a default value:

Copyvoid foo(String a, Optional<Integer> bOpt) {
    Integer b = bOpt.isPresent() ? bOpt.get() : 0;
    //...
}

foo("a", Optional.of(2));
foo("a", Optional.<Integer>absent());

Optional makes a method contract explicit for a caller, however, one may find such signature too verbose.

Update: Java 8 includes the class java.util.Optional out-of-the-box, so there is no need to use guava for this particular reason in Java 8. The method name is a bit different though.

Builder pattern

The builder pattern is used for constructors and is implemented by introducing a separate Builder class:

Copyclass Foo {
    private final String a; 
    private final Integer b;

    Foo(String a, Integer b) {
      this.a = a;
      this.b = b;
    }

    //...
}

class FooBuilder {
  private String a = ""; 
  private Integer b = 0;
  
  FooBuilder setA(String a) {
    this.a = a;
    return this;
  }

  FooBuilder setB(Integer b) {
    this.b = b;
    return this;
  }

  Foo build() {
    return new Foo(a, b);
  }
}

Foo foo = new FooBuilder().setA("a").build();

Maps

When the number of parameters is too large and for most of the default values are usually used, you can pass method arguments as a map of their names/values:

Copyvoid foo(Map<String, Object> parameters) {
    String a = ""; 
    Integer b = 0;
    if (parameters.containsKey("a")) { 
        if (!(parameters.get("a") instanceof Integer)) { 
            throw new IllegalArgumentException("...");
        }
        a = (Integer)parameters.get("a");
    }
    if (parameters.containsKey("b")) { 
        //... 
    }
    //...
}

foo(ImmutableMap.<String, Object>of(
    "a", "a",
    "b", 2, 
    "d", "value")); 

In Java 9, this approach became easier:

Copy@SuppressWarnings("unchecked")
static <T> T getParm(Map<String, Object> map, String key, T defaultValue) {
  return (map.containsKey(key)) ? (T) map.get(key) : defaultValue;
}

void foo(Map<String, Object> parameters) {
  String a = getParm(parameters, "a", "");
  int b = getParm(parameters, "b", 0);
  // d = ...
}

foo(Map.of("a","a",  "b",2,  "d","value"));

Please note that you can combine any of these approaches to achieve a desirable result.

Answer from Vitalii Fedorenko on Stack Overflow
🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › util › Optional.html
Optional (Java Platform SE 8 )
April 21, 2026 - Parameters: exceptionSupplier - ... exceptionSupplier is null · X extends Throwable · public boolean equals(Object obj) Indicates whether some other object is "equal to" this Optional....
Top answer
1 of 16
1975

There are several ways to simulate optional parameters in Java.

Method overloading

Copyvoid foo(String a, Integer b) {
    //...
}

void foo(String a) {
    foo(a, 0); // here, 0 is a default value for b
}

foo("a", 2);
foo("a");

One of the limitations of this approach is that it doesn't work if you have two optional parameters of the same type and any of them can be omitted.

Varargs

a) All optional parameters are of the same type:

Copyvoid foo(String a, Integer... b) {
    Integer b1 = b.length > 0 ? b[0] : 0;
    Integer b2 = b.length > 1 ? b[1] : 0;
    //...
}

foo("a");
foo("a", 1, 2);

b) Types of optional parameters may be different:

Copyvoid foo(String a, Object... b) {
    Integer b1 = 0;
    String b2 = "";
    if (b.length > 0) {
      if (!(b[0] instanceof Integer)) { 
          throw new IllegalArgumentException("...");
      }
      b1 = (Integer)b[0];
    }
    if (b.length > 1) {
        if (!(b[1] instanceof String)) { 
            throw new IllegalArgumentException("...");
        }
        b2 = (String)b[1];
        //...
    }
    //...
}

foo("a");
foo("a", 1);
foo("a", 1, "b2");

The main drawback of this approach is that if optional parameters are of different types you lose static type checking. Furthermore, if each parameter has the different meaning you need some way to distinguish them.

Nulls

To address the limitations of the previous approaches you can allow null values and then analyze each parameter in a method body:

Copyvoid foo(String a, Integer b, Integer c) {
    b = b != null ? b : 0;
    c = c != null ? c : 0;
    //...
}

foo("a", null, 2);

Now all arguments values must be provided, but the default ones may be null.

Optional class

This approach is similar to nulls, but uses Java 8 Optional class for parameters that have a default value:

Copyvoid foo(String a, Optional<Integer> bOpt) {
    Integer b = bOpt.isPresent() ? bOpt.get() : 0;
    //...
}

foo("a", Optional.of(2));
foo("a", Optional.<Integer>absent());

Optional makes a method contract explicit for a caller, however, one may find such signature too verbose.

Update: Java 8 includes the class java.util.Optional out-of-the-box, so there is no need to use guava for this particular reason in Java 8. The method name is a bit different though.

Builder pattern

The builder pattern is used for constructors and is implemented by introducing a separate Builder class:

Copyclass Foo {
    private final String a; 
    private final Integer b;

    Foo(String a, Integer b) {
      this.a = a;
      this.b = b;
    }

    //...
}

class FooBuilder {
  private String a = ""; 
  private Integer b = 0;
  
  FooBuilder setA(String a) {
    this.a = a;
    return this;
  }

  FooBuilder setB(Integer b) {
    this.b = b;
    return this;
  }

  Foo build() {
    return new Foo(a, b);
  }
}

Foo foo = new FooBuilder().setA("a").build();

Maps

When the number of parameters is too large and for most of the default values are usually used, you can pass method arguments as a map of their names/values:

Copyvoid foo(Map<String, Object> parameters) {
    String a = ""; 
    Integer b = 0;
    if (parameters.containsKey("a")) { 
        if (!(parameters.get("a") instanceof Integer)) { 
            throw new IllegalArgumentException("...");
        }
        a = (Integer)parameters.get("a");
    }
    if (parameters.containsKey("b")) { 
        //... 
    }
    //...
}

foo(ImmutableMap.<String, Object>of(
    "a", "a",
    "b", 2, 
    "d", "value")); 

In Java 9, this approach became easier:

Copy@SuppressWarnings("unchecked")
static <T> T getParm(Map<String, Object> map, String key, T defaultValue) {
  return (map.containsKey(key)) ? (T) map.get(key) : defaultValue;
}

void foo(Map<String, Object> parameters) {
  String a = getParm(parameters, "a", "");
  int b = getParm(parameters, "b", 0);
  // d = ...
}

foo(Map.of("a","a",  "b",2,  "d","value"));

Please note that you can combine any of these approaches to achieve a desirable result.

2 of 16
595

varargs could do that (in a way). Other than that, all variables in the declaration of the method must be supplied. If you want a variable to be optional, you can overload the method using a signature which doesn't require the parameter.

Copyprivate boolean defaultOptionalFlagValue = true;

public void doSomething(boolean optionalFlag) {
    ...
}

public void doSomething() {
    doSomething(defaultOptionalFlagValue);
}
Top answer
1 of 5
6

I agree that you should go with what makes more sense semantically, but I also find that, when the boolean argument is optional, the thing that fairly often makes more sense when omitting it is for it to have a default value of false - in languages that initialize instances of primitive types, false is generally the default value for a boolean.

It then acts as an "on" flag for the less commonly used feature. So that you have:

DoSomething(someParams);
DoSomething(someParams, true);

// Or, if your language supports named parameters
DoSomething(someParams, optionalFeature: true);

So, I would have a slight bias for the parameter to default to false, unless doing so feels unnatural (as in, it feels unnatural as a sentence when you read it). Sometimes, the exceptional behavior is better conceptualized as turning something off (for example, setters that take a boolean argument are often constructed this way, see Joop Eggen's answer; however, you should strive for encapsulation, and minimize the use of getters and setters).

If the feature controlled by the boolean argument is not less commonly used (in the general case), I wouldn't make it optional. Design for the general case. If there's a small number of users with applications that mostly use one value for the argument, they can create their own wrapper.

As for the logic inside the method, if it turns out that your choice makes it awkward to write conditionals, just introduce a new well-named variable with the flipped value (or a new variable that summarizes several boolean checks that repeat, or whatever) - it's not going to be a problem if your method is fairly short (which it should be - you shouldn't have a sprawling tree of nested if-statements in there).

2 of 5
10

In line with @Ewan's arguments, choose the one making the code easier to read and reason about.

For example, double negations (!isNotA or Ewan's !FileDoesntExist) are the kind of conditional statements you want to avoid because they cause a cognitive burden. Unbearable when flag names are meaningless.

Negation involves an extra cognitive step (even when the negation is in the name of the flag). We usually think first in the is part and then negate it. So, the more your if blocks look like the following, the better

//only for illustration
if(isA && isB)
else (isA)     //isA && !isB
else (isB)     //!isA && isB
else           //!isA && !isB

Ok, this is easier to say than done, but think about it. It depends on how we translate (mentally) rules into conditions. If we think in terms of "is not", we will end up with flags prefixed with isNot, and it's ok if we can address it later. For instance, we can invert the flag isA = !isNotA and use isA instead. 1

To summarize, use the notation that makes your code easier to read (to me, affirmative statements), always use meaningful names and avoid negations and double negations as the plague; your teammates will appreciate it.


1: Do it only to make your conditionals easier to read and reason about. Don't systematically invert flags all over the code.

🌐
GitHub
github.com › remkop › picocli › issues › 1108
support Optional<> for better tri-state boolean · Issue #1108 · remkop/picocli
June 12, 2020 - support Optional<> for better tri-state boolean#1108 · Copy link · Labels · theme: parserAn issue or change related to the parserAn issue or change related to the parsertype: enhancement ✨ · Milestone · 4.6 · maxandersen · opened · on Jun 12, 2020 · Issue body actions · currently when you do: @Option(names={"--cds"}, description = "If specified Class Data Sharing (CDS) will be used for building and running (requires Java 13+)", negatable = true) Optional<Boolean> cds = Optional.empty(); you get: Only boolean options can be negatable, but field java.util.Optional<Boolean> dk.xam.jba
Author   remkop
🌐
Javadoc.io
javadoc.io › doc › com.landawn › abacus-util-jdk7 › 1.2.8 › com › landawn › abacus › util › OptionalBoolean.html
OptionalBoolean (abacus API Documentation)
package-list path (used for javadoc generation -link option) https://javadoc.io/doc/com.landawn/abacus-util-jdk7/1.2.8/package-list ·
🌐
Devwithus
devwithus.com › java-optional-parameters
Complete guide to Java optional parameters | devwithus
January 1, 2020 - JavaBean convention suggests an easiest and scalable way to set optional parameters in Java! It allows to create an object using step-by-step strategy, first you need to call the default constructor to instantiate the class, and then call setXXX methods to set your object properties! Now let’s see together an example of how a JavaBean is defined in Java: public class Employee { private String firstname; private String lastname; private String email; private boolean ismanager; public Employee () { } public String getFirstname() { return firstname; } public void setFirstname(String firstname)
🌐
Baeldung
baeldung.com › home › java › core java › guide to java optional
Guide To Java Optional | Baeldung
February 15, 2026 - The orElse() method is used to retrieve the value wrapped inside an Optional instance. It takes one parameter, which acts as a default value.
Find elsewhere
🌐
FavTutor
favtutor.com › blogs › java-optional-parameters
Optional Parameters in Java Explained (with code)
August 23, 2023 - Find out what are optional parameters in java and how to declare and implement them. We also included syntax and examples for each method.
🌐
LinkedIn
linkedin.com › pulse › introduction-java-8-optional-aneshka-goyal
Introduction to Java 8 Optional
December 30, 2020 - We can even filter the optional object based on some constraints. This can be done as follows · boolean check = optionalUser.filter( userObj -> userObj.getUserName().equals("ABC")).isPresent(); System.out.println(check);
🌐
Hacker News
news.ycombinator.com › item
For Java developers... you can use Optional<Boolean> to store the elusive four p... | Hacker News
March 11, 2026 - public static void main (String[] args) { Optional<Boolean> n = Optional.ofNullable(null); Optional<Boolean> e = Optional.empty(); System.out.println(n.equals(e)); } true https://ideone.com/EGRdi5 · A null in an Optional is empty. So you've got:
🌐
Oracle
docs.oracle.com › en › java › javase › 11 › docs › api › java.base › java › util › Optional.html
Optional (Java SE 11 & JDK 11 )
January 20, 2026 - Parameters: exceptionSupplier - the supplying function that produces an exception to be thrown · Returns: the value, if present · Throws: X - if no value is present · NullPointerException - if no value is present and the exception supplying function is null · X extends Throwable · public boolean equals​(Object obj) Indicates whether some other object is "equal to" this Optional.
Top answer
1 of 16
376

Oh, those coding styles are to be taken with a bit of salt.

  1. (+) Passing an Optional result to another method, without any semantic analysis; leaving that to the method, is quite alright.
  2. (-) Using Optional parameters causing conditional logic inside the methods is literally contra-productive.
  3. (-) Needing to pack an argument in an Optional, is suboptimal for the compiler, and does an unnecessary wrapping.
  4. (-) In comparison to nullable parameters Optional is more costly.
  5. (-) The risk of someone passing the Optional as null in actual parameters.

In general: Optional unifies two states, which have to be unraveled. Hence better suited for result than input, for the complexity of the data flow.

2 of 16
237

The best post I've seen on the topic was written by Daniel Olszewski:

Although it might be tempting to consider Optional for not mandatory method parameters, such a solution pale in comparison with other possible alternatives. To illustrate the problem, examine the following constructor declaration:

Copypublic SystemMessage(String title, String content, Optional<Attachment> attachment) {
    // assigning field values
}

At first glance it may look as a right design decision. After all, we explicitly marked the attachment parameter as optional. However, as for calling the constructor, client code can become a little bit clumsy.

CopySystemMessage withoutAttachment = new SystemMessage("title", "content", Optional.empty());
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", Optional.ofNullable(attachment));

Instead of providing clarity, the factory methods of the Optional class only distract the reader. Note there’s only one optional parameter, but imagine having two or three. Uncle Bob definitely wouldn’t be proud of such code 😉

When a method can accept optional parameters, it’s preferable to adopt the well-proven approach and design such case using method overloading. In the example of the SystemMessage class, declaring two separate constructors are superior to using Optional.

Copypublic SystemMessage(String title, String content) {
    this(title, content, null);
}

public SystemMessage(String title, String content, Attachment attachment) {
    // assigning field values
}

That change makes client code much simpler and easier to read.

CopySystemMessage withoutAttachment = new SystemMessage("title", "content");
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", attachment);
🌐
Sonar Community
community.sonarsource.com › rules and languages › report false-positive / false-negative...
Rule java:S6814 "Optional REST parameters should have an object type" false positive - Report False-positive / False-negative... - Sonar Community
May 16, 2024 - Java Which rule? java:S6814 Optional REST parameters should have an object type Why do you believe it’s a false-positive/false-negative? Spring supports optional primitive boolean parameters.
🌐
Medium
medium.com › @hopewellmutanda › java-8-optional-usage-and-best-practices-975c41d66822
Java 8 Optional Usage and Best Practices | by Hopewell Mutanda | Medium
May 28, 2019 - If you do need to serialize an object that contains an Optional value, the Jackson library provides support for treating Optionals as ordinary objects. What this means is that Jackson treats empty objects as null and objects with a value as fields containing that value. This functionality can be found in the jackson-modules-java8 project. b) Do not use it as a parameter for constructors and methods as it would lead to unnecessarily complicated code.
🌐
GoLinuxCloud
golinuxcloud.com › home › java › crafting perfect code with java optional parameters
Crafting Perfect Code with Java Optional Parameters | GoLinuxCloud
October 7, 2023 - implement java optional parameters in java including the overloading method, optional container object, built pattern, and varargs
🌐
Java Code Geeks
examples.javacodegeeks.com › home › java development › core java
Java Optional Parameters - Java Code Geeks
August 11, 2021 - In this article, we’ve looked at a variety of strategies for working with optional parameters in Java, such as method overloading, the builder pattern, and the strategy of allowing callers to supply null values.