コンパイルしてから実行する
JDKをインストールしたので、Javaの実行は2段階のサイクルになります。インタープリタをファイルに向けるだけで動くスクリプト言語とは違い、Javaはまず人間が読めるソースをバイトコードにコンパイルし、その後で別のステップがそのバイトコードをJVM上で実行します。
この2つのステップは、JDKに付属する2つのコマンドラインツールに対応しています。
javac- コンパイラ。Main.javaを読み込み、Main.class(バイトコード)を書き出します。java- ランチャー。JVMを起動し、Main.class内のバイトコードを実行します。
自己完結した例なら、このページ上で直接実行できます。下のエディタが両方のステップをあなたの代わりに行います。とはいえ、自分のマシンで何が起きるのかを理解しておく価値はあります。実際のプロジェクトはそこに存在するからです。
自分のマシンでの2つのコマンド
このコードを Main.java として保存したとしましょう。
public class Main {
public static void main(String[] args) {
System.out.println("Hello from the terminal");
}
}
そのファイルがあるフォルダでターミナルを開き、コンパイラを実行します。
javac Main.java
コードがエラーなくコンパイルされると、javac は何も出力せず、ソースの隣に Main.class という新しいファイルを作成します。その .class ファイルがバイトコードです。読める文字列ではなく、あなたのOSにも縛られていません。
では、java コマンドでそれを起動します。
java Main
Hello from the terminal
初心者が最もよくする間違いはここにあります。プログラムを起動するには javac ではなく java を実行し、拡張子なしのクラス名を渡します。正しくは java Main であり、決して java Main.class でも java Main.java でもありません。
ファイル名はpublicクラスと一致しなければならない
Javaは初心者を驚かせるルールを課しています。public クラスは、まったく同じ名前に .java を付けたファイルに置かなければなりません。public class Main は Main.java の中になければなりません。大文字小文字を間違えると、javac はコンパイルを拒否します。
// This is in a file called Greeting.java
public class Greeting { // ERROR: class Greeting should be in Greeting.java... wait, it is
public static void main(String[] args) {
System.out.println("Hi");
}
}
実際に人を悩ませる不一致はもっと微妙です。クラスが Greeting なのにファイルを greeting.java(小文字)と名付けたり、Main.java を保存したのに public class Hello と書いたりすることです。コンパイラは次のようなメッセージを報告します。
Main.java:1: error: class Hello is public, should be declared in a file named Hello.java
修正方法はいつも同じです。ファイル名とpublicクラス名を、1文字ずつ完全に同じにすることです。
近道: 単一ファイルを直接実行する
JDK 11以降、単一のソースファイルなら明示的なコンパイルステップを省略できます。java コマンドがメモリ内でコンパイルし、一度に実行します。.class ファイルはディスクに書き出されません。
java Main.java
これは手早い実験や小さなスクリプトに最適です。渡すものの違いに注目してください。
java Main- すでにコンパイル済みのMain.classを実行します。java Main.java- ソースファイルを一度にコンパイルして実行します。
単一ファイルモードは、プログラム全体が1つのファイルに収まる場合にのみ機能します。コードを複数のファイルの複数のクラスに分割した瞬間、また javac で先にコンパイルすることに戻ります。基礎を学ぶ間は、単一ファイルモードがサイクルを短く保ってくれます。
プログラムへの引数の渡し方
main の中の String[] args を覚えていますか? これらはコマンドライン引数です。java コマンドでクラス名の後ろに入力したものはすべて、その配列に入ります。
自分のマシンでは、次のように引数を与えます。
java Main hello world
First argument: hello
Total arguments: 2
上のエディタはターミナル引数を受け取れないため、「引数なし」の分岐を実行します。ただし同じコードが両方のケースを処理します。これが、ファイルやユーザー入力に到達するずっと前に、Javaプログラムが起動時に渡された入力を読み取る方法です。
コンパイラのエラーメッセージを読む
javac がコードを拒否すると、ファイル、行、そして何が間違っていたかを教えてくれます。これらのメッセージを読めるようになることは、行き詰まりから抜け出す半分の道のりです。古典的な例として、セミコロンの抜けを挙げます。
public class Main {
public static void main(String[] args) {
System.out.println("Oops") // no semicolon
}
}
Main.java:3: error: ';' expected
System.out.println("Oops")
^
1 error
キャレット(^)は、コンパイラが何かを期待していた場所を指します。Main.java:3 はファイルと行番号です。当てずっぽうの誘惑に抗ってください。その行を読み、名指しされたただ1つを直し、再コンパイルします。コンパイルエラーはまだ何も動いていないことを意味し、実行時エラー(見た目が異なります)はプログラムが起動してから失敗したことを意味します。
動作確認用プログラム
これをエディタで実行するか、Main.java として保存して自分のマシンで javac Main.java のあと java Main を実行してください。3行すべてが見えれば、あなたのツールチェーンは端から端まで動いています。
ここには、まもなくきちんと出会う3つのものが現れます。int 変数、+ による文字列の連結、そして .length を持つ配列です。今はプログラムがコンパイルされて出力されれば十分です。
次へ: Javaの構文
いくつかのプログラムを実行しましたが、句読点については手探りで済ませてきました。波かっこ、セミコロン、public static void main、そしてなぜ各行がそのような姿をしているのか。次のページでは、構造が定型文のように感じられるのをやめて意味を持ち始めるように、Javaの構文を一つひとつ分解していきます。
よくある質問
Javaプログラムはどうやって実行しますか?
コードをpublicクラスと同じ名前のファイル(例えば Main.java)に保存し、そのフォルダでターミナルを開き、2つのコマンドを実行します。バイトコードにコンパイルする javac Main.java、そしてそれを実行する java Main です。JDK 11以降では、単一ファイルなら最初のステップを省略して java Main.java を直接実行できます。
javacとjavaの違いは何ですか?
javac はコンパイラです。.java ソースを読み込み、バイトコードが詰まった .class ファイルを生成します。java はランチャーです。JVMを起動し、.class ファイル内のバイトコードを実行します。javac で一度コンパイルすれば、あとは java で好きなだけ実行できます。
なぜ「could not find or load main class」が出るのですか?
ほぼ必ず、java に間違った名前を渡したためです。ファイル名ではなくクラス名を使ってください。正しくは java Main であり、java Main.class でも java Main.java でもありません。また、Main.class を含むフォルダにいること、そしてクラス名が大文字小文字を含めてファイル名と完全に一致していることを確認してください。