はじめに

プログラムを書いていると、同じ処理を何度も繰り返し記述する場面に遭遇します。コードの重複は保守性を低下させ、バグの温床となります。Javaではメソッドを使用して処理を部品化し、再利用可能なコードを設計できます。

この記事では、メソッドの基本的な定義方法から始まり、引数と戻り値の扱い方、同名メソッドを複数定義するオーバーロード、任意の数の引数を受け取る可変長引数、そしてstaticメソッドインスタンスメソッドの違いまで、段階的に解説します。

メソッドとは何か

メソッドとは、特定の処理をまとめた「名前付きのコードブロック」です。一度定義すれば、プログラムの任意の場所から呼び出して実行できます。

メソッドを使う3つのメリット

メリット 説明
再利用性 同じ処理を何度も書く必要がなくなる
可読性 処理に名前を付けることでコードの意図が明確になる
保守性 修正が必要な場合、メソッド内を変更するだけで済む

メソッドなしのコード vs メソッドありのコード

メソッドを使わない場合、同じ処理を繰り返し記述する必要があります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class WithoutMethod {
    public static void main(String[] args) {
        // 1回目の挨拶
        System.out.println("==================");
        System.out.println("こんにちは、田中さん!");
        System.out.println("==================");

        // 2回目の挨拶
        System.out.println("==================");
        System.out.println("こんにちは、佐藤さん!");
        System.out.println("==================");

        // 3回目の挨拶
        System.out.println("==================");
        System.out.println("こんにちは、鈴木さん!");
        System.out.println("==================");
    }
}

メソッドを使用すると、処理を一箇所にまとめて再利用できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class WithMethod {
    public static void main(String[] args) {
        greet("田中");
        greet("佐藤");
        greet("鈴木");
    }

    public static void greet(String name) {
        System.out.println("==================");
        System.out.println("こんにちは、" + name + "さん!");
        System.out.println("==================");
    }
}

コード量が減り、挨拶の形式を変更したい場合もgreetメソッド内を修正するだけで済みます。

メソッドの定義方法

Javaのメソッドは、以下の構文で定義します。

1
2
3
4
アクセス修飾子 修飾子 戻り値の型 メソッド名(引数リスト) {
    // メソッドの処理
    return 戻り値; // 戻り値がある場合
}

各要素の役割を詳しく見ていきましょう。

アクセス修飾子

メソッドへのアクセス範囲を制御します。

修飾子 アクセス範囲
public すべてのクラスからアクセス可能
protected 同じパッケージ内、またはサブクラスからアクセス可能
なし(パッケージプライベート) 同じパッケージ内からのみアクセス可能
private 同じクラス内からのみアクセス可能
1
2
3
4
public void publicMethod() { }      // どこからでも呼び出せる
protected void protectedMethod() { } // 同パッケージまたはサブクラスから
void packageMethod() { }            // 同パッケージからのみ
private void privateMethod() { }    // このクラス内からのみ

戻り値の型

メソッドが処理結果として返す値の型を指定します。値を返さない場合はvoidを使用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 戻り値がないメソッド
public void printMessage(String message) {
    System.out.println(message);
}

// 戻り値があるメソッド
public int add(int a, int b) {
    return a + b;
}

// 戻り値がString型のメソッド
public String createGreeting(String name) {
    return "こんにちは、" + name + "さん!";
}

引数(パラメータ)

メソッドに渡すデータを定義します。引数がない場合は空の括弧()を使用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 引数なし
public void sayHello() {
    System.out.println("Hello!");
}

// 引数が1つ
public void printNumber(int number) {
    System.out.println("数値: " + number);
}

// 引数が複数
public double calculateBMI(double weight, double height) {
    return weight / (height * height);
}

基本的なメソッドの例

以下は、2つの整数の最大値を返すメソッドの例です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class MethodExample {
    public static void main(String[] args) {
        int result = max(10, 25);
        System.out.println("最大値: " + result); // 最大値: 25
    }

    public static int max(int a, int b) {
        if (a > b) {
            return a;
        } else {
            return b;
        }
    }
}

三項演算子を使用すると、より簡潔に記述できます。

1
2
3
public static int max(int a, int b) {
    return (a > b) ? a : b;
}

メソッドの呼び出し

定義したメソッドを実行するには、メソッド名と引数を指定して呼び出します。

同じクラス内のメソッド呼び出し

同じクラス内のメソッドは、メソッド名だけで呼び出せます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class Calculator {
    public static void main(String[] args) {
        // 同じクラス内のstaticメソッドを呼び出す
        int sum = add(5, 3);
        System.out.println("合計: " + sum); // 合計: 8

        double avg = average(10, 20, 30);
        System.out.println("平均: " + avg); // 平均: 20.0
    }

    public static int add(int a, int b) {
        return a + b;
    }

    public static double average(int a, int b, int c) {
        return (a + b + c) / 3.0;
    }
}

別のクラスのメソッド呼び出し

別のクラスのメソッドを呼び出す場合は、クラス名またはオブジェクトを経由します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// MathUtilsクラス
public class MathUtils {
    public static int square(int n) {
        return n * n;
    }
}

// Mainクラスから呼び出す
public class Main {
    public static void main(String[] args) {
        // クラス名.メソッド名で呼び出す
        int result = MathUtils.square(5);
        System.out.println("5の二乗: " + result); // 5の二乗: 25
    }
}

戻り値の活用パターン

メソッドの戻り値は、様々な方法で活用できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ReturnValueExample {
    public static void main(String[] args) {
        // 1. 変数に格納する
        int result = multiply(3, 4);
        System.out.println(result);

        // 2. 直接出力する
        System.out.println(multiply(5, 6));

        // 3. 別のメソッドの引数として使用する
        System.out.println(multiply(multiply(2, 3), 4)); // (2*3)*4 = 24

        // 4. 条件式で使用する
        if (multiply(2, 5) > 8) {
            System.out.println("10は8より大きい");
        }
    }

    public static int multiply(int a, int b) {
        return a * b;
    }
}

オーバーロード(同名メソッドの多重定義)

オーバーロード(Overload) とは、同じ名前のメソッドを、異なる引数リストで複数定義することです。これにより、似た処理を直感的な名前で統一できます。

オーバーロードの条件

メソッドをオーバーロードするには、以下のいずれかが異なる必要があります。

条件 説明
引数の数 引数の個数が異なる
引数の型 引数の型が異なる
引数の順序 引数の型の並び順が異なる

戻り値の型だけが異なる場合は、オーバーロードとして認められません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class OverloadExample {
    public static void main(String[] args) {
        System.out.println(add(1, 2));           // 3
        System.out.println(add(1, 2, 3));        // 6
        System.out.println(add(1.5, 2.5));       // 4.0
        System.out.println(add("Hello", "Java")); // HelloJava
    }

    // int型の引数2つ
    public static int add(int a, int b) {
        return a + b;
    }

    // int型の引数3つ
    public static int add(int a, int b, int c) {
        return a + b + c;
    }

    // double型の引数2つ
    public static double add(double a, double b) {
        return a + b;
    }

    // String型の引数2つ(文字列連結)
    public static String add(String a, String b) {
        return a + b;
    }
}

標準ライブラリでのオーバーロード例

Javaの標準ライブラリでもオーバーロードは多用されています。System.out.println()は代表的な例です。

1
2
3
4
5
6
System.out.println();           // 引数なし(改行のみ)
System.out.println(42);         // int型
System.out.println(3.14);       // double型
System.out.println(true);       // boolean型
System.out.println("Hello");    // String型
System.out.println(new int[]{1, 2, 3}); // Object型(配列)

String.valueOf()も多くのオーバーロードを持っています。

1
2
3
4
String.valueOf(100);      // "100"
String.valueOf(3.14);     // "3.14"
String.valueOf(true);     // "true"
String.valueOf('A');      // "A"

オーバーロード使用時の注意点

引数の自動型変換により、意図しないメソッドが呼び出される場合があります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class OverloadCaution {
    public static void main(String[] args) {
        print(10);    // int版が呼ばれる
        print(10L);   // long版が呼ばれる
        print(10.0);  // double版が呼ばれる
        print(10.0f); // float版がなければdouble版が呼ばれる
    }

    public static void print(int value) {
        System.out.println("int: " + value);
    }

    public static void print(long value) {
        System.out.println("long: " + value);
    }

    public static void print(double value) {
        System.out.println("double: " + value);
    }
}

可変長引数(varargs)

可変長引数(Variable-length Arguments) を使用すると、任意の数の引数を受け取るメソッドを定義できます。引数の型の後に...を付けて宣言します。

可変長引数の基本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class VarargsExample {
    public static void main(String[] args) {
        System.out.println(sum());           // 0
        System.out.println(sum(1));          // 1
        System.out.println(sum(1, 2));       // 3
        System.out.println(sum(1, 2, 3, 4, 5)); // 15

        // 配列を渡すことも可能
        int[] numbers = {10, 20, 30};
        System.out.println(sum(numbers));    // 60
    }

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

可変長引数は、メソッド内部では配列として扱われます。

可変長引数のルール

可変長引数を使用する際は、以下のルールに従う必要があります。

ルール 説明
位置の制限 可変長引数は引数リストの最後に配置する
個数の制限 1つのメソッドに可変長引数は1つのみ
他の引数との組み合わせ 通常の引数の後に可変長引数を配置可能
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 正しい使い方
public static void log(String level, String... messages) {
    System.out.print("[" + level + "] ");
    for (String msg : messages) {
        System.out.print(msg + " ");
    }
    System.out.println();
}

// コンパイルエラー:可変長引数が最後でない
// public static void invalid(int... numbers, String label) { }

// コンパイルエラー:可変長引数が複数ある
// public static void invalid(int... a, String... b) { }

可変長引数の実用例

ログ出力やフォーマット処理など、実際の開発で役立つ例を紹介します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class VarargsUseCases {
    public static void main(String[] args) {
        // 複数の値を一度に出力
        printAll("Java", "Python", "JavaScript");

        // 最大値を取得
        int max = findMax(5, 2, 8, 1, 9, 3);
        System.out.println("最大値: " + max); // 最大値: 9

        // 文字列を区切り文字で連結
        String joined = join("-", "2026", "01", "04");
        System.out.println(joined); // 2026-01-04
    }

    public static void printAll(String... values) {
        for (String value : values) {
            System.out.println(value);
        }
    }

    public static int findMax(int first, int... rest) {
        int max = first;
        for (int n : rest) {
            if (n > max) {
                max = n;
            }
        }
        return max;
    }

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

値渡しと参照渡しの違い

Javaでは、メソッドに引数を渡す際の動作がプリミティブ型参照型で異なります。この違いを正しく理解することは、バグを防ぐために重要です。

プリミティブ型は「値渡し」

プリミティブ型(intdoublebooleanなど)を引数として渡す場合、値のコピーがメソッドに渡されます。メソッド内で値を変更しても、呼び出し元の変数には影響しません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class PrimitivePassByValue {
    public static void main(String[] args) {
        int number = 10;
        System.out.println("呼び出し前: " + number); // 10

        changeValue(number);
        System.out.println("呼び出し後: " + number); // 10(変化なし)
    }

    public static void changeValue(int n) {
        n = 100; // コピーされた値を変更
        System.out.println("メソッド内: " + n); // 100
    }
}
sequenceDiagram
    participant Main as main()
    participant Method as changeValue()
    Main->>Main: number = 10
    Main->>Method: 10(コピー)を渡す
    Method->>Method: n = 100(コピーを変更)
    Method-->>Main: 戻る
    Main->>Main: number は 10 のまま

参照型は「参照値の値渡し」

参照型(配列、オブジェクト)を引数として渡す場合、参照(メモリアドレス)のコピーがメソッドに渡されます。参照先のオブジェクトは同じなので、メソッド内での変更は呼び出し元にも影響します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class ReferencePassByValue {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3};
        System.out.println("呼び出し前: " + numbers[0]); // 1

        changeArray(numbers);
        System.out.println("呼び出し後: " + numbers[0]); // 100(変化した)
    }

    public static void changeArray(int[] arr) {
        arr[0] = 100; // 同じ配列オブジェクトを変更
        System.out.println("メソッド内: " + arr[0]); // 100
    }
}
sequenceDiagram
    participant Main as main()
    participant Heap as ヒープ領域
    participant Method as changeArray()
    Main->>Heap: numbers配列を作成 [1,2,3]
    Main->>Method: 参照(アドレス)のコピーを渡す
    Method->>Heap: arr[0] = 100(同じ配列を変更)
    Method-->>Main: 戻る
    Main->>Heap: numbers[0] は 100

参照自体の再代入は影響しない

メソッド内で参照変数に新しいオブジェクトを代入しても、呼び出し元の参照は変わりません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class ReferenceReassignment {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3};
        System.out.println("呼び出し前: " + numbers[0]); // 1

        reassignArray(numbers);
        System.out.println("呼び出し後: " + numbers[0]); // 1(変化なし)
    }

    public static void reassignArray(int[] arr) {
        arr = new int[]{100, 200, 300}; // 新しい配列を代入(参照のコピーを変更)
        System.out.println("メソッド内: " + arr[0]); // 100
    }
}

文字列(String)の特殊な動作

Stringは参照型ですが、イミュータブル(不変) なので、メソッド内での操作が呼び出し元に影響することはありません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class StringImmutable {
    public static void main(String[] args) {
        String message = "Hello";
        System.out.println("呼び出し前: " + message); // Hello

        changeString(message);
        System.out.println("呼び出し後: " + message); // Hello(変化なし)
    }

    public static void changeString(String str) {
        str = str + " World"; // 新しいStringオブジェクトが作成される
        System.out.println("メソッド内: " + str); // Hello World
    }
}

staticメソッドとインスタンスメソッド

Javaのメソッドは、staticメソッド(クラスメソッド)インスタンスメソッドの2種類に分類されます。

staticメソッドとは

staticキーワードを付けて定義するメソッドです。クラスに属し、インスタンスを作成せずに呼び出せます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public class StaticMethodExample {
    // staticメソッド
    public static int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        // クラス名.メソッド名で呼び出す
        int result = StaticMethodExample.add(5, 3);
        System.out.println(result); // 8

        // 同じクラス内ではクラス名を省略可能
        System.out.println(add(10, 20)); // 30
    }
}

インスタンスメソッドとは

staticキーワードを付けずに定義するメソッドです。オブジェクト(インスタンス)に属し、呼び出すにはインスタンスの作成が必要です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class InstanceMethodExample {
    private String name;

    // コンストラクタ
    public InstanceMethodExample(String name) {
        this.name = name;
    }

    // インスタンスメソッド
    public void greet() {
        System.out.println("こんにちは、" + this.name + "さん!");
    }

    public static void main(String[] args) {
        // インスタンスを作成してから呼び出す
        InstanceMethodExample obj = new InstanceMethodExample("田中");
        obj.greet(); // こんにちは、田中さん!
    }
}

staticメソッドとインスタンスメソッドの違い

特徴 staticメソッド インスタンスメソッド
所属 クラス インスタンス(オブジェクト)
呼び出し方 クラス名.メソッド名() インスタンス.メソッド名()
インスタンス変数へのアクセス 不可 可能
thisの使用 不可 可能
用途 ユーティリティ処理、ファクトリーメソッド オブジェクトの状態を扱う処理

staticメソッドの制約

staticメソッドからは、同じクラスのインスタンス変数やインスタンスメソッドに直接アクセスできません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class StaticRestriction {
    private String instanceField = "インスタンスフィールド";
    private static String staticField = "staticフィールド";

    public void instanceMethod() {
        System.out.println(instanceField);  // OK
        System.out.println(staticField);    // OK
        staticMethod();                      // OK
    }

    public static void staticMethod() {
        // System.out.println(instanceField); // コンパイルエラー
        System.out.println(staticField);      // OK
        // instanceMethod();                  // コンパイルエラー
    }

    public static void main(String[] args) {
        // staticメソッドからインスタンスメソッドを呼ぶには
        // インスタンスを作成する必要がある
        StaticRestriction obj = new StaticRestriction();
        obj.instanceMethod();
    }
}

使い分けの指針

staticメソッドとインスタンスメソッドの使い分けは、以下の基準で判断してください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class MethodTypeGuideline {

    // staticメソッドが適切な場合
    // 1. ユーティリティ処理(インスタンスの状態に依存しない)
    public static int max(int a, int b) {
        return (a > b) ? a : b;
    }

    // 2. ファクトリーメソッド(インスタンス生成をカプセル化)
    public static MethodTypeGuideline create(String config) {
        return new MethodTypeGuideline();
    }

    // インスタンスメソッドが適切な場合
    private int count;

    // 3. インスタンスの状態を読み取る・変更する処理
    public void increment() {
        this.count++;
    }

    public int getCount() {
        return this.count;
    }
}

標準ライブラリでの例

Javaの標準ライブラリを見ると、staticメソッドとインスタンスメソッドの使い分けが参考になります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// staticメソッドの例
int maxValue = Math.max(10, 20);           // 計算ユーティリティ
int parsed = Integer.parseInt("42");       // 変換ユーティリティ
List<String> list = List.of("a", "b");     // ファクトリーメソッド

// インスタンスメソッドの例
String text = "Hello, Java";
int length = text.length();                // 文字列の状態を取得
String upper = text.toUpperCase();         // 文字列を操作

List<String> names = new ArrayList<>();
names.add("田中");                          // リストの状態を変更
int size = names.size();                   // リストの状態を取得

よくあるエラーと対処法

メソッドを使用する際によく発生するエラーとその対処法をまとめます。

return文の欠落

戻り値の型がvoid以外のメソッドでは、すべての経路でreturn文が必要です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// コンパイルエラー:returnがない経路が存在する
public static int badMethod(int n) {
    if (n > 0) {
        return n;
    }
    // n <= 0 の場合のreturnがない
}

// 修正版
public static int goodMethod(int n) {
    if (n > 0) {
        return n;
    }
    return 0; // すべての経路でreturnを用意
}

引数の型不一致

メソッド呼び出し時に、定義された引数の型と互換性のない型を渡すとエラーになります。

1
2
3
4
5
6
7
8
public static void printNumber(int n) {
    System.out.println(n);
}

// 使用例
// printNumber("Hello"); // コンパイルエラー:Stringはintに変換できない
printNumber(42);         // OK
printNumber((int) 3.14); // OK:明示的キャストでintに変換

staticコンテキストからの非staticアクセス

mainメソッドなどのstaticメソッドから、インスタンスメンバーに直接アクセスしようとするとエラーになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class StaticContextError {
    private int value = 10;

    public void instanceMethod() {
        System.out.println("インスタンスメソッド");
    }

    public static void main(String[] args) {
        // System.out.println(value);  // コンパイルエラー
        // instanceMethod();           // コンパイルエラー

        // 解決策:インスタンスを作成する
        StaticContextError obj = new StaticContextError();
        System.out.println(obj.value);
        obj.instanceMethod();
    }
}

まとめ

この記事では、Javaのメソッドについて基礎から応用まで解説しました。

項目 ポイント
メソッドの基本 処理を部品化し、再利用性・可読性・保守性を向上させる
定義の構文 アクセス修飾子 戻り値の型 メソッド名(引数) { 処理 }
オーバーロード 引数の数・型・順序が異なれば同名メソッドを複数定義可能
可変長引数 型... 引数名で任意の数の引数を受け取れる
値渡し プリミティブ型は値のコピー、参照型は参照のコピーが渡される
static vs インスタンス staticはクラスに属し、インスタンスはオブジェクトに属する

次のステップとして、クラスとオブジェクトについて学ぶことで、オブジェクト指向プログラミングの本質を理解できるようになります。

参考リンク