Summary of how to implement default arguments in Java

Java doesn't have a default argument feature **, so I've summarized the implementations to replace it.

TL;DR I think that there is no problem if it is implemented with the following policy.

Number of arguments you want to default Solution
~ 4 Overload
5 ~ Builder pattern

What is the default argument?

The default argument in this article is if the value is not set as an actual argument when calling the method. Instead, it is a mechanism to initialize with the default value. (I think it's a syntax that is mostly introduced in modern languages)

Below is a sample of the default arguments written in Groovy.

def foo(a = 0, b = "undefined") {
    println "a = $a, b = $b"
}

foo(23, "hoge")  // => a = 23, b = hoge
foo()            // => a = 0, b = undefined

Implementation method in Java

1. Overload | If the number of default arguments is small

You can easily implement it with the pattern you see most often.

    static void foo(int a, String b) {
        System.out.println("a = " + a + ", b = " + b);
    }

    static void foo(int a) { foo(a, "undefined"); } //Only argument b is the default argument
    static void foo(String b) { foo(0, b); }        //Only argument a is the default argument
    static void foo() { foo(0, "undefined"); }      //Argument a,Both b are default arguments

    public static void main(String[] args) {
        foo(23, "hoge");    // => a = 23, b = hoge
        foo(23);            // => a = 23, b = undefined
        foo("hoge");        // => a = 0, b = hoge
        foo();              // => a = 0, b = undefined
    }

In the sample, the arguments declared by foo (int a, String b) are different types, so Overloading allows you to set default values for all arguments. If the arguments a and b are of the same type, it is not possible to declare "default argument only for argument a" and "default argument only for argument b" at the same time. In that case, there is no choice but to implement it with the Builder pattern described later or passing Null.

(Supplement) Variadic argument | If an array type formal argument is not specified, the default value of an empty array is entered.

The part that becomes a variable length argument has a constraint that it is the last of the method arguments If nothing is specified in the last argument, an empty array (length = 0) will be passed automatically. Therefore, in such cases, there is no need to overload.

    static void foo(String a, int... b) {
        int bSum = IntStream.of(b).sum();

        System.out.println("a = " + a + ", sum = " + bSum);
    }

    public static void main(String[] args) {
        foo("hoge", 23, 42);  // => a = hoge, sum = 65
        foo("hoge");          // => a = hoge, sum = 0
    }

2. Builder pattern | Can be used in a wide variety of ways. However, the trouble of creating a class is ...

In addition to overloading, there is a commonly used pattern that uses the Builder pattern to set default arguments. Overloading is nice because you can easily set the default value, but if the number of arguments becomes large Replacing it with the Builder pattern makes the code easier to read. SonarQube's rule states that it is desirable for the threshold to have no more than four arguments. Java: Methods should not have too many parameters | SonarQube - Rules

In the sample, it is written to set the default value in the Builder pattern for the method with two arguments.

import lombok.Builder;
import lombok.Value;

public class BuilderPattern {
    
    static void foo(Foo foo) {
        System.out.println("foo = " + foo);
    }
    
    public static void main(String[] args) {
        var specifiedFoo = Foo.builder().a(23).b("hoge").build();
        var defaultFoo = Foo.builder().build();
        foo(specifiedFoo);  // => foo = Foo(a=23, b=hoge)
        foo(defaultFoo);    // => foo = Foo(a=0, b=undefined)
    }
}

@Value
@Builder
class Foo {
    @Builder.Default
    Integer a = 0;
    @Builder.Default
    String b = "undefined";
}

(Supplement) Map type | If you do this, please use Builder

You can do the same thing with the Builder pattern in Map, but if you want to do this, I think you should write it in Builder.

    static void foo(Map<Foo, Object> params) {
        var a = (int) params.getOrDefault(Foo.A, 0);
        var b = (String) params.getOrDefault(Foo.B, "undefined");
        System.out.println("a = " + a + ", b = " + b);
    }

    public static void main(String[] args) {
        foo(Map.of(Foo.A, 23, Foo.B, "hoge"));  // => a = 23, b = hoge
        foo(Map.of());                          // => a = 0, b = undefined
    }

    enum Foo {
        A, B
    }

3. Pass Null | When the argument to set the default value is only the first or the second

As mentioned in the overload description, if the declared arguments are of the same type, In some cases, the default value could not be set for each argument. The workaround is to set a default value within the method. However, it is not possible to determine which variable has the default value based on the method signature alone. Method users need to look at the Javadoc or the method implementation, which is a pattern they don't want to use much.

    static void foo(String a, Integer b, Integer c) {
        b = Objects.requireNonNullElse(b, 0);
        c = Objects.requireNonNullElse(c, 0);
        System.out.println("a = " + a + ", b = " + b + ", c = " + c);
    }

    public static void main(String[] args) {
        foo("hoge", 23, 42);      // => a = hoge, b = 23, c = 42
        foo("hoge", null, null);  // => a = hoge, b = 0, c = 0
    }

(Supplement) Optional type | No. Zettai.

As a problem with the above-mentioned Null passing pattern "It is not possible to determine which variable has the default value based on the method signature alone." It's easy to wonder, "Well, maybe the Optional type can be used?", But this seems to be quite criticized. Because the Optional type is a mechanism to tell the caller that the value originally returned from the method may be null. If you use the Optional type as an argument, the code becomes more verbose and the number of meaningless codes increases. Therefore, the following writing style is strictly prohibited.

    static void foo(String a, Optional<Integer> bOpt) {
        var b = bOpt.orElse(0);
        System.out.println("a = " + a + ", b = " + b);
    }

    public static void main(String[] args) {
        foo("hoge", Optional.of(23));    // => a = hoge, b = 23
        foo("hoge", Optional.empty());   // => a = hoge, b = 0
        foo("hoge", null);               // => NullPointerException
    }

References

Java optional parameters | Stack Overflow Java: Methods should not have too many parameters | SonarQube - Rules Why should Java 8's Optional not be used in arguments | Stack Overflow

Recommended Posts

Summary of how to implement default arguments in Java
How to implement date calculation in Java
[java] Summary of how to handle char
Summary of how to write annotation arguments
How to implement coding conventions in Java
[Java] [Maven3] Summary of how to use Maven3
Summary of how to select elements in Selenium
[java] Summary of how to handle character strings
[Java] Summary of how to abbreviate lambda expressions
[Java] How to implement multithreading
Summary of Java communication API (1) How to use Socket
Summary of Java communication API (3) How to use SocketChannel
Summary of Java communication API (2) How to use HttpUrlConnection
How to learn JAVA in 7 days
How to use classes in Java?
How to name variables in Java
Try to implement Yubaba in Java
How to concatenate strings in java
How to implement one-line display of TextView in Android development
How to derive the last day of the month in Java
Summary of how to use the proxy set in IE when connecting with Java
How to make a Java calendar Summary
How to implement search functionality in Rails
Multilingual Locale in Java How to use Locale
Try to implement n-ary addition in Java
[Webpacker] Summary of how to install Bootstrap and jQuery in Rails 6.0
How to implement a job that uses Java API in JobScheduler
How to do base conversion in Java
How to embed Janus Graph in Java
How to get the date in java
How to implement ranking functionality in Rails
How to implement asynchronous processing in Outsystems
How to get the length of an audio file in java
How to increment the value of Map in one line in Java
[Java] Pass arguments to constructor in Mockito / Set method default call to callRealMethod
How to find the total number of pages when paging in Java
How to display a web page in Java
I tried to implement deep learning in Java
How to get Class from Element in Java
How to hide null fields in response in Java
How to implement a like feature in Rails
How to use JQuery in js.erb of Rails6
How to implement optimistic locking in REST API
[Java] How to substitute Model Mapper in Jackson
How to solve an Expression Problem in Java
[Java] How to get the authority of the folder
How to write Java String # getBytes in Kotlin?
How to implement Pagination in GraphQL (for ruby)
Summary of Java support 2018
Contemplation: How to take advantage of functional interfaces in your own functions (java)
[Java] How to get the URL of the transition source
How to implement UICollectionView in Swift with code only
[Java] How to use compareTo method of Date class
How to call functions in bulk with Java reflection
How to create a Java environment in just 3 seconds
[Java] How to omit the private constructor in Lombok
How to implement guest login in 5 minutes in rails portfolio
How to implement a like feature in Ajax in Rails
I tried to implement Firebase push notification in Java
How to write Scala from the perspective of Java
[Java] Types of comments and how to write them