Java | 基礎文法:コマンドライン引数

Java Java
スポンサーリンク

コマンドライン引数の全体像

Java のプログラムは main(String[] args) から始まり、args に「起動時に渡された文字列」が順番どおり入ります。引数はすべて文字列で渡されるので、必要に応じて数値やフラグへ変換します。役割は「入力の受け渡し」。プログラムは引数の検証→処理の振り分け→結果表示→終了コードで成否を返す、という流れで設計すると運用しやすくなります。


基本の使い方と定義

main と引数の受け取り

public class App {
    public static void main(String[] args) {
        // 例: 引数をそのまま表示
        System.out.println(java.util.Arrays.toString(args));
    }
}
Java
  • 引数がないときは args.length == 0。必須引数があるなら明示的にチェックして使い方を出します。
public static void main(String[] args) {
    if (args.length < 1) {
        System.err.println("usage: App <name>");
        System.exit(1); // 失敗の終了コード
    }
    System.out.println("Hello, " + args[0]);
    System.exit(0);
}
Java

文字列から型へ変換

引数は文字列なので、数値や真偽値へパースします。失敗時の例外を捕まえて、ユーザー向けのエラーメッセージへ変換します。

try {
    int n = Integer.parseInt(args[1]);  // "42" → 42
    boolean pretty = Boolean.parseBoolean(args[2]); // "true"/"false"
} catch (NumberFormatException e) {
    System.err.println("invalid number: " + args[1]);
    System.exit(2);
}
Java

スペース・引用符・OS差のポイント(重要部分の深掘り)

シェルが分解してから JVM に渡す

コマンドラインは「シェルが空白で分解→引用符で一塊に→JVMへ渡す」という流れです。つまり、空白を含む値は引用符で囲みます。

# 例(UNIX系)
java App "Koto City, Tokyo" 100
# args[0] = "Koto City, Tokyo", args[1] = "100"
Java

Windows の CMD/PowerShell でも基本は同じですが、エスケープの書き方に差があります。ファイルパスや空白を含む文字列は、常に引用符で守る習慣にすると安全です。

改行や特殊文字

改行、タブ、クォートを含む複雑な値は、設定ファイルから読み込む設計に切り替えると実務では安定します。長大な JSON を引数で渡すのは避け、パスだけ渡してファイルを読むのが定石です。


位置引数とオプション引数の設計

位置引数(positional)をシンプルに

「入力ファイル」「出力先」など、順番で意味が決まる引数は位置引数で受けます。チェックを早期に行い、足りなければ使い方を表示します。

public static void main(String[] args) {
    if (args.length < 2) { usage(); System.exit(1); }
    String inPath = args[0];
    String outPath = args[1];
    // 以降、処理
}
static void usage() {
    System.err.println("usage: App <input> <output>");
}
Java

オプション(-f, –flag)で柔軟性を追加

オプションは「順不同で指定可」「デフォルトあり」にできるため、運用に便利です。小規模なら自前で簡単にパースできます。

record Opts(String format, boolean pretty, java.nio.file.Path input) {}

static Opts parse(String[] args) {
    String format = "txt";
    boolean pretty = false;
    java.nio.file.Path input = null;

    for (int i = 0; i < args.length; i++) {
        switch (args[i]) {
            case "--format":
                format = args[++i]; // 次のトークン
                break;
            case "--pretty":
                pretty = true;
                break;
            default:
                input = java.nio.file.Path.of(args[i]); // 位置引数扱い
        }
    }
    if (input == null) throw new IllegalArgumentException("missing input");
    return new Opts(format, pretty, input);
}
Java

本格的にやるなら JCommander、picocli などのライブラリを使うと、検証・ヘルプ生成まで一式整います。


ヘルプ・エラー・終了コードの扱い

使い方(usage)を明確に

誤った引数に対しては、短いヘルプを System.err に出し、失敗の終了コードを返します。成功は 0、入力エラーは 1〜2、実行中の失敗は 3 など、プロジェクトでルールを決めて統一します。

static int usage() {
    System.err.println("usage: App [--format <fmt>] [--pretty] <input>");
    return 1;
}
public static void main(String[] args) {
    int exit = 0;
    try {
        var opts = parse(args);
        run(opts);
    } catch (IllegalArgumentException e) {
        exit = usage();
    } catch (Exception e) {
        System.err.println("fatal: " + e.getMessage());
        exit = 3;
    } finally {
        System.exit(exit);
    }
}
Java

標準出力と標準エラーを使い分ける

  • 成功した処理の結果は System.out
  • 使い方・警告・失敗は System.err。 ログやシェル連携が劇的に楽になります。

よくある落とし穴と回避

Null や不足の見逃し

args[1] を無条件に読むと ArrayIndexOutOfBoundsException。必須数を最初にチェックしてから分岐するのが鉄則。

型変換の例外

Integer.parseInt は不正入力で NumberFormatException。try-catch でユーザー向けメッセージを返し、終了コードを分けておくと運用しやすい。

空白・パスの扱い

空白を含むパスは引用符で渡す。プラットフォーム差を避けるため、Java 側は Path を使い、文字列連結で OS 依存のセパレーターを作らない。

var p = java.nio.file.Path.of(args[0]);

役割の押し込みすぎ

main に引数パース・実処理・I/O を全部書くと巨大化します。パースは Cli クラス、処理は Service へ——「配電盤」スタイルに分割してテスト可能にします。


例題で身につける

例 1: 位置引数で合計を計算

public class SumApp {
    public static void main(String[] args) {
        if (args.length == 0) { System.err.println("usage: SumApp <ints...>"); System.exit(1); }
        try {
            int sum = java.util.Arrays.stream(args).mapToInt(Integer::parseInt).sum();
            System.out.println(sum);
            System.exit(0);
        } catch (NumberFormatException e) {
            System.err.println("invalid number: " + e.getMessage());
            System.exit(2);
        }
    }
}
Java

例 2: オプション+位置引数でフォーマット出力

public class PrintApp {
    record Opts(boolean upper, String sep, String text) {}
    static Opts parse(String[] args) {
        boolean upper = false; String sep = " "; String text = null;
        for (int i = 0; i < args.length; i++) {
            switch (args[i]) {
                case "--upper": upper = true; break;
                case "--sep": sep = args[++i]; break;
                default: text = args[i];
            }
        }
        if (text == null) throw new IllegalArgumentException("missing text");
        return new Opts(upper, sep, text);
    }
    public static void main(String[] args) {
        try {
            var o = parse(args);
            String out = o.upper ? o.text.toUpperCase() : o.text;
            System.out.println(String.join(o.sep, out.split("\\s+")));
            System.exit(0);
        } catch (IllegalArgumentException e) {
            System.err.println("usage: PrintApp [--upper] [--sep <s>] <text>");
            System.exit(1);
        }
    }
}
Java

例 3: 引数をファイルパスとして処理

import java.nio.file.*;
import java.io.*;

public class ReadApp {
    public static void main(String[] args) throws IOException {
        if (args.length < 1) { System.err.println("usage: ReadApp <path>"); System.exit(1); }
        var path = Path.of(args[0]);              // 空白を含むなら引用符で渡す
        try (var br = Files.newBufferedReader(path)) {
            System.out.println(br.readLine());
        }
        System.exit(0);
    }
}
Java

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

コマンドライン引数は「すべて文字列」で渡される。必須数を最初にチェックし、型へ変換する際は例外をユーザー向けメッセージと終了コードに変換する。空白やパスは引用符で守り、結果は標準出力、使い方や失敗は標準エラーへ。位置引数はシンプルに、柔軟性が必要ならオプションを導入し、パースと実処理をクラス分割して main は薄く保つ——この型が身につけば、CLI のアプリを安全に設計・運用できます。

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