ITお絵かき修行

3歩歩いても忘れないために

JJUG CCC 2017 Springメモ【AB6 Java8プログラミング ベストプラクティス & きしだが働いてるかどうかIDEのメモリ使用状況から機械学習で判定する】

JJUG CCC 2017 Springに参加した。
表題のセッションに参加したので、参加メモを書いておく。

JJUG CCC 2017 Spring
JJUG CCC 2017 Spring
■Call for Papers
きしだが働いてるかどうかIDEのメモリ使用状況から機械学習で判定する
SlideShare
Java8 コーディングベストプラクティス and NetBeansのメモリログから...

【概要】

最近は機械学習が流行しています。 しかし、Javaのメモリ使用状況のような波形データの分析は、そのままの形では単純な機械学習器に不向きです。 このセッションでは、このような波形データに対して、ウェーブレット変換で周波数解析してから機械学習を行う方法について紹介します。
…とのことだったが予定変更して機械学習部分はさわりの部分のみとして、大半はJava8のプログラミングで気を付けることを話されていた。
→スライドの内容はレビュワー/レビュイそれぞれがチェックシート的に使えそうと感じた(特にJava8の部分)

【内容】

機械学習

NetBeansのメモリ使用量をJMX経由で取得し、InfluxDB・Grafanaを通して可視化
GCの場合、波形データとなるため単純な閾値での判定はできない
→「周波数解析」を行った。
フーリエ変換→離散ウェーブレット変換
NetBeansのデフォルトのスレッド数が32なのでそれを教師データにした(※入れているプラグインによっては増える)
・実は機械学習でなく近傍法などの障害検知手法でよかったのでは…というオチ

■Java8プログラミングベストプラクティス

1.一般的なこと
(1)変数に適当な初期値を入れない。
理由:(宣言部では宣言のみとすると)最適化がかかりやすい、コンパイルエラーへの期待(※Java8では実質的final扱いとなる)
NG例:Stringの変数の初期値にデフォルト値を入れておき、条件に応じて入れ替えるのはNG

(2)ImmutableList/Mapを使う
理由:値がどこで書き換えられるかをソースを追うのは辛い、並列処理で不具合が起きない
  →for文に比べ性能が落ちる場面があるが、大抵の場合は問題にならない
NG例:for文の中でList内の値を書き換えて、同じListのインスタンスを別の処理で使いまわす
  →ラムダ式が使えない場合はGuava等のライブラリを使うとよい

(3)論理式をうまく使う
 →条件式の片方がbooleanリテラルの条件式の場合は論理演算にするetc
理由:バグの元、複雑になる
NG例:※スライドを参照

(4)大事なものはインデントを浅く
理由:読む範囲を短くする。早期リターン。
NG例:if文内の処理が全部終わって処理を抜けた後でreturn null;とかするのはNG

(5)if文の中でbooleanを反転させない
理由:バグの元(※びっくりするようなコードは書かない)
NG例:メソッド内でOKの場合にfalseを返し、NGの場合にtrueを返す

(6)(コンストラクタ・メソッド共に)オーバーロードは下記の目的のためだけに使うべき。
1.引数の省略
2.処理の集約
OK例:引数が多いものから先にクラス内に書いていき、一度に読む処理量を減らす。

(7)メソッド内の処理が違う場合はメソッド名を変える
理由:バグの元
NG例:同じメソッド名で引数の型だけが違う


2.Java8
(1)Stream
・forEachのifはfilterにできる
・forEachの値変換はmapにできる
・forEachの入れ子はflatMapにできる
・count>0は使わない
【メリット】
・行われる操作が限定される
・変数の行く先を追わなくてよい
・結果、読みやすくなる
ラムダ式の中で手続き処理的なコードを書かなければよさそう

(2)例外処理
→例外処理と関数型プログラミングは相性が悪いのであきらめる。
 →try-catchはgotoである。そのため、集合を扱う処理の中にポインタの考え方を持ち込むのはむつかしい。
 →stream・ラムダ式をあきらめるか、try-catchを書くか

(3)Optional
・ifPresentのifをfilterにできる
・ifPresentでの値変換はmapにできる
・ifPresentでの入れ子はflatMapにできる
・引数では使わない
→メソッド定義者がnullチェックを実装するべき
 →Optionalはserializableでないので色々問題になりそう
・orElseThrowにException::newを書かない
→Exception::newをしてしまうと例外発生時の情報が握りつぶされてしまうので、例外メッセージを含めて例外をthrowする

(4)FunctionalInterface
ラムダ式を割り当てた変数は作らない。
→メソッドとして定義する
・むやみにAtomicInteger/Longを使わない
→finalから逃げる場合は配列を使えば解決できる

(5)Date and time
・Calendarクラスの時みたいに「3*24*60*60」とかしないで、Durationクラス等のメソッドを呼んで計算しよう


3.Java7以前
(1)LinkedListは使わない
→連結リストとしての動作を期待しても、内部実装がよくないためArrayListよりも処理時間がかかる場合がある
 →ArrayListと違いメモリ上に分散して領域確保するため、CPUのキャッシュに載らない可能性がある

(2)IOExceptionをRuntimeExceptionへ変換したいときはUncheckedIOExceptionというクラスがあるのでそちらを使おう