エラーの読み方:赤い字のどこを見るか

はじめの一歩

プログラム|Java入門

エラーの読み方:赤い字のどこを見るか

前回は javac で翻訳して java で動かしました。 手が止まった人もいるでしょう。 それがエラーで、どこで・何に困ったかが書いてあります。 出る場所はおもに2か所。 翻訳するとき(javac)と、動かすときです。

図1 エラーが出る場所は2つ。翻訳のときと、動かしたとき

図1:エラーが出る場所は2つ。翻訳のときと、動かしたとき。

まず結論:この章の用語

用語意味
コンパイル人が書いた文を、機械寄りの形へ翻訳すること。javac がこれをする
コンパイラ翻訳をする道具そのもの。ここでは javac のこと
クラスファイル翻訳のあとにできる、名前が .class で終わるファイル。java が動かすのはこちら
コンパイルエラーjavac が翻訳をやめたときに出るエラー。翻訳が終わらないので、いま書いた文は動かない
実行時エラーjava のあとに出るエラー。翻訳はもう通っている
行番号ファイルの上から何行目かを表す数。エラー文の「Hello.java:3」の3がこれ
キャレットエラー文の下に出る山形の印。その行の左から何文字目で困ったかを指す
構文解析javac が、文の組み立てを上から順に追っていくこと
全角スペース日本語入力のときの広い空白。見た目は空白だが、Javaは1つの文字として扱う
パッケージJavaが部品をしまっている引き出しの名前。java.lang.NoClassDefFoundError の java.lang. までがこれで、うしろが困りごとの名前
ロードjava が、動かす相手のクラスファイルを読みこむこと。8章の「検出およびロード」がこれ
thread動いている処理の流れ。9章の Exception in thread “main” は main の流れのこと。いまは読み飛ばしてよい
Exception困りごとの知らせに付く英語。日本語では例外と言い、あつかい方は第26回で
BOMUTF-8 で保存するときに先頭へ付くことがある印。付いていると1行目に「’\ufeff’は不正な文字です」が出る

この章のゴール
エラー文を見て、翻訳か実行時か。何行目か。何に困っているか。の3つを言えるようになることです。

1. エラーが出るのはおもに2か所

図2 一度も翻訳が通っていなければ、クラスファイルはできません

図2:一度も翻訳が通っていなければ、クラスファイルはできません。

javac は、おかしいところを見つけるとクラスファイルを作りません。 まだ一度も翻訳が通っていなければ、java が動かす相手は無く、1行も動きません。

通ればクラスファイルができて、そこから先は動かしている途中のエラー。 javac のあとならコンパイルエラー、java のあとなら実行時エラー。

ただし javac 自体が見つからないという文は、javac が動く前なのでどちらでもありません(第1回8章)。

2. お手本をひとつ持っておく

図3 翻訳がうまくいくと、フォルダにクラスファイルが増えます

図3:翻訳がうまくいくと、フォルダにクラスファイルが増えます。

壊す前に、正しく動く形を用意します。 この回の画面はすべて日本語の Windows 11 と Java 21 で出たものです。 エディタ(メモ帳など)でこれを書き、新しいフォルダに Hello.java という名前で、文字コードは UTF-8(BOM なし) で保存してください。 この6行は別の名前でも保存しておきます。 何度も戻します。

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello");
        System.out.println("Java");
    }
}

そのフォルダのアドレス欄に cmd と打って開いたコマンドプロンプト(ターミナル)に打ちます。

> javac Hello.java
> java Hello
Hello
Java

先頭に「> 」が付いた行が打ちこむコマンド、その下が画面に出た文です。 javac は黙ったままで、かわりに Hello.class が増えます。 通ったかは画面ではなく、クラスファイルができたかで見ます。

ここで一度通したので、あとで javac が失敗しても Hello.class は残ります。 そのあと java を打つと、直す前の古いクラスファイルが動きます。 書き直したのに画面が変わらないときは、これを疑います。

3. セミコロンを1つ消す:エラー文は4つの部品

図4 エラー文はこの4つ。ファイル名・行番号・困っている内容・指している場所

図4:エラー文はこの4つ。ファイル名・行番号・困っている内容・指している場所。

3行目の行末のセミコロン( ; )を1つだけ消します。 ほかは同じです。 壊した形は図4にあります。

> javac Hello.java
Hello.java:3: エラー: ';'がありません
        System.out.println("Hello")
                                   ^
エラー1個

4つに分けます。 Hello.java がファイル名。 コロンのうしろの 3 が行番号で、上から3行目。 「’;’がありません」が困っている内容。 山形の印(キャレット)が、どこで困ったかを指します。

キャレットは閉じ丸括弧のすぐ右、「ここにセミコロンがほしかった」という意味です。 最後の「エラー1個」は件数です。

言語設定によっては、同じエラーが英語で出ます。 並びは同じで、言葉だけが変わります。

日本語で出る文英語で出る文
‘;’がありません‘;’ expected
‘\u3000’は不正な文字ですillegal character: ‘\u3000’
publicであり、…で宣言する必要がありますis public, should be declared in a file named …
構文解析中にファイルの終わりに移りましたreached end of file while parsing
エラー4個4 errors

4. 大文字と小文字は別の字

図5 Javaは大文字と小文字を別の字として探します

図5:Javaは大文字と小文字を別の字として探します。

お手本に戻して、3行目の System の S を小文字の s にします。

> javac Hello.java
Hello.java:3: エラー: パッケージsystemは存在しません
        system.out.println("Hello");
              ^
エラー1個

形は同じで、内容が「パッケージsystemは存在しません」に変わりました。 javac は system を引き出しの名前だと思って探し、見つからなかったのです。 キャレットは system のすぐ右のドットを指します。 「存在しません」と出たら、つづりを疑います。

5. 全角スペース:見えないのに止まる

図6 全角スペースは空白ではなく文字。4つ置けば4個出ます

図6:全角スペースは空白ではなく文字。4つ置けば4個出ます。

もう一度6行に戻してから、3行目の字下げの半角スペース8つを、全角スペース4つに置き換えます。 見た目は同じです。

> javac Hello.java
Hello.java:3: エラー: '\u3000'は不正な文字です
    System.out.println("Hello");
^
Hello.java:3: エラー: '\u3000'は不正な文字です
    System.out.println("Hello");
 ^
Hello.java:3: エラー: '\u3000'は不正な文字です
    System.out.println("Hello");
  ^
Hello.java:3: エラー: '\u3000'は不正な文字です
    System.out.println("Hello");
   ^
エラー4個

同じ内容が4回くり返され、最後に「エラー4個」と出ました。 全角スペース1つにつき1個です。 直すところは1か所、エラーの件数は4個です。

内容の ‘\u3000’ は全角スペースの番号です。 番号は 0〜9 のあとに A〜F と続く数え方(16進)で書くので、4桁の 3000 です。

キャレットも文字の下にそろいません。 全角スペースは幅が2つぶんなのに、数えるときは1文字だからです。 なお UTF-8 以外で保存すると、ここは別のエラーになります。 BOM が付いていると1行目に ‘\ufeff’は不正な文字です が増えて、件数も1つ増えます。

6. ファイル名とクラス名は同じにする

図7 publicと書いたクラスは、ファイル名と同じ名前でなければなりません

図7:publicと書いたクラスは、ファイル名と同じ名前でなければなりません。

こんどはファイルの名前です。 正しい形に直してから、Hello.java のまま、1行目のクラス名だけを Aisatsu に変えます。

> javac Hello.java
Hello.java:1: エラー: クラス Aisatsuはpublicであり、ファイルAisatsu.javaで宣言する必要があります
public class Aisatsu {
       ^
エラー1個

行番号は1で、内容には直し方まで書いてあります。 public と書いたクラスは、第1回・第2回のとおりファイル名とそろえる決まりです。

7. 行番号は「困った場所」

図8 行番号はコンパイラが困った場所。間違えた場所と1行ずれることがあります

図8:行番号はコンパイラが困った場所。間違えた場所と1行ずれることがあります。

行番号が指すのはjavac が困った場所で、打ち間違えた場所とは限りません。 控えから6行を戻し、6行目の閉じ波括弧を消して5行のファイルにします。

> javac Hello.java
Hello.java:5: エラー: 構文解析中にファイルの終わりに移りました
    }
     ^
エラー1個

消したのは6行目なのに、出たのは5行目です。 消した行はもう無いので指せません。 「ファイルの終わりに移りました」は、閉じるものを待つうちに最後まで来たという意味。

8. java のあとのエラー:動き出す前に止まる

図9 エラーが見つかるのは、javac が読むあいだか、java が動かすあいだです

図9:エラーが見つかるのは、javac が読むあいだか、java が動かすあいだです。

お手本のままで翻訳は成功させ、java のうしろの名前を小文字の hello にします。

> javac Hello.java
> java hello
エラー: メイン・クラスhelloを検出およびロードできませんでした
原因: java.lang.NoClassDefFoundError: hello (wrong name: Hello)

形が変わりました。 ファイル名も行番号もキャレットも出ていません。 中を読んで困ったのではなく、動かす相手が見つからなかったのです。 (wrong name: Hello) は「探したのは hello、あったのは Hello」の知らせ。 名前を大文字小文字のとおりに探すしくみでは出ません。

Hello も Java も出ていないので、これは1行も動いていません。 java のあとでも、動き出す前に止まることがあるわけです。

うしろに書くのはクラス名です。 java Hello.java は翻訳せずに動かす Java 11 以降のやり方で、この連載では使いません。

9. java のあとのエラー:動き出してから止まる

図10 動かしたときのエラーは、途中まで動いてから止まります

図10:動かしたときのエラーは、途中まで動いてから止まります。

最後は、翻訳は通るのに動かすと止まる例です。 お手本に戻して、4行目に 10 / 0 を入れます。 「10を0で割る」という意味です。 二重引用符ではさむと字がそのまま出るので付けません。 はさまない数はそのまま計算されます(第5回)。

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello");
        System.out.println(10 / 0);
        System.out.println("Java");
    }
}
> javac Hello.java
> java Hello
Hello
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Hello.main(Hello.java:4)

0で割る文は書き方としてはおかしくないので、javac は止めません。 おかしくなるのは割ろうとした瞬間で、翻訳が通ったことは正しく動く保証ではない。

Hello は出ていて、Java は出ていません。 3行目までは動き、5行目には届かなかった。 出ている行と出ていない行の境目が止まった場所です。

Exception in thread “main” は「main の途中で止まった」、/ by zero が「0で割った」。 下の行の at Hello.main(Hello.java:4) にファイル名と行番号が入ります。

10. 読む順番:上から1件目だけ

図11 上から1件目だけを見る。直したらもう一度翻訳します

図11:上から1件目だけを見る。直したらもう一度翻訳します。

1つ目は、どちらのコマンドのあとに出たかです。 これで種類が決まります。 2つ目は、画面を上まで戻して1件目を読むこと。 5章のように原因1か所で4件のこともあり、1件目を直すと下の件ごと消えるからです。

3つ目は、行番号の行を開くこと。 4つ目は、キャレットの左右を疑うこと。 指した場所の手前に足りないものが多いからです。 5つ目は、1か所だけ直して、もう一度 javac を打つこと。 まとめて直すと、どちらが効いたか分かりません。

確認問題

問1 次のうち、javac の段階で止まるものはどれか。
ア 3行目の行末のセミコロンを消す
イ 4行目に System.out.println(10 / 0); と書く
ウ java のうしろに hello と打つ
エ イとウの両方

答え:ア
セミコロン忘れは書き方の間違いなので翻訳で止まります。 イは翻訳は通り、動かすと止まります。 ウは java の話です。

問2 javac が出した「Hello.java:3:」の 3 は何を指すか。
ア エラーの件数
イ ファイルの上から3行目
ウ その行の左から3文字目
エ Javaの版

答え:イ
コロンのうしろの数は行番号です。 行の中の位置を指すのはキャレットです。

問3 1つの行の字下げを全角スペース4つで書いたら、エラーが4個出た。 直すところはいくつか。
ア 1か所
イ 4か所
ウ 8か所
エ 分からない

答え:ア
直すのはその行の字下げ1か所。 全角スペース1つにつき1個出るので件数は4個ですが、原因は1か所です。

まとめ

図12 どちらのコマンドのあとに出たかで、見るところが決まります

図12:どちらのコマンドのあとに出たかで、見るところが決まります。

エラーは失敗の記録ではなく、どこで何に困ったかの手紙です。

持って帰るのは3つ。 javac のあとか java のあとかで見るところが決まる。 行番号は探し始める場所。 件数と原因の数は別のもの。

書いて・動かして・止まったら読む、というひと回りができました。 次回は「変数と型:値に名前をつける」。 値に名前をつけて持ち歩きます。

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