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 OverflowThere 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.
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);
}
support Optional<> for better tri-state boolean
coding style - Should an optional boolean function argument rather default to true or false? - Software Engineering Stack Exchange
Optional parameter in java (can be null) - Stack Overflow
Why should Java 8's Optional not be used in arguments - Stack Overflow
For good order
if (spouseIsMale.orElse(false)) {
System.out.println("There is a male spouse.");
}
Clear.
It is possible to achieve that behaviour with .filter(b -> b):
spouseIsMale.filter(b -> b).ifPresent(b -> System.out.println("There is a male spouse."));
However, it costs some brain execution time seconds to understand what is going on here.
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).
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.
Use Boolean class
public String foo(Boolean addWhere){
String query = "SELECT * FROM tbl";
if(addWhere != null){
query += (addWhere? " WHERE true" : " WHERE false");
}
return query;
}
Call it as following,
String q = foo(false);
You can use java.lang.Boolean; this is the wrapper class for primitive boolean. The value can be null, Boolean.TRUE or Boolean.FALSE, but due to auto-unboxing you can also directly compare with true and false.
Oh, those coding styles are to be taken with a bit of salt.
- (+) Passing an Optional result to another method, without any semantic analysis; leaving that to the method, is quite alright.
- (-) Using Optional parameters causing conditional logic inside the methods is literally contra-productive.
- (-) Needing to pack an argument in an Optional, is suboptimal for the compiler, and does an unnecessary wrapping.
- (-) In comparison to nullable parameters Optional is more costly.
- (-) 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.
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);
I like using Optional<> to return values that may be null but today I saw people using them to accept parameters that may be null, if the parameter wasn't an Optional<> then it couldn't be null. I personally don't like doing that but I'd like to hear some opinions.
They were doing things like
double getStartingBalance(@NotNull Optional<UUID> user) { ... }
In my opinion, Optional<> is used to force the developer to handle null values. If my method is called and may return null, I'll return an Optional<> to make sure that null is handled but if I design the method and define that something cannot be null I can just use Objects#requereNonNull or if it can be null a simple check does the job. Also having to box values in optionals and having to use Optional.empty() for nulls to call a method is messy and makes the call harder to read.
So what are your opinions on using optionals as parameters?
How about using the terniary operator that's already included in the language?
boolVar ? trueResult : falseResult
EDIT: that's how it would look like if you really want such a class:
public class Conditional<T> {
private final boolean condition;
private T valueWhenTrue;
public static Conditional valueOf(boolean condition) {
return new Conditional(condition);
}
private Conditional(boolean condition) {
this.condition = condition;
}
public Conditional ifTrue(T valueWhenTrue) {
this.valueWhenTrue = valueWhenTrue;
return this;
}
public T orElse(T valueWhenFalse) {
return condition ? valueWhenTrue : valueWhenFalse;
}
}
Usage:
Conditional.valueOf(boolVar).ifTrue(trueResult).orElse(falseResult)
java.lang.Boolean does not have a an ifTrue() method.
You could write your own implementation of Boolean and make it do whatever you like, but I don't see why you wouldn't use existing patterns around handling booleans, which work perfectly well.
There are loads of weird and wonderful possibilities:
return Stream.of(Boolean.valueOf(b))
.filter(Function.identity())
.map( b -> trueResult)
.findAny()
.orElse( falseResult);
----
return Optional.of(b)
.filter(function.identity())
.map( b -> trueResult)
.orElse(falseResult);
... but why would you when a ternary operator using the primitive is clearer, shorter and more efficient both in both memory and operations:
return b ? trueResult : falseResult;