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()にするだけです。
やってみると
for文よりも完結で読みやすい
並列処理も簡単に書ける
しかし
例外処理はそんなに得意ではない
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);
しかし、
Javaの日付処理系はすでに資産があるのであまり困らなかった
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で動作を見ながら実装していくような開発になりそうです