4

So I found that we have the 3 dot notation for zero or more but is there anything for zero or one?

I'm needing to alter a method and rather than overloading it I was wondering if there is a syntax to just allow for zero or one value passed?

public void test(String sample, ObjectMapper... argOm){
    ObjectMapper om = (!argOm.equals(null)?argOm:new ObjectMapper());
}

This does not do what I want as it is expecting [ ]. I just want to zero or one.

Is overloading the only way aside from altering all references to this?

edjm
  • 4,830
  • 7
  • 36
  • 65
  • 2
    Yes, overloading is the only way. – Louis Wasserman Mar 06 '17 at 18:11
  • Probably the best way for this particular situation, but certainly not the *only* way. See below. – Vidya Mar 06 '17 at 22:03
  • Thanks everyone for your input. At this time I'm trying to avoid altering the POJOs as they are controlled by third party. I'll keep trying to find another way around the issue. – edjm Mar 07 '17 at 13:32

3 Answers3

6

If you would like the compiler to check the number of arguments for you, you need to use overloading. Unfortunately, Java does not offer the default parameter mechanism, which is used for modeling "zero or one" in other languages.

Fortunately, the overload is very simple, and it lets you replace the conditional assignment in your implementation:

public void test(String sample){
    test(sample, new ObjectMapper());
}
public void test(String sample, ObjectMapper om){
    if (om == null) {
        throw new IllegalArgumentException("object mapper");
    }
    ...
}

Note that your conditional code that used to allow callers pass no object mapper is replaced with the overload, which detects this situation at compile time.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
5

The best practice would be to overload your method and provide a default value as follows:

public void test(String sample) {
    test(sample, new ObjectMapper());
    ...
}
public void test(String sample, ObjectMapper argOm) {
    ObjectMapper om;
    if (argOm != null)
        om = argOm;
    ...
}

The default value is a new ObjectMapper object. The method with 1 parameter calls the method with 2 parameters including the default value.

Joe
  • 320
  • 1
  • 7
3

As the other answers have stated, overloading is probably your best option. But just keep in mind that using the Builder Pattern works too for this problem:

class Foo {
     private final String sample; 
     private final ObjectMapper objectMapper = new ObjectMapper();

     private Foo(String sample, ObjectMapper objectMapper) {
        this.sample = sample;
        if (objectMapper != null) {
           this.objectMapper = objectMapper;
        }
     }

     public static class Builder {
        private final String sample; 
        private final ObjectMapper objectMapper;

        public Builder sample(String sample) {
            this.sample = sample;
            return this;
        }

        public Builder objectMapper(ObjectMapper objectMapper) {
            this.objectMapper = objectMapper;
            return this;
        }

        public Foo build() {
            return new Foo(sample, objectMapper);
        }
     }
 }

Then later on:

Foo.Builder
   .sample(mySample)
   .objectMapper(myObjectMapper)
   .build()

Or simply:

Foo.Builder
   .sample(mySample)
   .build()

I like the elegance and the fluent clarity of this approach. After all, many software experts like Uncle Bob warn about the complexity each additional parameter brings to a method, but this is probably overkill for your simple situation. Still, it is a nice pattern to keep in mind in general.

Community
  • 1
  • 1
Vidya
  • 29,932
  • 7
  • 42
  • 70