Java | 基礎文法:引数

Java Java
スポンサーリンク

引数の全体像

引数は「メソッドが外から受け取る入力」です。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 の扱いと検証は入口で統一し、引数評価の副作用は事前分解で排除する。コマンドライン引数は文字列前提で安全に変換する。

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