Java | オブジェクト指向:メソッド内ローカル変数

Java Java
スポンサーリンク

ローカル変数の全体像

メソッド内ローカル変数は「メソッドの中だけで使える一時的なメモ」。メソッドが呼ばれている間だけ存在し、終わったら消えます。オブジェクトの状態(フィールド)とは別物で、外から見えません。初期化しないと使えない、スコープ(見える範囲)がブロックで区切られる、というルールを理解すると安全に書けます。


宣言・初期化・スコープ(基本のルール)

宣言と初期化

ローカル変数は宣言しただけでは使えません。「必ず初期化してから」使います。フィールドと違い、デフォルト値は自動で入りません。

public void greet(String name) {
    String trimmed = name == null ? "" : name.trim(); // 初期化
    if (trimmed.isEmpty()) System.out.println("Hello, guest");
    else System.out.println("Hello, " + trimmed);
}
Java

未初期化のローカル変数を使おうとするとコンパイルエラーになります。これは「初期化忘れによるバグ」を防ぐための強いガードです。

スコープ(見える範囲)

ローカル変数は「宣言したブロックの内側」でのみ見えます。ブロックを出ると存在しない扱いになります。

public void demo(boolean ok) {
    if (ok) {
        int count = 1;
        System.out.println(count);
    }
    // System.out.println(count); // エラー:ここからは見えない
}
Java

同じ名前を内側で宣言すると外側を隠してしまい(シャドーイング)、読みづらくなります。基本は避けましょう。


ライフサイクルとメモリ(重要ポイントの深掘り)

いつ生まれていつ消えるか

ローカル変数はメソッドの呼び出し開始で生まれ、ブロック終了で消えます。JVMでは主にスタックフレーム上に置かれ、メソッドが終わるとフレームごと破棄されます。フィールドのように「長生き」しないため、スレッド安全性が高く、使い捨ての計算に向いています。

使い回しより「狭いスコープ」が正解

変数の有効範囲はできるだけ狭く取るほど、誤用や改変リスクが減ります。必要な直前で宣言・初期化し、使い終えたらブロックを閉じるクセをつけましょう。

public int sum(java.util.List<Integer> xs) {
    int total = 0;                      // ここでだけ使う
    for (int x : xs) total += x;
    return total;
}
Java

final・実質的 final・ラムダ・内部クラス

final と「実質的 final」

ローカル変数に final を付けると「再代入禁止」になります。ラムダ式やローカル内部クラスが外側の変数を参照するには、その変数が「final または実質的 final(結果として一度も再代入していない)」である必要があります。

public void capture() {
    final String prefix = "Hi"; // または、一度も再代入しないなら final 省略でも可
    Runnable r = () -> System.out.println(prefix); // 参照可能
    r.run();
}
Java

再代入した変数はラムダで参照できません。予期せぬ変更を避け、並行性や読みやすさを守るための設計上のルールです。

ローカルクラスとキャプチャ

メソッド内でクラスを定義する「ローカルクラス」も、外側のローカル変数を参照するには同じく final/実質的 final が必要です。

public void localClass() {
    String msg = "ok";
    class Printer { void print() { System.out.println(msg); } }
    new Printer().print(); // msg は再代入していないので参照可
}
Java

型推論(var)と可読性

var の使いどころ

Java 10 以降、ローカル変数は var で型推論できます。右辺から型が明確に分かるときに使うと、重複を減らして読みやすくなります。

var list = new java.util.ArrayList<String>(); // 右辺で型が明確
var name = "Taro";                            // String と分かる
Java

ただし、戻り値がインターフェース型や複雑なジェネリクスで「何の型か分かりにくい」場合は、明示的な型を残す方が読み手に優しいです。


例外・リソースとローカル変数

try-with-resources で安全に閉じる

ファイルやソケットなど「閉じる責務があるリソース」は、ローカル変数に受けて try-with-resources を使うと、ブロック終端で自動クローズされます。

import java.nio.file.*;
import java.nio.charset.StandardCharsets;

public void read(Path p) throws java.io.IOException {
    try (var br = Files.newBufferedReader(p, StandardCharsets.UTF_8)) {
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
    } // ここで br が自動クローズ
}
Java

リソース変数のスコープを最小にすると、扱いが安全になります。


シャドーイングと this の明示

フィールドと同名のローカルは避ける

ローカルがフィールド名を隠すと混乱します。どうしても同名になるなら、フィールド側は this.field と明示して誤解を防ぎます。

public final class Product {
    private String name;
    public void rename(String name) {
        var x = name == null ? "" : name.trim();
        if (!x.isEmpty()) this.name = x; // フィールド更新を明示
    }
}
Java

例題で身につける

例 1: 入力の正規化と短いスコープ

public int countWords(String text) {
    String trimmed = text == null ? "" : text.trim(); // ここだけで使う
    if (trimmed.isEmpty()) return 0;
    String normalized = trimmed.replaceAll("\\s+", " "); // ここだけで使う
    return normalized.split(" ").length;
}
Java

「使う直前で宣言・初期化」「使い終わったらスコープを抜けて消える」ことで、変数の迷子を防ぎます。

例 2: var と明示型のバランス

public java.util.List<String> top3(java.util.List<String> names) {
    var sorted = new java.util.ArrayList<>(names); // 右辺から型が分かる
    sorted.sort(String::compareTo);
    java.util.List<String> head = sorted.subList(0, Math.min(3, sorted.size())); // 戻り型が List と分かるよう明示
    return head;
}
Java

「読めるかどうか」で var か明示型かを選びます。

例 3: ラムダでのキャプチャ

public void runTasks(java.util.List<String> tasks) {
    int size = tasks.size(); // 実質的 final(再代入なし)
    tasks.forEach(t -> System.out.println(size + ": " + t)); // 参照可能
}
Java

size を再代入するとラムダから参照できなくなるため、値を変えない設計にします。


よくあるつまずきと回避

初期化忘れ

フィールドはデフォルトが入りますが、ローカルは入りません。必ず初期化してから使う。分岐で初期化されない経路がないかを意識しましょう。

スコープが広すぎる

メソッド冒頭で「とりあえず全部」宣言すると、後半で誤用や再代入の危険が増えます。必要な直前で最小スコープに。

シャドーイングによる混乱

フィールドと同名のローカルを作らない。やむを得ず同名なら this.field を明示し、ローカル名は意味のある別名にする。

var の乱用

型が分かりづらくなるなら var は使わない。右辺が明確なときだけ使う。


仕上げのアドバイス(重要部分のまとめ)

ローカル変数は「短命で安全な作業メモ」。必ず初期化してから使い、スコープは最小に、シャドーイングは避ける。ラムダやローカルクラスで参照するなら final/実質的 final に保つ。var は「分かりやすいときだけ」。リソースは try-with-resources で閉じる——この型を守ると、メソッドの読みやすさと安全性が一気に上がります。

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