mike-neckのブログ

Java or Groovy or Swift or Golang

Java 23 で文字列を表示するために println だけでよくなったか確認してみた

表題の通り Java 23 がリリースされたそうなので println だけで文字列を表示できるようになったかを確認してみた。


三行で

  • 暗黙に定義されたクラス(無名クラスではない)では、 System.out を使わずとも println だけで標準出力に文字を出力できる。
  • 暗黙に定義されたクラスでは、 java.base モジュールが自動でモジュールインポートされるので、 List などのコレクションクラスを使うのに import java.util.List を書かなくても良い。
  • 暗黙に定義されたクラスを java コマンドから直接実行できないので、 javac によるコンパイルが必要である。


println だけで文字列を表示できるようになったのと関係のある JEP は JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)

というわけで、次のようなクラスを作って実行します。なお、 Preview 機能なので、 --enable-preview の指定が必要です。

void main() {
  println("Java23");
}

この println メソッドは java.io.IO クラスの println メソッドで、 implicitly declared class (暗黙に定義されたクラス)(つまりクラス class Foo {} ブロックがないクラス/JEP445,[JEP463https://openjdk.org/jeps/463]) の場合に自動でインポートされるメソッドであるとのこと。

すると、 class ブロックで囲まれた場合には使えないのか気になってくる。そこで次のようなクラスを作ってコンパイル・実行してみる。

class ExplicitClass {
  void main() {
    println("explicit");
  }
}

println メソッドが見つからず、コンパイルエラーになる。したがって、 class を作って main メソッドを定義するタイプの Java ファイルでは println は使えないようだ。

また、同様に package が宣言されている場合は implicitly declared class になれないので、 class などのクラス宣言、あるいは interface などのインターフェース宣言が必要となるため、 println は使えない。

package pkg;
void main() {
  println("foo");
}


JEP477 の隣の JEP である JEP476 Module Import Declarations (Preview) との関連で、 implicitly declared class の場合には、デフォルトで java.base モジュールがインポートされているとのこと。そこで次のプログラムを書いて実行してみる。

void main() {
  var now = OffsetDateTime.now(ZoneId.of("Asia/Tokyo"));
  println(now.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
}

コンパイル、実行共に成功している。


余談

ここまで、 javac してから実行しているが、javac をすっ飛ばして java でも実行できるはずなので、やってみると…

--release オプションの扱いにてエラーが発生する。

したがって、 version 23 においては、 java コマンドでの implicitly declared class は利用できない。

2つの配列をマージしてオブジェクトの配列を作る(How to merge/zip two arrays into an array in jq)

一瞬わからなくて、グーグルなどで検索したけどよくわからなかったものの、ドキュメントを読み直したら解けた。

これは、パイプラインを理解してないと思いつかないと思う。


次のようなオブジェクトがあり、 namesscores は同じ長さの配列かつ names は重複のない配列として、それらをマージして (name, score) を組みにしたオブジェクトを作るのが目標とする。

item:
  names:
  - foo
  - bar
  - baz
  scores:
  - 10
  - 20
  - 30

namesscores に名前を付けて参照可能にしておいて、 names をメインのイテレーターとしてインデックスを自身から取得して、そのインデックスで scores から score を取得する

.item.names as $names |
.item.scores as $scores |
[
  .item.names[] |
  . as $name |
  {
    name: .,
    score: $scores[
      $names | index($name)
    ]
  }
]