Public static void main(String[] args) は死んだ
(mccue.dev)- Java の最初のプログラムは、もはや public static void main(String[] args) で始める必要はなく、簡略化された void main() 構文で書けるようになった
- 新しい構文では、IO.readln や IO.println のようなシンプルな呼び出しだけで入出力を処理でき、コードははるかに直感的になった
- 従来の new Scanner(System.in)、System.out.println のような冗長な構文は不要になった
- これまでの不便さが 「ついに終わった」。Java の基本構造が軽くなり、入門のハードルが下がって学びやすさ が大きく向上しそうだ
- 従来、Java ではプログラム開始のために
public static void main(String[] args)という長い宣言が必要だった - しかし 2025 年 9 月 16 日時点で、Java の最初のサンプルとして知られていた
main関数の複雑な宣言は、新しいシンプルな形に置き換えられた - 従来の方式:
public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("What is your name? "); String name = scanner.nextLine(); System.out.println("Hello, " + name); } } - 新しい方式:
void main() { var name = IO.readln("What is your name? "); IO.println("Hello, " + name); } - 初心者にとっては不必要に冗長で、「呪文のように」暗記しなければならない構文だという批判を受けてきた
- 従来の宣言の煩雑さ と わかりにくさ を解消し、簡潔な構文の導入によってコードの可読性が高まり、Java 入門のハードルは大きく下がった
- もはや Scanner, System.out.println など複雑なオブジェクト生成や呼び出しを基本例として使わない
Good Fucking Riddance = 「ようやく消えてせいせいした。さようなら」
5件のコメント
別の方法が新たに1つ増えたからといって、既存の方法が死んだと言っているように聞こえます。
本当に既存の方法は使えなくなり、新しい方法を使わなければならないのでしょうか?
Wow
Javaをもう一度学び直さないといけないのかな..
main は死んだ。main 万歳!
Hacker Newsの意見
時間が経つにつれて、こういう見慣れないコードがだんだん理解できるようになっていく過程が懐かしく思える気がする。最初にPythonを学んでからJavaに移ったとき、
voidやString[]のような型が何を意味するのかわからず不思議だった。型を学んでから理解できるようになり、その次にclassとobjectの概念、そしてmainがなぜstaticメソッドとして存在するのかもわかるようになった。さらに深く入っていくと、このクラスがいつ呼ばれるのかも学び、最初は単なるボイラープレートに見えたコードがだんだん筋の通ったものに思えてきた。たぶん経験豊富なJava開発者なら、私よりもこの1行からもっと多くの意味を読み取れるのだと思う。それでも、もうなくなってすっきりした本当にすっきりした。この30年間、ソフトウェア教育は「工学」という名目で、開発者に無駄な複雑さを生み出すことを教えてきた。たとえばA開発者は、エントリーポイントやコールバック、インターフェースなど必要に応じて何でもclassを作る。その結果、私たちはclassを手に入れる。B開発者はclassにインスタンス変数を追加して全体を変更可能にし、その結果「実装の泥沼」が生まれる。その後、別の開発者がコード再利用のために継承を追加するが、これによってさらに複雑さと動的ディスパッチの悪夢が増える。最終的には参照循環(reference cycle)が生じてオブジェクト同士のつながりがこんがらがる。時間が経つほどリファクタリングはますます難しく面倒になり、結局コードを消して最初からやり直すことになる
大学で初めてプログラミングを学んだとき、このコードを見て教授が「普段ならコードの説明は全部するけれど、この部分はとりあえず受け入れてくれ」と言っていたのを思い出す。後になって、自分がそのコードを全部理解していると気づいたときはかなり格好いい経験だった。それでも、もう時代が変わるようで胸がすく
実際のところ、staticなクラスメソッドは、プログラムの単一のエントリーポイントが必ずclassと結び付いていなければならないという現実否認に近い。C++だけでなく、PythonやRubyのように手続き型の現実を認めた言語もあるのに、Javaはまるでユーザーの目を隠して「完璧なOOP世界」に押し込もうとしているようだ
古いclassベースのやり方を知っている立場からすると、新しいスタイル(Java 21のunnamed classesなど)のほうがむしろ疑問を生む気がする。本当に「すべてがオブジェクト」のJavaを手続き型言語に変えたのだろうか。もしコマンドライン引数が必要なときはどうするのか気になる。私は主にJavaを避けてきたので詳しくはないが、これは純粋に気になっている質問だ
Java 1.2時代には、標準入力を次のように読んでいた。Scanner classは新しいので見慣れない
私も似たような経験がある。かなり昔にJavaを使っていたので
public static void mainパターンには慣れていたが、Scannerの使い方がぎこちなくて、理由を正確には理解していなかった私の経験では、大規模プロジェクトで何十年も仕事をしてきたので、main関数がどう書かれているかは日常やキャリアにまったく影響しない。みなさんはこうした変化が実際どれくらい影響すると思うのか気になる
Android開発者ならmainという概念自体がなかった。正直、取るに足らないHello Worldの実装が不格好だからといって、その言語がそれ以上のことをうまく扱えるかどうかの尺度になるとは思わない
多くの人がJavaでプログラミングを始める際にmainを何十回もタイプしたが、それが何を意味するのかはまったくわかっていなかった
実務の開発者には大きな影響はないが、初心者には重要な問題だ。以前Javaを教えていたが、「Hello, World」を表示する前に覚えなければならない魔法の呪文(ボイラープレート)が、学生にとって参入障壁になっていた
コマンドラインインターフェースを作るなら影響はあるかもしれないが、JavaでCLIを作ることはそれほど多くない
私はここ5年ほどcodebaseでmainを見たことがない。そして新しいclassを自分で作るというより、たいていはフレームワーク固有のclassを実装したり拡張したりしている
JEP 445: Unnamed Classes and Instance Main MethodsがJava 21でリリースされた
https://openjdk.org/jeps/445
30年を経て、Javaがついにかなりまともな言語へ進化しているのは驚きだ
私はフレームワークなしで純粋にJavaとC++でたくさんのコードを書いていたが、その頃はボイラープレートがずっと少なくて単純だった。本当に便利さを実感したのは、10年ほど前にlambdaが追加されたときだ。lambda導入後はコード量が減り、非常に快適になったと感じた。Javaは長い間、ひどく明示的で、些細なことにもタイプミスのチェックしかしていないような不要な繰り返しが多かった。Kotlinが登場するまではそんな雰囲気だったが、その後lambdaや匿名classなどによって開発体験は大きく改善した
Javaがひどい言語だったという主張は大げさすぎる
一方でPythonのような言語は、30年経ってもまだ不便だと思う
おそらく本当にひどい言語を経験したことがないか、「ひどくない」の基準がものすごく高いのだろうと思う
それでもJavaには優れた後方互換性とパッケージ管理システムがある点はすごい
前のコメントでも触れた話だが、Java開発者としてはpythonのほうがむしろ変わっていると感じるが、今のやり方が悪いとは思わない。ただ、抽象化の基本を理解しないままいきなりプログラミングを始めるなら、「プログラミング入門」としては良い選択ではないかもしれない。道具が目的志向、パラダイム志向などで設計されると、ときに極端な抽象化が起こりうる。JavaはOOPに焦点を当てて設計されているため、interfaceのようなブロック単位の思考が自然だ。メソッド/classのアクセス修飾子も、それが誰のためのものかに応じて明確に区別されている(public, protected, default, private など)。つまり、Javaへの入門は、ユーザー(プログラマ)に向けたinterfaceの露出から始まる。奇妙に見えるかもしれないが、少なくとも一貫性はある
重い文法はOOPと直接の関係はない。Javaが登場する前のOOPのどの定義にも、「関数はclassの外に存在できない」とは書かれていなかった。Sunは長い間スタンドアロン関数の概念を拒否してきた(静的importはJava 5、クロージャはJava 8、compact source file/instance mainはようやく今になって導入された)。その結果、すべての関数はいまでもclassの内側にある(実用性と互換性のためであって、哲学的理由ではない)。「すべてがオブジェクト」にこだわろうとしたが、実際にはprimitive値を導入するという矛盾もあった。関数が必ずclassの中にあることによる実用上の利点はない。むしろ整数のような値にメソッドを定義できたほうがよかっただろう。ちなみにSmalltalkのような「純粋OOP」言語では、classの外に関数を自由に定義でき、REPLでも直接コードを実行できる
関連リンク
Hello Worldが重要なのは、プログラム実行のためのボイラープレートと実際の出力コードを同時に見せられるからだ。また、ビルドツール設定という観点では、一部は「ボイラープレート」というより実習やツール設定のための手順でもある。これをすぐ説明してしまえば大きな問題ではない
もしコンパイラのトリックで内部的にclassを生成しているだけなら、単なる見せかけの変化にすぎない。ほかのtop-level関数が許されないなら、結局は特異ケースでしかなく、やはり不自然だ
C#は9.0からtop level statementをサポートしているが、結局内部的には静的メソッドに変換される。複数のtop level関数も似たように動く。実例: C# decompiled example
こうしたトリックは実際に有用なコンパイラ変換の例でもある(closure、async state machineなど)。今回の変更もそういうものだ
C/C++でmain()にだけ暗黙の
return 0が適用されるのも、似たように不自然に感じるもしmainだけがtop-level関数として許可され、それ以外は不可能なら、これもあまり良い変更ではないと思う
Javaのコード例でimport行をなぜ省略するのか理解できない。ボイラープレートの複雑さを示したいなら、importも必ず書くべきだと思う
普通はIDEがimportを自動管理してくれるので気にしない。IO関連のclassならcompactな例では別途importが不要なので、実際にコードはそのままで動く
ほとんどのJava IDEはimportを自動で管理してくれる
public static void main(String[] args)というエントリーポイントをC#のようなtop-level statementパラダイムで抽象化すれば、ボイラープレートを減らしてコードを簡潔にできそうなのに、なぜそうしなかったのか気になるPaving the on-ramp の文書を参照するとよい
エントリーポイントが特別な例外ケースとして存在するなら、それはすでにOOPの限界を認めていることになる。そうであれば、思い切って新しい代替案を設計したほうがよいのではないかと思う
unnamed class方式を活用すると、グローバル変数の実装が容易になり、ホットリロードも可能で、しかも文法が簡潔になる点は良いと思う。一方で、Javaファイルはpublic classと同じ名前でなければならないという制約があるので、むしろ
public class X { }の部分をオプションにして必要なときだけ書けばよかったのではとも思う。なぜ匿名classを導入しなければならなかったのか、いまひとつ理解できないコンパイラは依然として HelloWorld.class のようなclassに変換するので、その名前は実装詳細にすぎず、実際にはソースコード上で直接使うことはできない
https://openjdk.org/jeps/445