Java 逆引き集 | 可変引数メソッド(…) - 汎用ユーティリティ

Java Java
スポンサーリンク

可変引数メソッドって何者か(「いくつ来るかわからない」を受け止める仕組み)

可変引数(varargs)は、同じ型の引数を 0 個以上まとめて受け取るための仕組みです。 メソッド定義で int... nums のように書くと、呼び出し側は好きな数だけ値を渡せます。

public static int sum(int... nums) {
    int total = 0;
    for (int n : nums) {
        total += n;
    }
    return total;
}
Java

呼び出し側はこう使えます。

sum();             // 0個
sum(10);           // 1個
sum(10, 20, 30);   // 3個
Java

「引数の数が呼び出し側によって変わる」場面で、可変引数は非常に便利です。 ユーティリティメソッド(共通処理)でよく使われる理由は、柔軟性が高く、呼び出し側の負担が少ないからです。

可変引数の正体は「配列」である

メソッド内部では配列として扱われる

可変引数は、内部では普通の配列として扱われます。

public static void debug(String... messages) {
    System.out.println("件数: " + messages.length);
    for (String msg : messages) {
        System.out.println("DEBUG: " + msg);
    }
}
Java

呼び出し側はこう書けます。

debug("start");
debug("load", "connect", "finish");
Java

内部では messagesString[] として扱われるので、 length で個数を調べたり、拡張 for 文で回したりできます。

配列引数との違いを理解する

配列を渡すメソッドと比較してみます。

public static int sumArray(int[] nums) { ... }
Java

呼び出し側は配列を作る必要があります。

sumArray(new int[]{10, 20, 30});
Java

可変引数なら、配列を作らずにそのまま渡せます。

sum(10, 20, 30);
Java

呼び出し側の書き心地が圧倒的に軽いのが可変引数の強みです。

可変引数のルールと注意点(ここは重要)

可変引数は「最後の引数」にしか書けない

次のような定義は OK です。

public static void log(String level, String... messages) { ... }
Java

しかし、次のような定義は NG です。

// コンパイルエラー
public static void bad(String... messages, String suffix) { ... }
Java

理由は、どこまでが可変引数で、どこからが次の引数なのか判別できないためです。 可変引数は必ず最後に置く、というルールを覚えておきましょう。

オーバーロードと組み合わせるときは慎重に

可変引数は柔軟すぎるため、オーバーロードと組み合わせると曖昧さが生まれることがあります。

public void print(int... nums) { ... }
public void print(int n) { ... }
Java

呼び出し側が print(5) と書いたとき、どちらが呼ばれるか分かりづらくなります。 可変引数を使うときは、オーバーロードを増やしすぎないことが大事です。

汎用ユーティリティでの可変引数の使いどころ

ログ出力ユーティリティ

ログは「複数のメッセージをまとめて出したい」場面が多いので、可変引数がよく使われます。

public static void info(String... messages) {
    for (String msg : messages) {
        System.out.println("[INFO] " + msg);
    }
}
Java

呼び出し側はこう書けます。

info("start", "loading", "done");
Java

「複数メッセージをまとめてログに出す」という意図が、呼び出し側のコードから自然に伝わります。

数値処理ユーティリティ

例えば「最大値を求める」メソッド。

public static int max(int... nums) {
    int result = Integer.MIN_VALUE;
    for (int n : nums) {
        if (n > result) result = n;
    }
    return result;
}
Java

呼び出し側はこう書けます。

max(3, 10, 7, 2);
Java

「何個来るか分からないけど全部比較したい」という処理にぴったりです。

文字列結合ユーティリティ

public static String join(String sep, String... parts) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < parts.length; i++) {
        sb.append(parts[i]);
        if (i < parts.length - 1) sb.append(sep);
    }
    return sb.toString();
}
Java

呼び出し側はこう書けます。

String s = join(", ", "A", "B", "C");
System.out.println(s); // A, B, C
Java

「区切り文字付きで連結したい」という処理を、可変引数でシンプルに書けます。

可変引数を使うときの設計ポイント(深掘り)

「本当に可変である必要があるか」を考える

可変引数は便利ですが、乱用するとメソッドの意図がぼやけます。

例えば「必ず3つの値が必要な処理」なのに可変引数にしてしまうと、

calc(a, b);       // 足りない
calc(a, b, c, d); // 多すぎる
Java

といった誤用がコンパイル時に検出できなくなります。

可変であること自体が仕様の一部になっているか? ここを自問してから使うと、設計が安定します。

呼び出し側の負担を減らすために使う

可変引数の最大のメリットは、呼び出し側のコードが軽くなることです。

配列を作らなくていい 値をそのまま並べて渡せる 読みやすい

ユーティリティメソッドでは「呼び出し側の負担を減らす」ことが重要なので、 可変引数はその目的に非常に合っています。

まとめと練習

可変引数(...)は、同じ型の引数を 0 個以上受け取るための柔軟な仕組みで、 内部では配列として扱われ、ユーティリティメソッドで特に威力を発揮します。

練習として次の2つを自分で書いてみると理解が深まります。

練習1:任意個の整数の平均値を返すメソッド

double avg(int... nums)
Java

練習2:任意個の文字列を「|」で結合するメソッド

String joinWithBar(String... parts)
Java

「可変であることが仕様の一部になっているか」「呼び出し側が楽になるか」を意識しながら書くと、 可変引数メソッドを“設計できる”感覚が身につきます。

タイトルとURLをコピーしました