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になってしまうので値に変更を加えたい場合
結論
見通しの良いコードを書くことが大事
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で変わったくらいの変更はあった感じはあるかな
それ故に
逆に変わりすぎて手を付けられずにいるところも多かった感じもあります。
ただ、使ってみれば便利なんですけどね
JDK 9
ここからダウンロードして使えます
開発者目線で気になるもの
jshell(REPL)
とりあえず、/helpと/exitを覚えておけばだいたい使える
jshellツールを使用するとJavaコマンドを実行して即座に結果を取得できる
1行実行でHello,Worldが書ける
クラスを作る、メソッドを作る、他のメソッドをインポートできる
Read-Eval-Print-Loop
→Rubyなんかにはあった
Stream新メソッド
list.stream().takeWhile(s -> s.startsWidth(“J”)).forEach(System.out::println);
list.stream().dropWhile(s -> s.startsWith(“J”)).forEach(System.out::println);
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クラス利用による複雑さ
公開したいもの
抽象的なもの
クラスへのアクセス
インタフェース
ファクトリ
公開しないもの
向いてる開発
必要なさそう
→大きくなりそうならむしろ初めからモジュールを設計したほうがいい
すでに稼働している巨大なシステム
→不要というよりおそらく難しい
実際にモジュールを使う場合
サイトA moduleとBmodule
大規模プロジェクト
大規模リファクタリングをする時
小規模プロジェクト
moduleを使った安全な設計を取り入れる
システムのコンポーネント化をより意識
システムの導入は新規にしろ既存にしろ設計をしっかり意識する必要がありそう
大規模システムでのそれぞれが行ってたルール作成や規約づくりを標準に合わせる形にできるのでリプレース案件では使えるのかな?
延期延期で今年9月まで延ばされたJava9ですが、Jshellで動作を見ながら実装していくような開発になりそうです