初投稿です。
牛尾剛氏著の『世界一流エンジニアの思考法』を読んで光の速さで感化され、とりあえず今のプロジェクトで使っているJavaとSpring bootを徹底的に基礎から勉強しなおそうと思い立ちました。
※エンジニアとしては6年目とかですが、これまでJavaは表層をさらっと理解した程度でググりながらor他のプログラマの見よう見まねで現場を乗り越えてきたド三流エンジニアです。
まずはJava、ということで定番書でもあるEffective Java 第3版を読み始める。
読み始めてすぐ、
staticファクトリメソッドとは?という疑問にぶちあたりました。
というか、そもそもstaticって何?ちゃんと理解しているか?していない。
じゃあまずはstaticについてちゃんと理解しよう。
staticなメンバとは
結論から言うと、「インスタンスではなくクラスに紐づくメンバ」である。
ちょうど業務でいい例があったのでそれを使って整理してみます。
この日のタスクで解消したい課題は以下の通り。
「CSVから取り込んだ値に対して、数値項目を最終的なデータ連携先のDBの桁数に合わせてバリデーションかけたい」
(むしろ、やってなかったんかーい、とも思ったが)
まずはダダダっとこんな感じの処理を作ってみました。
String strNum = "1234.5678" // ほんとはcsvから読み取った値
try {
BigDecimal bigDecimalNum = new BigDecimal(strNum);
if (bigDecimalNum.precision() - bigDecimalNum.scale() > 30 || bigDecimalNum.scale() > 5) {
// 桁数チェックエラーの処理
}
} catch e {
// 数値以外が入ってきた場合の例外処理
}
が、桁数のべた書き気になるー
ってことでアーキテクトに相談。
(余談だが、このアーキテクト、かなり優秀なエンジニアである。エディタは秀丸を使用w)
そして以下のように改善してみました。
元々データ連携するための数値項目クラスが以下のような感じで実装されていた。
public class numValue {
private BigDecimal value;
// コンストラクタ
public numValue(BigDecimal value) {
this.value = value;
}
public BigDecimal getValue() {
return value;
}
}
そこに、こんな感じで追加。
public class numValue {
private BigDecimal value;
static final int INTEGER_LENGTH_LIMIT = 30; // staticなメンバ
static final int DECIMAL_LENGTH_LIMIT = 5; // staticなメンバ
// コンストラクタ
public numValue(BigDecimal value) {
this.value = value;
}
public BigDecimal getValue() {
return value;
}
public static boolean isValidLength(BigDecimal value) {
if (value.precision() - value.scale() > INTEGER_LENGTH_LIMIT
|| value.scale() > DECIMAL_LENGTH_LIMIT
) {
return false;
}
return true;
}
}
はい、出てきましたstaticなメンバ。
まずはstaticでないメンバ value
。
これは new numValue(value)
で生成されたインスタンスに紐づくメンバです。
numValue num1 = new numValue(new BigDecimal(123.45));
numValue num2 = new numValue(new BigDecimal(67.89));
それぞれのインスタンスで異なる値を持ちますね。
一方でstaticなメンバはというと、num1 でも num2でも同じ値を持ちます。
何ならインスタンス化しなくても値を参照できます。
System.out.println(num1.INTEGER_LENGTH_LIMIT); // 30
System.out.println(num2.INTEGER_LENGTH_LIMIT); // 30
System.out.println(numValue.INTEGER_LENGTH_LIMIT); // 30
これはこのメンバがクラスに紐づくメンバだからです。
最後にもう一度まとめ
- 非staticなメンバ:インスタンスに紐づく
- staticなメンバ:クラスに紐づく
以上がstaticについて私が理解したことのまとめです。
(でもまだstaticなクラスって?と聞かれたら説明できないのでまた勉強して書きます。)
余談:staticファクトリメソッド
余談ですが、ここで実装している isValidLength
メソッドは疑問の出発点だったstaticファクトリメソッドです。
staticファクトリメソッドの長所の1つである「メソッドの戻り値型の任意のサブタイプのオブジェクトを返せること」をしっかり享受しています。
(他にも長所はあるので、ちゃんと理解してそのうち書きます。)
このメソッドを利用して最初のコードを直してみます。
String strNum = "1234.5678" // ほんとはcsvから読み取った値
try {
BigDecimal bigDecimalNum = new BigDecimal(strNum);
if (!bigDecimalNum.isValidLength) {
// 桁数チェックエラーの処理
}
} catch e {
// 数値以外が入ってきた場合の例外処理
}
ビジネスロジックの中に定数をべた書きする必要もなくなってすっきりしました。(ここはstaticはあんまり関係ないかもしれないけど)
以上。
追伸
誤りなどありましたら是非ご指摘ください!