DEV Community

TANIAOKA, Akihiro
TANIAOKA, Akihiro

Posted on

8章4

このJavaコードは、Runnableインターフェースの実装としてラムダ式を使用してスレッドを生成し、実行しています。私はこのコードにコメントを加えて、どのように動作するのかを説明し、それがなぜ答えD「コンパイルエラーが発生する」になるのかを解説します。

public class Sample {
    public static void main(String[] args) {
        int cnt = 0; // メインメソッドのスコープでカウンタ変数cntを宣言して0で初期化

        // ラムダ式を使ってRunnableインターフェースの実装を作成
        Runnable r = () -> {
            // ラムダ式の中でcnt変数を再宣言している。これはスコープが異なるためエラーにはならないが、
            // このcntは外側のcnt変数とは異なる変数である。
            for (cnt = 0; cnt < 10; cnt++) {
                // このcnt++はループの中でカウンタを増やすために使われているが、
                // これが実際にはラムダ式の外側のcnt変数を変更しようとしていることになる。
                // Javaのラムダ式では、ラムダ式の外側のローカル変数を変更することは許されていない。
                // この行はコンパイルエラーを発生させる。
                System.out.println(cnt++);
            }
        };

        // 新しいスレッドを作成してラムダ式を実行
        new Thread(r).start();
    }
}
Enter fullscreen mode Exit fullscreen mode

このコードの問題点は、ラムダ式内で外部のローカル変数cntを変更しようとしていることです。Javaでは、ラムダ式から参照される外部のローカル変数は実質的にfinalである必要があります。つまり、ラムダ式内部で変更することはできません。しかし、ここではforループの中でcnt++というインクリメント演算を行っているため、コンパイルエラーが発生します。

そのため、答えは「D. コンパイルエラーが発生する」となります。

追記

コンパイルエラーを避けるには、ラムダ式内で外部のローカル変数を変更しないようにする必要があります。このコードでは、Runnableインターフェースの実装内でループ変数cntを使用していますが、これが外部スコープの変数cntと衝突しています。コンパイルエラーを避けるためには、ラムダ式内で使用するカウンタ変数を独立させる必要があります。

以下はそのための修正案です:

public class Sample {
    public static void main(String[] args) {
        // ラムダ式から参照されるローカル変数はfinalまたは実質的finalである必要があるため、
        // ラムダ式内で変更する変数はラムダ式内で宣言する。

        Runnable r = () -> {
            for (int i = 0; i < 10; i++) {
                // ラムダ式内で独立したループカウンタiを使用。
                System.out.println(i);
            }
        };

        // Runnableの実装をThreadコンストラクタに渡してスレッドを起動
        new Thread(r).start();
    }
}
Enter fullscreen mode Exit fullscreen mode

この変更により、Runnableの実装内で新しいカウンタ変数iを導入しました。この変数はRunnableの実装内でのみスコープされるため、外部の変数に干渉せず、コンパイルエラーが発生しません。また、Runnable実装外で宣言されたcnt変数はもはや不要なので、削除することができます。

Top comments (0)