#20 Javaで学ぶ関数の応用(デフォルト引数・可変長引数)の基本
「関数(メソッド)に、状況に応じて渡す引数の数を変えたい」——そんな場面に出会ったことはありませんか。たとえば「割引率を指定しなかったら0%として計算する」とか、「数値をいくつでも渡せる合計関数を作りたい」といった要望です。
Python など一部の言語には、こうした要望に応える「デフォルト引数」という仕組みが標準で用意されています。関数を定義するときに引数の初期値をあらかじめ決めておき、呼び出し側で省略できるようにする機能です。しかし、Javaにはこのデフォルト引数という言語仕様が存在しません。今回は、Javaがその代わりにどんな方法で同じような柔軟さを実現しているのかを見ていきましょう。
Javaにデフォルト引数がない理由と代替手段
まず前提として、Javaの設計方針では「引数の数や型によって呼び出し方を明確に区別する」ことが重視されています。デフォルト引数のような「省略できる引数」を許すと、コードを読む人が「実際に何が渡されているのか」を把握しにくくなります。そう考えられているためです。良し悪しというより、言語ごとの設計思想の違いだと捉えておくとよいでしょう。
では、Javaで「引数を省略したような呼び出し」をしたい場合はどうするのか。答えは「メソッドのオーバーロード(overload)」です。オーバーロードとは、同じ名前のメソッドを、引数の数や型を変えて複数定義できる仕組みのことです。呼び出し側が渡した引数の内容に応じて、コンパイラが自動的にどのメソッドを使うかを判断してくれます。
オーバーロードの具体例
たとえば「割引率を指定しない場合は0%として計算する」処理は、以下のように2つのメソッドを用意することで実現できます。
public class Shop {
// 割引率を指定するバージョン
static int calcPrice(int price, double discountRate) {
return (int) (price * (1 - discountRate));
}
// 割引率を省略した場合のバージョン(0%扱い)
static int calcPrice(int price) {
return calcPrice(price, 0.0);
}
public static void main(String[] args) {
System.out.println(calcPrice(1000, 0.1)); // 900
System.out.println(calcPrice(1000)); // 1000
}
}
ポイントは、引数が少ないほうのメソッド(calcPrice(int price))の中で、引数が多いほうのメソッドを呼び出している点です。こうすることで処理の中身を1か所にまとめられ、コードの重複を防げます。Python等に慣れている人からすると少し遠回りに感じるかもしれませんが、「呼び出しごとに使うメソッドがはっきり分かる」というメリットがあります。
可変長引数(varargs)を使いこなす
次に、「引数の数がそもそも決まっていない」場合の書き方を紹介します。たとえば「渡された数値をすべて合計する関数」を作りたいとき、引数が2個の場合と3個の場合でメソッドを分けて用意するのは非効率です。こうしたケースで使うのが「可変長引数(かへんちょうひきすう、varargs)」です。
可変長引数は、型のうしろに ...(ピリオド3つ)を付けて宣言します。これにより、その引数には0個以上の値をいくつでも渡せるようになります。
public class Calculator {
static int sum(int... nums) {
int total = 0;
for (int n : nums) {
total += n;
}
return total;
}
public static void main(String[] args) {
System.out.println(sum()); // 0
System.out.println(sum(1, 2)); // 3
System.out.println(sum(1, 2, 3, 4)); // 10
}
}
この int... nums は、メソッドの内部では実質的に配列(int[])として扱われます。そのため、拡張for文(配列の要素を先頭から順に取り出せるfor文。for (int n : nums))でひとつずつ取り出して処理できるのです。配列について自信がない方は、過去の「配列」に関する記事もあわせて読んでみてください。
可変長引数を使うときの注意点
可変長引数には、いくつか押さえておきたいルールがあります。
- 1つのメソッドに書けるのは1個まで。複数の可変長引数を並べることはできません。
- 可変長引数は、必ず引数リストの一番最後に書く必要があります。
- 固定の引数と組み合わせることも可能です(例:
void greet(String name, String... titles))。
また、オーバーロードと可変長引数は組み合わせて使うこともできます。「基本の呼び出し方は決め打ちのメソッドで対応し、それ以外の細かいパターンは可変長引数で受け止める」という使い分けです。状況に応じて使い分けると、コードが読みやすくなります。
まとめ
今回は、Javaにおける関数(メソッド)の応用として、デフォルト引数の代わりとなる「オーバーロード」と、引数の数を柔軟にする「可変長引数(varargs)」を紹介しました。Javaにはデフォルト引数という機能そのものはありませんが、オーバーロードでほぼ同じことを実現でき、可変長引数を使えば「引数がいくつあっても対応できる関数」も書けます。
他言語の書き方をそのままJavaに持ち込もうとすると戸惑う場面もありますが、「Javaにはこういう考え方の代替手段がある」と知っておくだけで、コードの見通しがぐっとよくなります。ぜひ実際に手元で動かして、感覚をつかんでみてください。
関連記事
本ページはプロモーションを含みます。
参考書籍(PR)
Javaをもっと学びたい方には「スッキリわかるJava入門 第4版」がおすすめです。
コメント
コメントを投稿