実行と起動の罠
実行と起動の罠
このレッスンでできるようになること。java コマンドで起動できる main メソッドの形を見分けられるようになり、コマンドライン引数の番号を間違えずに読めるようになります。
まず予測してください
次の4つのクラスを java Main で起動したとき、正常に動くのはどれでしょうか。答えを決めてから先に進んでください。
// A
public class Main {
public static void main(String[] args) { }
}
// B
public class Main {
static public void main(String[] args) { }
}
// C
public class Main {
public static void main(String... args) { }
}
// D
public class Main {
public void main(String[] args) { }
}答えと理由
起動できるのは A と B と C です。D だけが起動できません。
- 修飾子の順番は自由です。
static publicでもpublic staticでも同じです。ここを「順番が違うからエラー」と読ませるのが定番の引っ掛けです - 可変長引数でも起動できます。
String... argsは内部的にString[] argsと同じ扱いなので、起動用の main として認められます staticが無いと起動できません。 D はコンパイル自体は通ります。通るのに実行時に落ちる、というのが厄介なところで、Main method is not staticのようなエラーになります
つまり「コンパイルエラー」と「実行時エラー」を分けて考える必要があります。試験ではこの2つを混ぜた選択肢が必ず並びます。
引数の名前と型
引数名は args でなくてもかまいません。public static void main(String[] a) でも起動します。逆に、型が違うものは起動用として認められません。main(int[] args) や main(String args) はコンパイルは通りますが、起動用の main としては使われません。
戻り値は void である必要があります。public static int main(String[] args) はコンパイルできますが、起動には使えません。
コマンドライン引数の数え方
java Main hello world と打ったとき、配列 args の中身は次のようになります。
args.lengthは 2args[0]はhelloargs[1]はworld
クラス名 Main は配列に入りません。 ここが C 言語の argv と決定的に違うところで、args[0] をクラス名だと思い込むと1つずつずれます。引数を渡さずに起動したときは args.length が 0 になります。null にはなりません。空の配列が渡ってくるので、args.length を見るコードは安全に動きます。ここで「args が null だから NullPointerException」と読ませる選択肢もよく出ます。
存在しない添字を読むと ArrayIndexOutOfBoundsException になります。引数を1つしか渡していないのに args[1] を読むコード、というのが試験で最も多い形です。
まとめ
順番は自由、static は必須、可変長引数も可、引数の先頭はクラス名ではなく最初の引数です。この4点だけ覚えれば、この分野の出題はほぼ落とせません。
要件
- 受け取った2つの文字列から、要素数2の String 配列 args を作ること
- args.length と args[0] を半角スペース1つでつないだ文字列を返すこと
- クラス名は Main、メソッド名は firstArg のままにすること
入出力例
firstArg("hello", "world") → "2 hello"
firstArg("java", "silver") → "2 java"
firstArg("main", "exam") → "2 main"