日々常々

ふつうのプログラマがあたりまえにしたいこと。

Java17雑感

LTSとなるJava17が出ました。組織が今後もJavaを使っていけるかの試金石になるバージョンだと思います。

実際のとこLTSだから特別安定してるとかそんなことはないと思うし、6バージョン(3年)ごとにLTSにするってのもたぶんOracleさんが言ってみただけで、いろんなとこがそれに乗っかってるから、実質的に節目になってるに過ぎない。はず。 その程度のものなんだけど、私のようなのは乗っかりますし、たぶん多数派なんじゃないかなぁ……この派閥が運用で使うJavaのバージョンは8、11、17で、他のバージョンは評価に使うくらいでしょう。

11から17のジャンプになるんで、かなりたくさんの変更がありますが、業務アプリケーションの表層に関係するものはそこまで多くありません。パフォーマンスとかに影響のあるものは多々ありますが、基本的には早くなるはずで、問題になることは稀です。稀なことはよくあるんですが。

ということで、17にした時に業務アプリケーションの表層に影響のありそうなものを挙げて雑感を書いておきます。多分3ヶ月後くらいにはいうこと変わりますが。 JEPの名前とリンク、正式版として導入されたバージョンです。

  • Text Block: JEP 378, Java15
    • 複数行文字列が書けるようになります。
    • テストコードでJSONを書くときにエスケープしなくて良くなるのが嬉しいです。
    • プロダクトコードで巨大な文字列を扱う場合はテンプレートエンジンを使うと思うのであまり出番はないはずです。
    • あるとしたらSQL。JdbcTemplateやMyBatisのアノテーションなど、SQLJavaコードに交えて書くのが楽になる気はします。
  • Switch Expression: JEP 361, Java14
    • switch式です。 if式が欲しい
    • なんかswitchの強化多いんですよね。11以前はswitchなんて滅多に使わなかったけど、今後は見る機会が増えてくるかもしれません。
    • とはいえ無理に使わなくてもいいと思います。いい感じに書けそうなら試す、くらいで。
  • Record: JEP 395, Java16
    • 目玉。Java17を採用するなら使っていきたいかなーと。
    • 私がよく見る「lombokを使いたい動機」のほとんどが消えます。Data以外にBuilderとか使い倒してたら引き続き出番はありますが。
    • イミュータブルの強要、アクセサのメソッド名にgetがつかない、バインディングライブラリの対応状況など、地味なハードルはあります。
    • とは言え無理に使わなくてもいいと思います。recordでなければできないことも今はないだろし。
    • 2021-09-24追記: Recordを使ってく上で気にしとくこと 書いた。
  • Sealed Class: JEP 409, Java17
    • 他言語によく(?)あるSealedClassがJavaにもやって来ました。
    • 挙げてはみたものの、今後の準備として入った程度の認識で良いかと。
    • 使い方がこなれて、これを利用するものが増えてきてからでいいと思います。
  • Pattern Matching for instanceof: JEP 394, Java16
    • instanceofの後のキャストを書かなくて良くなります。
    • ジェネリクス以降登場機会の激減したキャストさんの活躍場所がまた減った。
    • 挙げてはみたものの、そもそもinstanceofを使う機会が少ないし、無理に使う必要は無いかと。
    • 使える場面では喜んで使えばいいと思います。一行減るだけだけど。

五つだけ。まとめると「TextBlockをテストで使って、データクラスを新しく作るならRecordを使ってみる」くらいでしょうかねぇ。

コーディングにそう影響ないから挙げてないけど、個人的に一番嬉しいのはHelpful NullPointerExceptionsだったりします。下手にnullチェックして例外投げるくらいなら、チェックせずそのままNPE発生させる方が役立つ可能性まである気がしてたり。

細かいけど嬉しいの

  • String#formatted Java12
  • Stream#toList Java16
  • Collectors#teeing Java12

ちょっと便利系。この辺のAPIIDEが教えてくれるから、存在自体を知らなくても、使う機会が来たら使えると思います。

実際いつあげんの

  • プロダクトはSpringBootがほとんどなんで、来週出るらしいJava17対応のSpringBoot2.5.5に乗っかる。
  • その頃にはbuildpackも出るだろから乗っかってないのもいけるかなって。
  • Java16で動かしてるものは軽い気持ちでコンパイルから全部17にあげる。
  • Java11のは検証環境のランタイムだけ17にしてしばらく回してから。

そんな感じ。

まともな情報

とりあえずSpringBootアプリケーションをherokuで公開する

手順の全て

  • mkdir {てきとうななまえ}
  • cd {てきとうななまえ}
  • curl -O https://start.spring.io/pom.xml -d dependencies=web -d javaVersion=8
  • Applicationクラス作成(後述)
  • git init
  • git add .
  • heroku create
  • heroku git:remote -a {createで作られたもの}
  • git push heroku main

9ステップ。これでgit pushのレスポンスメッセージに出てるURLにアクセスしたらhelloと表示されます。目指せ5分!

説明

書きたいところを適当に書いていきます。あ、herokuアカウントの作成とコマンドラインツールのインストールは済ませといてください。私はbrewで入れてます。

この記事は現在に対する局所最適なので、バージョンなどは割愛します。 未来にこの記事のバージョンに合わせて動かすより、やりたいときにその時点での最新のやり方でやるのがいいと思います。 どうせherokuの挙動変わったらバージョンなんぞ合わせられないし。

curl...

Spring Initializr です。ブラウザでも使えますけど私はもっぱら curl で叩いてます。 詳しくは SpringBootのプロジェクトを作成する - 日々常々 とか。

普段はGradle使っていますが、今回はMavenを選択。

これは plain jarがSpringBoot2.5からできるようになって、herokuのデフォルトだと *.jar で起動しようとしてエラーになるため。 無効にするとかexecutable jarを実行するように明示するとかすればいいんだけどステップが増えるので今回は回避しています。

-d dependencies=web はこれがないとウェブアプリケーションにならないので。(webflux でもいいんだろけど)

-d javaVersion=8 がポイントでherokuのデフォルトJavaバージョンは1.8だったりします。SpringInitializrデフォルトは11なんで、そのままじゃ動かない。 pom.xmlを修正したり、system.properties(herokuが読む設定)に java.runtime.version=11 とか書いてもいいんだけど、今回は一番ステップが少なくなるの選びました。 普通は system.properties 書くことになると思います。書けばJava16も使えるよ。実際いくつかで使ってたりします。

Applicationクラス作成

コマンドだけで無理やり作るとこう。

% mkdir src/main/java/hoge
% cat>src/main/java/hoge/Application.java
package hoge;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@SpringBootApplication
@RestController
public class Application {

    public static void main(String[] args) { SpringApplication.run(Application.class, args); }

    @RequestMapping
    String index() { return "hello"; }
}

1クラスとはいえIDEで書くのがなんだかんだで早いと思う。importとか書いてられん。 (とはいえIDEで書くと後の git add .. じゃ余計なものが入るので pom.xmlApplication.java だけaddしなきゃになって若干面倒にはなる。些細な問題だけど。)

@Controller でなく @RestController なのはハンドラメソッドの戻りで文字列を直接返したいから。@Controllerだとテンプレート探しに行ってエラーになって /error なくて404になっちゃう。@ResponseBody とか書けばいいんだけど面倒だから @RestController にしちゃった。

あとデフォルトパッケージにすると余計なものコンポーネントスキャンで食っちゃうので、適当でもいいんでパッケージはつけなきゃです。

heroku create

ログインしてないとこれ叩いたときに自動でログイン促されます。ブラウザが開く。

heroku createapps:create の短縮。アプリ名を渡せるけど、指定しなかったら適当につけてくれる。今回はお任せ。

f:id:irof:20210805012937p:plain

これだと salty-woodland-12925 ですね。(destroy済み)

次の heroku git:remotegit remote add heroku {herokuのgitのURL} を代わりにやってくれるコマンドです。git コマンドを叩いても一緒なんでお好きな方でOK。gitのURLもcreate 時に出てますしね。 ここに push したらherokuはビルドして動くようにしてくれます。

git push

ソースコードを投げ込むといい感じにビルドしてくれるのがbuildpack。 「pom.xmlがあるからMavenだろ」「SpringBootだからこうだろ」みたいなのを雰囲気でやってくれます。 雰囲気でやってくれすぎて何がどうなってるか分からなくなる可能性がそこそこ。

わかりたかったら https://buildpacks.io/ とかで pack コマンド使って手元でビルドして docker run とかいじってみると、何かわかるかもしれない。わからないかもしれない。

git push したらMavenのいつものjarダウンロードのログがダラダラ流れる。git push でそんなん表示されるのに慣れてないと面食らうかもですね。

成功したらこんな感じ。

f:id:irof:20210805014310p:plain

Released とかの次の行の https://... を開いたら動いてる。はず。

今回はherokuのgitにpushしたけど、普段はGitHubからherokuに繋いで使ってます。この辺の連携も素直につながるのでいいですよね。

あとがき

適当にやろうとしたら地味なつまずきかたをしたので整理してみました。 ビルドは3分くらいで終わるんで、スムーズにできれば「ゼロから始めて5分でデプロイ完了」までいけると思います。ドラが鳴る前に終わることを祈る。

今回つまづいたのは

  • *-plain.jar のおかげでGradleだと素直に動かない。
    • build.gradlejar タスク止めるか、Procfile(herokuの設定ファイル)で動かすJar名を明示したらいける。普段は後者でやってる。
  • デフォルトJavaバージョンの食い違い
    • pom.xml とか build.gradle のバージョン読んでくれるようにきっとそのうちなると信じてる。

……くらいかな? こういうの踏んだときに雰囲気で察しちゃったりするんだけど、「ここにこのログが出てる」と確認しておくのも大事で、そういうのがこの手の素振りの目的だったりもします。

herokuでMaven使った記憶はないんだけど、「どうせいけるだろ」みたいなノリで push したらいけました。よかったよかった。 この「どうせいけるだろ」みたいな感覚って結構大事だと思ってたりします。たまに大外しするけど。

追記: タイムアタック結果

  • start: 2021-08-05T11:20:11
  • finish: 2021-08-05T11:22:08

コマンドのみの一発勝負。1分57秒でした。 mkdirから最後にcurlでhelloが返って来るところまで(curlのhello確認は上の手順にないですが。)で、全ログは gist に置いてます。 少し上で「ビルドは3分」とか書いてますが、herokuのご機嫌によりますね。

…… git initReinitialized になってるな。空じゃなかったのか。🤔

似た記事

irof.hateblo.jp

ソースコードの公開まで」って感じですね。今回のは手元の動作確認すらしてないという・・・。

アームがないモニターアームを買ってみた、その後

irof.hateblo.jp

f:id:irof:20210728115649p:plain

ということです。

  • 移動に自由度がない。上下移動するにはネジまわさなきゃで面倒。
  • デッドスペース(10数センチ)を許容するには机が小さすぎる
  • モニターの上下移動は使いづらい。上端、下端でとまらないからカーソルが行方不明になる。

あたりが理由。

ちなみに他のモニターアーム。

写真の通り、結局エルゴトロンにしてます。

マットブラックにしてみた。格好いい(黒が好きなアレです)。

台座はそこそこ大きいから複数並べると邪魔になるんだけど、追加モニターアームも売ってるし、1つ目の台座に2つのアームつけちゃってます。

追加用を買わなかったのは台座がほしくなることもありそうだから……値段も大差ないし。