A Method with an Optional Parameter

How do I use optional parameters in Java?

There are several ways to simulate optional parameters in Java:

  1. Method overloading.

    void 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.

  1. Varargs.

a) All optional parameters are of the same type:

    void 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:

    void 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.

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

    void 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.

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

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

    foo("a", Optional.of(2));
    foo("a", Optional.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.

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

    class 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();
  3. 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:

    void 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:

    @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.

A method with an optional parameter

def some_func(variable = nil)
...
end

How to pass a class as optional parameter to a method?

That's not quite possible. As the error message states, you require a standard conversion: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/conversions#standard-conversions

All we can do is to define an implicit conversion operator for the class: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators

In your case, it would be something like:

public static implicit operator MyClass(string val) => new MyClass(val);

And replace your test method with something like this:

public static string test(string a, MyClass b = null)
{
b = b ?? " with default text";
return a + b;
}

Also note that both your test methods have the same signature if only one argument is provided, so the compiler won't know which one to use, remove the default value for the 2nd test method.

How do I define a function with optional arguments?

Try calling it like: obj.some_function( '1', 2, '3', g="foo", h="bar" ). After the required positional arguments, you can specify specific optional arguments by name.

Why should Java 8's Optional not be used in arguments

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.

C# Optional parameters / multiple required

I think you need the old way - method overloading.

// b = true
public void ParamChoise(string A, string C)

// b = false
public void ParamChoise(string A)

They should call a private version of your original

private void ParamChoiseInternal(string A, bool B = false, string C = "")

You should ensure that you're giving the 2 public methods a name that accurately conveys their meaning - that will help the programmer (probably you, I know) call the right method for their current state.


After update

Same as above, names reflect requirement, and you should still be able to call your original private method. The overloads ensure your consistency

public void AOnly(string A)
public void AAndBAndC(string A, bool B, string C)

Struggling to decipher these 2:

NOT A & B WITHOUT C !!!

NOT A AND C (Because B gives the point if C is needed)

How do I make List string as optional parameter?

Java doesn't support optional parameters. You can provide multiple signatures with different parameters, like this:

public SESReqErrorIdAndArgs(String errorIdentifier, List<String> arguments) {
this.errorIdentifier = errorIdentifier;
this.args = arguments;
}

public SESReqErrorIdAndArgs(String errorIdentifier) {
this(errorIdentifier, new ArrayList<>());
}

Note that (1) there's no point in assigning a new ArrayList<>() in your args initializer, as it will always be immediately discarded, and (2) it's typically best to make a defensive copy of items passed in this way, so this is likely better (since Java 10):

public SESReqErrorIdAndArgs(String errorIdentifier, List<String> arguments) {
this.errorIdentifier = errorIdentifier;
this.args = List.copyOf(arguments);
}

public SESReqErrorIdAndArgs(String errorIdentifier) {
this(errorIdentifier, Collections.emptyList());
}

Finally, depending on your use case varargs might be a better option:

public SESReqErrorIdAndArgs(String errorIdentifier, String... arguments) {
this.errorIdentifier = errorIdentifier;
this.args = List.of(arguments);
}


Related Topics



Leave a reply



Submit