引数の全体像
引数は「メソッドが外から受け取る入力」です。Java では、メソッド定義側で「型と名前」を宣言し、呼び出し側がその順番に値を渡します。戻り値は結果、引数は材料。設計の核心は「正しい型」「順番と意味の明確化」「不正入力の早期検出」です。
定義と呼び出しの基本
最小の書式
static int add(int a, int b) { // ここが「引数定義」
return a + b;
}
int s = add(3, 8); // ここが「引数の受け渡し」
Java定義側は「型 名」の並びで引数を宣言します。呼び出し側は同じ順番で値を渡します。Java には「デフォルト引数」や「名前付き引数」はありません。必要ならオーバーロードやビルダーで表現します。
意味が伝わる名前
static int calcDiscount(int subtotal, int memberYears) { ... }
Java「何を表す引数か」が名前から分かると、誤用が減ります。a, b, x など抽象名は最小限に留めましょう。
値渡しの本質(重要ポイントの深掘り)
Java の引数はすべて「値渡し」
プリミティブは値そのもの、参照型は「参照の値」が渡されます。参照先の「中身」は変更が反映されますが、参照自体の再代入は呼び出し元に影響しません。
class Box { int v; }
static void bump(Box b) { b.v++; } // 中身変更は反映
static void reassign(Box b) { b = new Box(); } // 参照再代入は反映されない
Box box = new Box();
bump(box); // box.v が増える
reassign(box); // box は同じインスタンスのまま
Java引数で受け取った参照に対し「状態変更」を行うか、「不変(イミュータブル)」を受けて副作用を避けるかを、設計として明確にします。
プリミティブと参照型の違い
値がその場で変わるか、オブジェクトの中身が変わるか
static void inc(int x) { x++; } // 呼び出し元の値は変わらない
int n = 10; inc(n); // n は 10 のまま
static void append(StringBuilder sb) { sb.append("!"); } // 参照先の中身は変わる
StringBuilder buf = new StringBuilder("Hi"); append(buf);
// buf は "Hi!"
Java「変わっていいのか」を契約に含めましょう。変更するならメソッド名に動詞(update, add, remove)を入れ、不変を期待するならイミュータブル型(String, List.copyOf など)を受けると安全です。
可変長引数とオーバーロード(重要ポイントの深掘り)
可変長引数(varargs)
static int sum(int... nums) {
int s = 0;
for (int n : nums) s += n;
return s;
}
sum(); // 0個でも呼べる
sum(1, 2, 3); // 個数可変
sum(new int[]{4, 5}); // 配列でも渡せる
Java内部では配列として扱われます。引数が多く、意味が混在する場合は「明示の配列やコレクション」を受けるほうが可読性が上がります。
オーバーロード解決
static int mul(int a, int b) { return a * b; }
static double mul(double a, double b) { return a * b; }
var x = mul(3, 4); // int 版
var y = mul(3.0, 4.0); // double 版
Java曖昧な呼び出しはコンパイルエラーになります。必要なら明示キャストで意図を示してください。
null 安全性と契約
受け取る側と渡す側の約束
static String safeUpper(String s) {
if (s == null) return ""; // 契約:nullなら空文字を返す
return s.toUpperCase();
}
Java「null を許容するか」を決めて、ドキュメントや名前で明示します。許容しないなら入口で Objects.requireNonNull(s, "...") のように早期検証し、呼び出し側に責任を返す設計も有効です。
引数評価の順序と副作用
左から右へ評価される
int a = 1, b = 2;
int r = add(a++, a + b); // 先に a++(a=2)→ 次に a+b(4)
Java副作用(++, --)を混ぜると読みづらく、意図が伝わりません。事前に中間変数へ分解してから渡すと安全です。
コマンドライン引数(main の args)
文字列配列として受け取る
public class App {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("引数がありません");
return;
}
System.out.println("最初の引数: " + args[0]);
}
}
Javaコマンドライン引数はすべて文字列です。数値が欲しい場合は Integer.parseInt(args[0]) のように明示的に変換し、失敗時のハンドリング(例外または既定値)を入れます。
実用例で身につける
例 1: バリデーションしてから処理
static int discount(int subtotal, int memberYears) {
if (subtotal < 0) throw new IllegalArgumentException("subtotal >= 0");
if (memberYears < 0) memberYears = 0; // 入力を正規化
int rate = (memberYears >= 5) ? 10 : 5;
return subtotal * rate / 100;
}
Java入口で前提を整えると、以降のロジックがシンプルになります。
例 2: 参照型を防御的に受ける
static java.util.List<String> top3(java.util.List<String> src) {
if (src == null) return java.util.List.of();
int n = Math.min(3, src.size());
return java.util.List.copyOf(src.subList(0, n)); // 外部から変更されない防御的コピー
}
Java受け取ったコレクションをそのまま保持せず、防御的コピーで契約を守ると副作用に強くなります。
例 3: 可変長引数でオプションを受ける
static String join(String sep, String... parts) {
if (parts == null || parts.length == 0) return "";
StringBuilder sb = new StringBuilder(parts[0]);
for (int i = 1; i < parts.length; i++) {
sb.append(sep).append(parts[i]);
}
return sb.toString();
}
Java「必須+可変」は、必須を先に固定引数で受けると、呼び出し側の意図が明確です。
設計の指針(重要部分のまとめ)
引数は「契約」。型と順番で意図を伝え、名前で意味を明確化します。Java は値渡しなので、参照型の変更可否を設計として決め、必要なら防御的コピーやイミュータブルで副作用を制御します。可変長引数やオーバーロードは便利ですが、曖昧さを避けて可読性を優先。null の扱いと検証は入口で統一し、引数評価の副作用は事前分解で排除する。コマンドライン引数は文字列前提で安全に変換する。
