Help us understand the problem. What is going on with this article?

「Java8からJava11」で何が起きたのか、どう環境構築すればいいのか

この記事の目的

  • 「Javaの環境構築」で絶対にハマったり、錯綜する情報にいつも惑わされる人に向けた記事です。
  • 2017年以降のJavaは、移り変わりが激しい世界になりました。このことを認識し、「軸となる考え方」や「重要な動向」を把握できるように、調べた情報をまとめました。
  • 「5年ぶりに(Java|JVM言語)触るんだけど環境周りが全然わからん」とか、「CorrettoとかAdoptOpenJDKとか、みんな何を言っているんだ」という人(つまりちょっと前の筆者)が、「今後に渡って2度とハマらないための基礎知識を得られること」を目的にしています。以下の3本立てです:
    • ざっくりとした歴史
    • 2020年におけるローカル開発環境構築
    • 情報源と参考URL
  • APIや言語仕様の変更点には触れません(他の良い記事があります)。

I. ざっくりとした歴史

  • 2017年9月、OracleはJavaのリリース・モデルの変更を発表し、同時に「Oracle JDKの有償機能をOpenJDKで公開」することを発表した。すなわちJavaはオープン化されることになった(有償化ではなく)。
  • 以前から有償契約でサポートを受けていたクライアントは、引き続き有償サポートを受けられる。この場合に限り、JDKは"Open"ではない「Oracle JDK」として提供され、プロダクション環境での利用が有償となる(ここが誤解されがち)。

リリースサイクルについて

  • 毎年3月と9月にフィーチャー・リリースが提供され、メジャーバージョンが上がっていく。Ex: Java9 => 2017年9月、Java10 => 2018年3月、Java11 => 2018年9月、...
  • 全フィーチャー・リリースがOracle JDKのLTS(Long Term Support)というわけではない。Java9以降では、Java11, Java17がLTS対象。それ以外はnon-LTS。

  • 詳しくは、Oracle Java SE サポート・ロードマップを参照。

image.png

「8とそれ以降」

  • Java8は「リリース・モデル変更前の最後のバージョン」という位置にいる。Java8自体もオープン化され、かつOracle JDKのLTS対象になっている。
  • Java8からJava9に上がる際、Project Jigsawと呼ばれるモジュール化が採用され、設計に比較的大きな変更が入った。
  • つまり、「Java8以前とJava9以降」ではリリース・モデルの面でも、互換性の面でも大きな隔たりがある。移行に際しては両面を(混同することなく)意識したほうが良い。

ディストリビューションの分化

  • オープンソース化したことで、複数ベンダーがJDKをビルド、発表できるようになった。OpenJDKのソースを取り巻き、Linuxのように各社のディストリビューションが複数存在する状況が生まれた。 image.png (出典: 最適なOpenJDKディストリビューションの選び方
  • 2020年現在、主要なディストリビューションは以下:

    • Oracle OpenJDK (by Oracle)
    • Red Hat OpenJDK (by Red Hat)
    • Azul Zulu (by Azul Systems)
    • SapMachine (by SAP)
    • Liberica JDK (by BellSoft)
    • Amazon Corretto (by Amazon)
    • AdoptOpenJDK (Community Based)
  • 各社のOpenJDKディストリビューションは、「latestだけ」「OracleのLTS対象だけ」などバージョンを絞って公開・サポートすることがある。

    • 例えば2020年1月現在、Oracle OpenJDKは最新の13をGA(General-Availability Release)として公開。他バージョンもダウンロードは可能だが、使用は非推奨。
    • 同じく2020年1月現在、Amazon Correttoは8と11を公開。
  • ディストリビューションにお墨付きを与えるため、Technology Compatibility Kit(TCK)という一連のテストがOpenJDKコミュニティ(Oracleと要契約)によって用意されている。TCKをパスしたディストリビューションは、“Java SE compatible”と名乗ることができる

  • AdoptOpenJDKのように、TCKをpassしていないが比較的普及しているディストリビューションもある

どう選べばいいの?

  • サポート状況や、各ディストリビューションを取り巻くエコシステムで判断するのが現実的。

    • 例えば、Zuluのような有償ライセンス / サポートがあるか?
    • 例えば、インストーラはきちんと準備されていて、使いやすいか?
    • 例えば、公式Dockerイメージは用意されているか?
  • とはいえ、現状目立った差は少なく、選びづらい面もある。これから特徴が出てくるかもしれない。

II. 2020年におけるローカル開発環境構築

Iに書いたような状況なので、定まったベストはなく、しかもすぐに陳腐化する傾向にある。

=> SDKMAN!が現状のベストプラクティス。(2020.1.10 追記)

ここでは、「コマンドラインのみでインストールが終わること」「複数バージョンを切り替え可能な状態にすること」を重視し、以下2パターンの構築手順を例示する:

  • パターン1: SDKMAN!(推奨)
  • パターン2: Homebrew & jEnv

パターン1: SDKMAN!によるインストール

https://sdkman.io/

SDKMAN!は、Groovyの複数バージョン管理ツールであるGVMを前身とする。JVM言語やそのビルドツールを中心に多種多様なツールの複数バージョンの管理を実現してくれる。

SDKMAN!自体のインストールは公式を参照。導入後、Javaのインストールは以下のコマンドで完結する:

sdk install java      

このときインストールされるディストリビューションは、2020年1月現在はAdoptOpenJDKの11。

その他のディストリビューションに関しても、list, install, defaultの3つのサブコマンドで自由に確認・切替えできる。バージョンやディストリビューションの指定はリスト中のIdentifierを使用する。

sdk list java

================================================================================
Available Java Versions
================================================================================
 Vendor        | Use | Version      | Dist    | Status     | Identifier
--------------------------------------------------------------------------------
 AdoptOpenJDK  |     | 13.0.1.j9    | adpt    |            | 13.0.1.j9-adpt      
               |     | 13.0.1.hs    | adpt    |            | 13.0.1.hs-adpt      
               |     | 12.0.2.j9    | adpt    |            | 12.0.2.j9-adpt      
               |     | 12.0.2.hs    | adpt    |            | 12.0.2.hs-adpt      
               |     | 11.0.5.j9    | adpt    |            | 11.0.5.j9-adpt      
               | >>> | 11.0.5.hs    | adpt    | installed  | 11.0.5.hs-adpt      
               |     | 8.0.232.j9   | adpt    |            | 8.0.232.j9-adpt     
               |     | 8.0.232.hs   | adpt    |            | 8.0.232.hs-adpt     
 Amazon        |     | 11.0.5       | amzn    |            | 11.0.5-amzn         
               |     | 8.0.232      | amzn    |            | 8.0.232-amzn        
               |     | 8.0.202      | amzn    |            | 8.0.202-amzn        
 Azul Zulu     |     | 13.0.1       | zulu    |            | 13.0.1-zulu         
               |     | 12.0.2       | zulu    |            | 12.0.2-zulu  

...(中略)...         

 SAP           |     | 12.0.2       | sapmchn |            | 12.0.2-sapmchn      
               |     | 11.0.4       | sapmchn |            | 11.0.4-sapmchn      
================================================================================

なお、2つ目以降のJDKインストール時に、そのディストリビューションをデフォルトにするかどうかプロンプトで尋ねられる。

sdk install java 13.0.1-open # Oracle OpenJDK 13

Downloading: java 13.0.1-open

...(中略)...

Installing: java 13.0.1-open
Done installing!

Do you want java 13.0.1-open to be set as default? (Y/n): Y

Setting java 13.0.1-open as default.

デフォルトに設定すれば、その時点でJavaのバージョンは切り替わる。パスの設定等は一切不要。試しにjshellの起動確認をしてみる。

jshell
|  JShellへようこそ -- バージョン13.0.1
|  概要については、次を入力してください: /help intro
jshell>

jshellはJava9から追加されたJavaのREPLである。他の言語でお馴染みかもしれないが、標準APIのちょっとした動作確認などに重宝する。/exitで終了できるので、バージョンを戻して再実行してみる。

sdk default java 11.0.5.hs-adpt

Default java version set to 11.0.5.hs-adpt
jshell
|  JShellへようこそ -- バージョン11.0.5
|  概要については、次を入力してください: /help intro
jshell>

バージョンが切り替ることを確認できた。

パターン2: Homebrew & jEnvによるインストール

パターン2: Homebrew & jEnvによるインストール

SDKMAN!に比べて煩雑で、お勧めできない。裏側でどのようにパスが通されているかなどの参考にはなるかも

HomebrewでのJDKインストール

https://brew.sh/index_ja

  • 比較的最近(恐らく2019年11月)、Formulaeにopenjdkが追加された。したがって、brew install openjdkでインストール可能。
  • この時インストールされるディストリビューションは、Oracle OpenJDK。
  • Java8やそれ以前をインストールする必要がある場合、または他のディストリビューションを利用したい場合は、現状Homebrew Caskを使うことになる(この記事では割愛する)。
  • サポートされているFormulaeはここで検索するのが早い => https://formulae.brew.sh/formula/

インストールに成功するとCaveats(警告)が出ていることに気づく。以下はCatalina+zshで試したときのメッセージ。

==> Pouring openjdk-13.0.1+9.catalina.bottle.tar.gz
==> Caveats
For the system Java wrappers to find this JDK, symlink it with
  sudo ln -sfn /usr/local/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk

openjdk is keg-only, which means it was not symlinked into /usr/local,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

If you need to have openjdk first in your PATH run:
  echo 'export PATH="/usr/local/opt/openjdk/bin:$PATH"' >> ~/.zshrc

さらっと書いてあるが、どのパラグラフも重要。環境によってはメッセージの細部や取るべき対応が違うこともある。

For the system Java wrappers to find this JDK, symlink it with...

"system Java wrappers"が何を指すか明確でないが、後述するjava_homeコマンドなどを動作させるために、シンボリックリンクの作成が必要。

openjdk is keg-only, which means it was not symlinked into /usr/local,...

/usr/local以下にsymlinkされていないということなので、つまりこの時点でターミナルでjavaと打ってもここでインストールしたOpenJDKが直ちに動作するわけではないと言っている。

If you need to have openjdk first in your PATH run:...

ここでインストールしたOpenJDKがパスとして最初に検索されるようにするためには、シェルの起動時にパスを追加する必要がある。

ただ、今回は複数バージョンのJDKを別ツールで管理する方針なので、Javaのパスを直接~/.zshrcに書くことは避ける。

以上を踏まえて、最初のメッセージが推奨する、シンボリックリンクの作成だけを実行する:

sudo ln -sfn /usr/local/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk

こうすれば、以下のコマンドが動作するようになってくれるはずだ:

java --version

openjdk 13.0.1 2019-10-15
OpenJDK Runtime Environment (build 13.0.1+9)
OpenJDK 64-Bit Server VM (build 13.0.1+9, mixed mode, sharing)
/usr/libexec/java_home

/Library/Java/JavaVirtualMachines/openjdk.jdk/Contents/Home

jEnvへの登録

http://www.jenv.be/

pyenvのように、複数バージョンのJDKの管理を楽にしてくれるツール。インストール手順は公式に譲る。brew installの実行後、パスを通す必要がある。

例えばpyEnvだとpyenv install 3.5.0などのコマンドでPythonをインストールできる。だがここまでの操作からもわかるように、jEnv自体にJDKをダウンロードしてくる機能はない。jenv addコマンドが引数として要求するのは、「ダウンロード済みのJDKのJAVA_HOMEへのフルパス」だ。このパスは先述のjava_homeコマンドで参照できる。

/usr/libexec/java_home

/Library/Java/JavaVirtualMachines/openjdk.jdk/Contents/Home

あとはこれを利用してJDKをjEnvに追加してやれば良い:

jenv add `/usr/libexec/java_home`

openjdk64-13.0.1 added
13.0.1 added
13.0 added

複数バージョンのインストール

上記の状態から、例えば、Oracle OpenJDKの11を追加でインストールする場合は以下のような手順になる:

# 1. JDKをインストールする
brew install openjdk@11

# 2. JavaVirtualMachines配下にsymlinkを作成する
# (brew install時にプロンプトに出てくるコマンドをコピペする)
sudo ln -sfn /usr/local/opt/openjdk@11/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-11.jdk

# 3. jEnvの管理対象に加える
jenv add `/usr/libexec/java_home -v 11`

jEnvが複数バージョンを管理できるようになったことの確認と、jshellの起動確認をしてみる。

jenv versions

* system
  11.0
  11.0.5
  13.0
  13.0.1
  openjdk64-11.0.5
  openjdk64-13.0.1

バージョンを13に設定する。

jenv global 13.0 

jenv versions

  system
  11.0
  11.0.5
* 13.0
  13.0.1
  openjdk64-11.0.5
  openjdk64-13.0.1
jshell
|  JShellへようこそ -- バージョン13.0.1
|  概要については、次を入力してください: /help intro
jshell>

続いてバージョンを切り替えて同じことをしてみる。

jenv global 11.0

jenv versions

  system
* 11.0
  11.0.5
  13.0
  13.0.1
  openjdk64-11.0.5
  openjdk64-13.0.1
jshell
|  JShellへようこそ -- バージョン11.0.5
|  概要については、次を入力してください: /help intro

バージョンが切り替ることを確認できた。

ここまでやっておけば、ある程度ディストリビューションやバージョンの追加にも対応できるローカル開発環境と言えるはず。

III. 情報源と参考URL

以上述べてきたような経緯があるので、選択したディストリビューションによって開発者が参照すべき情報は異なってくる。

横断的に現状を把握できるページが見つかれば望ましいが、現状は、まずOpenJDKの開発をリードするOracle公式のロードマップを参照するのが良いだろう。

Oracle Java SE サポート・ロードマップ
https://www.oracle.com/technetwork/jp/java/eol-135779-ja.html

Red Hatなど、ベンダーが自社ディストリビューションのライフサイクルやポリシーを公開している場合もある。

OpenJDK Life Cycle and Support Policy
https://access.redhat.com/articles/1299013

その他 参考URL

(本記事はほとんど以下の記事からの抜粋と要約なので、より深く知りたい方はぜひ!)

JDKの新しいリリース・モデルおよび提供ライセンスについて
https://www.oracle.com/technetwork/jp/articles/java/ja-topics/jdk-release-model-4487660-ja.html

Project Jigsaw
https://openjdk.java.net/projects/jigsaw/

これからのJDK 何を選ぶ?どう選ぶ? (v1.2)
https://www.slideshare.net/TakahiroYamada3/how-to-choose-jdk-20191101
(2020-03-09追加。 @yamadamn さん、ありがとうございます)

最適なOpenJDKディストリビューションの選び方
https://www.oracle.co.jp/campaign/code/2019/pdfs/oct2019_b-3-3.pdf

「Java 有償化」で誤解する人になるべく分かりやすく説明するためのまとめ
https://togetter.com/li/1343743

OpenJDK - Wikipedia
https://ja.wikipedia.org/wiki/OpenJDK

Oracle JDK vs. OpenJDK builds comparison
https://devexperts.com/blog/oracle-jdk-vs-openjdk-builds-comparison/

to-lz1
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした