技術関連の覚書

案件でやったり自宅で試したことの覚書

Java8をおさらいしつつJava9を眺める

https://d-cube.connpass.com/event/62507/

こちらに行って来ました

案件ではJDK8を使いながらJava7までの機能しか使えないなど(規約でLambda、Streamを許可されない)でちゃんと使ってこれなかったのでこれを機会に案件でどのように使ってきてJava9ではどのようにしたらよいかを聞いてきました。

これまでの開発環境(Java6+7)からJava8へ移行した時の話

Lambda式とStreamAPIの登場

Lambda式は1メソッドのインタフェースと実装をそのまま1行で書けるような記述ができます。 、Listや配列などのループを1行で記述もできます。 こういったことからfor文禁止にトライしてみたようです。

今までListをFor分で書くところがStreamで書くと1行で書けて見通しが良くなる →for文禁止の規約ができた

Streamを使えば

List lang = Arrays.asList("Java7", "Java8", "Java9");
for (String s: str) {
    System.out.println(s);
}

List lang = Arrays.asList("Java7", "Java8", "Java9");
Stream<String> st = lang.stream();
st.forEach(System.out::println);

にできます。

並列処理の場合はlang.stream()をlang.parallelStream()にするだけです。

やってみると

  1. for文よりも完結で読みやすい

  2. 並列処理も簡単に書ける

しかし

  1. 例外処理はそんなに得意ではない

  2. for文ダメ絶対はなかなかできない

for文を許す場合は * 処理が複雑で可読性が下がる場合 * count++などしたい時 →Finalになってしまうので値に変更を加えたい場合

結論

  • for文は原則禁止

  • 完全駆逐は難しい

  • StreamとLambdaで書くことでぱっと読みにくいが指摘しやすくなった*1

見通しの良いコードを書くことが大事

Date & Time APIの登場

Calendar 月が-1 Calendar.Julyなどなら問題はないが7にすると8月になってしまうなどバグの元があった

Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2017)
cal.set(Calendar.MONTH, Calendar.JULY) // ここをcal.set(Calendar.MONTH, 7)にすると8月になる
:

LocalDateTime date = LocalDateTime.of(2017, 7, 26, 15, 0, 0);

しかし、

  1. Javaの日付処理系はすでに資産があるのであまり困らなかった

  2. Date & Timeはたしかに便利

正直なところすでに日付処理はUtilなど整備していたのであまり有り難みがなかった*2

既存のコードは無理してリファクタリングしない 新規に使うならDate&TimeAPIの方がよい

これは同感でした

Optional

Optional<String> strOpt = Optional.of("Java")

//インスタンス生成

System.out.println(strOpt.get())

空のOptionalの生成

Optionalから値がある場合のみ処理をする if文で分岐するのはアンチパターン

if (s!=null) {
    System.out.println(s);
}

このように

ifPresent(s -> {
  System.out.println(s);
});
  • Optional -> nullであることを明示的に許容する

  • その戻り値にnullがあることをソースレベルで表現できることに価値がある

  • すべてOptionalにしたらいいというわけでない

  • isPresent+getはあまり今までと変わらないので使わないようにしてる

  • 使うならifPresentやorElse,orElseGet

java8は現場の開発者にとってインパクトが大きい変更が多数会った StreamやLambda式、Optionalなどは実装方針に影響をもたらしたのでは?

といった結論でした

Java5で変わったくらいの変更はあった感じはあるかな

それ故に

  • コーディング規約などはもっと早い段階で見直したかった

  • 学習コストはそんなに高くなかった印象(みんな新しい物好き)

逆に変わりすぎて手を付けられずにいるところも多かった感じもあります。 ただ、使ってみれば便利なんですけどね

Java9ではどうなる?

JDK 9 ここからダウンロードして使えます

開発者目線で気になるもの

jshell(REPL)

とりあえず、/helpと/exitを覚えておけばだいたい使える

jshellツールを使用するとJavaコマンドを実行して即座に結果を取得できる 1行実行でHello,Worldが書ける クラスを作る、メソッドを作る、他のメソッドをインポートできる

  • 補完が聞くようになってるのでタブを押して書ける

  • やろうと思えばいろいろできる

  • 最初の一行を実行するのが圧倒的に楽

  • 業務では使いドコロが思いつかない スクリプト的な開発みたいなことができるかですね

  • 初学時にちょっといじる

  • ペアプロで見せるなんかの時はいいかも

Read-Eval-Print-Loop

Rubyなんかにはあった

Stream新メソッド

  • takeWhile

list.stream().takeWhile(s -> s.startsWidth(“J”)).forEach(System.out::println);

  • dropWhile

list.stream().dropWhile(s -> s.startsWith(“J”)).forEach(System.out::println);

  • ofNullable

Java8でやるとnullチェックが必要な場合 map.get() == nullをチェック

keys.stream().flatMap(str -> Stream.ofNullable(map.get(str))).forEach(System.out::println);

Optional

ifPresentOrElse

opt.ifPresentOrElse(s -> System.out.println(“This is ”+s),() -> System.out.println(“nothing”));

Optional#Stream

OptionalをStreamに変換することができる

Optionalで構成されるListがある時StreamとflaMapを併用すると簡単nullをスキップした処理ができる

list.stream()

Optionalが使いやすくなる 使いドコロが増えそうな文ちゃんとコーディング規約を決めたい 実装時以外でnullを意識しないで良い

ImmutableなCollectionのファクトリーメソッド

List#of Set#of Map#of

コレクションのインスタンスを作る時

new Map<>(){{
  put();
  ..
}};

Guavaでイミュータブル

immutableMap = ImmutableMap.builder().put().put()...

がこんな感じに

list = List.of("Java7", "Java8", "Java9");
Set.of("Java", "Go", "Rub", "Scala");
Map.of("key1", "value1", ...)

もさっとしてたコードがすっきりする ライブラリを使ってたところが標準でできるようになる

Mapはkey,valueで改行しないと混乱しそうな気もします

モジュールシステム

jigsaw

Javaをモジュール化して必要な部分だけを使えるように

クラスパスと肥大化したJDK →複雑になり管理が難しくなる →依存関係がコンフリクトを起こす可能性がある

言語仕様の強化ではなくmoduleの機能と解決するもの

機能パッケージの依存関係の記述 公開するクラスとしないクラスの明治 予期せぬ利用をコンパイルエラーでチェック

解決するもの 意図しない場所でのpublicクラス利用による複雑さ

公開したいもの

  • 抽象的なもの

  • クラスへのアクセス

  • インタフェース

  • ファクトリ

公開しないもの

  • 実装

  • bean

  • model

向いてる開発

  • 大規模

  • 大人数

必要なさそう

  • 小規模

  • 少人数

→大きくなりそうならむしろ初めからモジュールを設計したほうがいい

すでに稼働している巨大なシステム →不要というよりおそらく難しい

実際にモジュールを使う場合

サイトA moduleとBmodule

大規模プロジェクト 大規模リファクタリングをする時

小規模プロジェクト moduleを使った安全な設計を取り入れる

システムのコンポーネント化をより意識

システムの導入は新規にしろ既存にしろ設計をしっかり意識する必要がありそう

大規模システムでのそれぞれが行ってたルール作成や規約づくりを標準に合わせる形にできるのでリプレース案件では使えるのかな?

延期延期で今年9月まで延ばされたJava9ですが、Jshellで動作を見ながら実装していくような開発になりそうです

*1:ただし、デバッグはしづらくなることもある

*2:確かに日付関係のライブラリを独自に作ってるところは多いです