要約
JDK 8のバージョン番号の読み方
インストーラの表記
- インストーラを入手する時は、「jdk8u312-b07」というような表記のうち、
u
の後ろの数字が一番大きなものが最新版 -b
の後ろの数字はjdk自体のビルド番号であり、jdk自体の開発者向け情報...利用者側は無視してよい
java -versionの出力
java -version
でインストール済みのバージョンを確認すると、1行目に「1.8.0_312」とインストーラと異なる表記方法で出力される- アンダースコア以降の数字がインストーラの
u
に続く数字と一致する 1.8.0
は固定で、今後JDK 8がアップデートされても変わることは無い(u
の後ろの数字だけがインクリメントされる)
JDK 10以降のバージョン番号の読み方
インストーラの表記
- インストーラを入手する時は、「jdk-17.0.1+12」というような表記のうち、
+
の前の数字を確認する +
の後ろの数字はjdk自体のビルド番号であり、jdk自体の開発者向け情報...利用者側は無視してよい17
はJDKのメジャーバージョン...JDK xxという表記と一致する- 続く二つ目のバージョンの数字は現状
0
のまま - 続く三つ目のバージョン番号の数字が一番大きなものが最新版
java -versionの出力
java -version
でインストール済みのバージョンを確認すると、1行目に「17.0.1」とインストーラのバージョン番号からビルド番号を除いたものが出力される
JDK 9
上記二つと異なる表記ルールだが、LTSバージョンではないため割愛
詳細
Javaのバージョン番号の形式は典型的なセマンティックバージョニングでもないし、長い歴史の中で何度も変わっているので分かりづらいところがあります。
例えば2021年11月14日時点で最新バージョンのTemurinのJDK 8のバージョンはダウンロードサイトには「jdk8u312-b07」と表記されています。
実際にインストールして「java -version
」でバージョン番号を確認すると以下のように返ってきます。
openjdk version "1.8.0_312" OpenJDK Runtime Environment (Temurin)(build 1.8.0_312-b07) OpenJDK 64-Bit Server VM (Temurin)(build 25.312-b07, mixed mode)
まず、バージョン番号らしきものが3種類出てきて、どれ一つダウンロードサイトの表記と合っていません。
openJDKベースのでJDKであるTemurinをインストールしたのでおそらくopenjdk version
がJDKのバージョン情報のように見えます。しかし、「1.8.0_312」というバージョンの、セマンティックバーョニングでいうメジャーバージョンを示す位置にある「1」や、パッチバージョンを示す位置にある「0」はどこから登場したのでしょうか。
また、同じくTemurinのJDK 17のバージョンは「jdk-17.0.1+12」とダウンロードサイトに表記されています。
同じようにインストールして「java -version
」でバージョン番号を確認すると以下のように返ってきます。
openjdk version "17.0.1" 2021-10-19 OpenJDK Runtime Environment Temurin-17.0.1+12 (build 17.0.1+12) OpenJDK 64-Bit Server VM Temurin-17.0.1+12 (build 17.0.1+12, mixed mode, sharing)
少し表記が一致しましたが、今度は最後の「+12」はどこかへ消えてしまいました。JREのバージョン番号には含まれているし、完全一致しています。
この違いは何でしょうか?
OracleのJavaのサイトに残っているリリース情報を見てみるとバージョン番号の形式が色々と変わってきたことがわかります。
https://www.java.com/releases/
その最後にバージョン番号の変遷の歴史が載っていました。
ここに書かれている「JEP 223」と「JEP 322」がポイントになるようです。それぞれ提案を見てみましょう(JEPは、JDK Enhancement Proposalsの略で、機能拡張の提案文書のこと)。
JEP 223: New Version-String Scheme
JDK 9リリースに向けてバージョン番号の形式を変更する提案が、「JEP 223: New Version-String Scheme」でした。これは採択されてJDK 9から実際に適用されました。
Motivation
の項にこう書かれています。
What's the difference between releases named "JDK 7 Update 60", "1.7.0_60", and "JDK 7u60"?
These are just different names for the same release. These differences make it difficult to identify and verify equivalent releases. A simple pointwise comparison of sequences of parsed tokens does not suffice; instead, a fairly sophisticated algorithm is needed. The use of the lower-case 'u' is not an industry standard and is not language-neutral.
冒頭のJDK 8のバージョン番号の件でいえば、「1.8.0_312」と「JDK 8 8u312」は同じものを指すそうです(その後ろに続く「b07」は後述します)。
また、話は前後しますが、u
の後ろに続く数字は以下のようなルールで採番されているそうです。
Minor releases containing changes beyond security fixes are multiples of 20. Security releases based on the previous minor release are odd numbers incremented by five, or by six if necessary in order to keep the update number odd.
機能追加の時には20の倍数を付与し、セキュリティ修正をする時は、5か、6を足していく...よく分からないですね。とにかくJDK 8に更新が発生すると「u」に続く数字がインクリメントされ、リリースされることが分かります。とにかくこの数字が一番大きなものを使っておけば大丈夫、という訳です。
ただ、これでは分かりにくい、ということで「JEP 223: New Version-String Scheme」では「$MAJOR.$MINOR.$SECURITY」という一般的なバージョン番号の形式に変更することが提案されました。
メジャーバージョンが上がれば$MAJOR
がインクリメントされ、バグ修正や実装の改善(GCの拡張など)が有れば$MINOR
がインクリメントされ、セキュリティ修正が反映されれば$SECURITY
がインクリメントされます。ただし、$MINOR
がインクリメントされても$SECURITY
はリセットされずそのままインクリメントされ続けます。これはセキュリティパッチと機能追加を独立してチェックできるようにするための仕組みだそうです。
また、この時点でメジャーバージョンとJDKの番号が同期されるようになり、JDK 9のメジャーバージョンである$MAJOR
は「1」ではなく、「9」になりました。ここは分かりやすくなった点です。ただ、逆にちょっと分かりづらくなった点として、$SECURITY
がゼロになる時は、ゼロと表記するのではなく省略となり、更に$MINOR
と$SECURITY
の両方がゼロの場合は両方とも省略されます。そのため、最初にリリースされた「JDK 9」のバージョンは「9」で、その後にリリースされたセキュリティアップデートは、「9.0.1」というバージョンになりました。ちょっと分かりづらいですね...
しかし、openJDKが半年に一度のメジャーリリースとなり、それに対応した更に新しいバージョン番号の形式であるTime-Based Release Versioning
がJEP 322として提案されたため、この形式でのリリースはJDK 9のみとなってしまいました。$MINOR
はインクリメントされないまま終わりました。
ちなみに、4番目以降の数値はopenJDKの派生リリースを行うベンダが自由に付与して良い、という扱いになっています(JDKのディストリビューションベンダが独自のパッチを当てたバージョンをリリースする際に利用する)。
JEP 322: Time-Based Release Versioning
openJDKが半年に一度のリリースサイクルに変更されることに合わせて「JEP 322: Time-Based Release Versioning」という更に新しいバージョン番号の形式が提案され、JDK 10から実際に適用されました。
今度は、「$FEATURE.$INTERIM.$UPDATE.$PATCH」という形式に変わっています。
$FEATURE
は$MAJOR
と同じ...JDK 17であれば「17」...ただし、JDKが6ヶ月ごとのリリースモデルに変わったため、何が含まれているかに関わらずインクリメントされます$INTERIM
は$MINOR
と同じ...バグ修正や、互換性を破壊しない拡張が含まれると定義されています...ただし、6ヶ月ごとのリリースモデルではゼロに固定化されます...将来のリリースモデル変更のための予約となっています$UPDATE
は、互換性を破壊しないセキュリティ修正、バグ修正、リグレッション修正が含まれる...従来の$SECURITY
と$INTERIM
が混ざったような定義になっています$PATCH
は、緊急リリースのために使われます
$FEATURE
は6ヶ月に一度インクリメントされますが、$UPDATE
も新しい$FEATURE
のリリース後1ヶ月時点、以降は3ヶ月に一度でインクリメントされてリリースが行われます。
また、ビルド番号を示す$BUILD
を「+」に続けて付加することができます。ビルド番号は開発中にインクリメントされる番号で、リリースされてしまえば気にする必要はありませんが、リポジトリのtagでは番号表記だったり「ga(general availability)」と表記されていたり、ちょっと分かりづらいですね。冒頭の、「17.0.1+12」であればJDK 17.0.1というところだけを注目しておけばOKです。
17.0.1はビルド番号12がGAリリースなので、17.0.1+12とが17.0.1+gaという表記は同じものを指しています...逆に17.0.1の後ろが11以下のバージョンのソースを開発目的以外で使うべきではない、ということが分かります。このビルド番号の考え方はJEP322が適用される前のJDK 8でも同様に運用されているようです(ただし、ビルドを示す「b」が付加されて「b07」という表記になっているので多少表記方法は異なる)。
あくまでビルド番号なので、バージョンコマンドでopenjdk自体のバージョン表記には含まれていないようです。
JEP 223の定義と変わらず、$PATCH
と$UPDATE
と$INTERIM
が全てゼロの場合は省略されるので、JDK 17の初期リリース時のバージョンは「17」となり、次のリリースのバージョンは「17.0.1」となりました(長期サポート版にはバージョン番号の後ろに、空白を一つ空けてLTS
を付ける...というルールも有るようですが、Oracleのリリース一覧では何故かそれぞれの初期リリースの時にしか付加していないようですね)。
バージョンコマンドで表示される3つのバージョン
冒頭で、バージョンコマンドは3つのバージョンを表示すると書きましたが、一つ目がJDKのバージョン、二つ目がJREとしてのバージョン、三つ目がJVMとしてのバージョンとなっていてビルド番号はJDK 8の頃よりJREとJVMにのみ表記する仕様が踏襲されているようです。
openjdk version "17.0.1" 2021-10-19 OpenJDK Runtime Environment Temurin-17.0.1+12 (build 17.0.1+12) OpenJDK 64-Bit Server VM Temurin-17.0.1+12 (build 17.0.1+12, mixed mode, sharing)
派生バージョンのバージョン番号
バイナリをリリースしているベンダが独自にパッチを充てた場合、上記のバージョン番号の後ろにディストリビューション独自のバージョン番号を付与して区別します。例えば、ubuntu 18.04のopenJDK 11のパッケージのアップデート情報は以下のように管理されていて、11.0.11+9-0ubuntu2~18.04
が、11.0.11+9をUbuntu 18.04へバックポートしたビルドであることが分かります。
おわりに
バージョン番号の後ろに+に続いて付けられている番号の意味が分からなかったので調べ始めたら、色々なことがわかったのでメモにしてみました。簡単に言うと、無視しておいて良かった、ですね。
次回こそディストリビューションの話をします。