Main メソッドの役割
Java の「プログラムの入口」は main メソッドです。JVM は指定されたクラスを読み込み、最初に public static void main(String[] args) を探して、そこから実行を開始します。C や Python と違い、Java は必ずクラスの中に main を置く必要があり、main は「アプリのスタートボタン」と覚えると理解しやすいです。
正しいシグネチャと意味
基本形(覚えるべき一行)
public static void main(String[] args)
Javaこの一行には重要な意味が詰まっています。
- public: JVM からどこからでも呼べるように公開します。公開されていないと入口に到達できません。
- static: クラスのインスタンスを作らずに呼べます。起動直後はまだオブジェクトがないため、入口は static である必要があります。
- void: 戻り値は使いません。終了コードは
System.exit(コード)で明示します。 - String[] args: コマンドライン引数を受け取ります。未指定なら長さ 0 の配列が渡されます。
同等の書き方として public static void main(String... args)(可変長引数)も使えます。配列と機能は同じです。
最小の例と実行方法
Hello, World(最小構成)
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, main!");
}
}
Javaこのファイルを Hello.java として保存し、次で実行します。
- コンパイル:
javac Hello.java - 実行:
java Hello
よくある間違いは「java Hello.class と書く」ことですが、拡張子は付けずにクラス名だけを指定します。また、public class Hello とファイル名 Hello.java を一致させるのも必須です。
引数の扱い(コマンドラインから値を渡す)
単純な計算機(引数の読み取りと型変換)
public class Add {
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("使い方: java Add 3 5");
return;
}
try {
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
System.out.println(a + b);
} catch (NumberFormatException e) {
System.out.println("整数を指定してください");
}
}
}
Java重要点は次の通りです。args は文字列配列なので、数値にしたいときは Integer.parseInt などで変換します。引数不足(args.length)や形式不正(例外)を必ずチェックすると、落ちないプログラムになります。
複数の main とエントリポイントの選び方
どのクラスが入口か(選択の仕組み)
複数のクラスに main を置けますが、起動時に「どのクラス名を指定したか」で入口が決まります。
public class A {
public static void main(String[] args) {
System.out.println("A の main");
}
}
Javapublic class B {
public static void main(String[] args) {
System.out.println("B の main");
}
}
Java- 実行例:
java Aなら A が、java Bなら B が実行されます。 - JAR 配布: JAR にする場合はマニフェストに
Main-Class: Aのように入口を明示します。これでjava -jar app.jarだけで起動できます。
よくある落とし穴と対策(深掘り)
static コンテキストの制約
main は static なので、インスタンスメンバー(非 static)を直接触れません。触るには「インスタンスを作る」か「メンバーを static にする」必要があります。
public class App {
private int counter = 0; // 非 static
public static void main(String[] args) {
App app = new App(); // インスタンスを作る
System.out.println(app.counter);
}
}
Java設計のコツは「main は薄く、実処理は別クラス/メソッド」に分離すること。テストしやすく、保守性が上がります。
シグネチャの誤り
public static void main(String args[]) は OK(配列記法の違いだけ)。しかし次は NG です。
public void main(String[] args)(static がない)static void main(String[] args)(public がないと起動できない)public static int main(String[] args)(戻り値が void でない)public static void main(String[] a, String[] b)(引数の型・数が違う)
終了コードの使い分け
成功・失敗を OS やスクリプトに伝えたいときは System.exit(コード) を使います。慣例的に 0 が成功、0 以外が失敗です。
public class ExitDemo {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("引数が必要です");
System.exit(1); // 失敗を示す
}
System.out.println("OK");
System.exit(0); // 成功
}
}
Javamain の最後で自然終了する場合は 0 と同等です。異常系だけ System.exit を使うと読みやすくなります。
実用例題で総復習
例題 1: ファイルを読み行数を数える(例外と終了コード)
import java.nio.file.*;
import java.io.IOException;
import java.util.List;
public class CountLines {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("使い方: java CountLines <path>");
System.exit(1);
}
try {
List<String> lines = Files.readAllLines(Path.of(args[0]));
System.out.println("lines=" + lines.size());
} catch (IOException e) {
System.out.println("読み取り失敗: " + e.getMessage());
System.exit(2);
}
}
}
Javaポイントは、入力検証→処理→例外対応→適切な終了コードの流れを main に集約し、詳細ロジックは標準ライブラリや別メソッドに委ねることです。
例題 2: サブコマンド形式の入口(薄い main、厚いロジック)
public class CliApp {
public static void main(String[] args) {
if (args.length == 0) {
printHelp();
return;
}
String cmd = args[0];
switch (cmd) {
case "greet" -> greet(args);
case "sum" -> sum(args);
default -> printHelp();
}
}
static void greet(String[] args) {
String name = (args.length >= 2) ? args[1] : "Java";
System.out.println("Hello, " + name + "!");
}
static void sum(String[] args) {
if (args.length < 3) {
System.out.println("使い方: sum a b");
return;
}
int a = Integer.parseInt(args[1]);
int b = Integer.parseInt(args[2]);
System.out.println(a + b);
}
static void printHelp() {
System.out.println("使い方: greet <name> | sum <a> <b>");
}
}
Javamain はコマンドの振り分けだけに集中させ、個別処理は別メソッドへ。規模が大きくなっても整理が効き、テストもしやすくなります。
仕上げのアドバイス(設計視点の深掘り)
main は「起動配線」、ロジックは「別ユニット」
main を「起動・入力検証・エラー処理」に限定することで、アプリの心臓部は疎結合に保てます。単体テストは main 経由ではなくロジックのメソッド/クラスに対して行うのが定石です。
入口は一つでも、責務は分ける
大きなアプリでは、main から DI コンテナや設定読み込み、ログ初期化を呼び、実処理はサービス層へ渡します。責務を分けることで、main は「どこから来てどこへ行くか」を示す最小のガイドになります。
次の一歩
JShell を使えば、main なしで一行から動作確認ができますが、アプリとして配布するなら main の理解が不可欠です。
