Effective Java 再履修
オブジェクトの生成と消滅
コンストラクタの代わりにstaticファクトリメソッドを検討する
こんなやつ
public class Boolean {
public static Hoge valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
}
自然とやってるな。Effective Java起因だったのか。
命名規則みてると「あるあるー」って感じ。
// from
// 単一のパラメータを受け取り、対応するインスタンスを返却する
Date d = Date.from(instant);
// of
// 複数のパラメータを受け取り、それらを含んだインスタンスを返却する
Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
// valueOf
// from や of の代わり
BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
// instance or getInstance
// パラメータがあれば、そのパラメータで表されているインスタンスを返却するが、必ずしも同じ値とは限らない
StackWalker luke = StackWalker.getInstance(options);
// create or newInstance
// instanceやgetInstanceに似ているが、呼び出しごとに新しいインスタンスを返却する
Object newArray = Array.newInstance(classObject, arrayLen);
// getType
// ファクトリメソッドが対象のクラスとは異なる場合に使用
FileStore fs = Files.getFileStore(path);
// newType
// 同上
BufferedReader br = Files.newBufferedReader(path);
// type
// getTypeやnewTypeの代わり
List<Complaint> litany = Collections.list(legacyLitany);
でもfromとofの使い分け(単数か複数か)は明確に言語化できていなかったな。
きっと何でやねん、コードをたくさん書いてしまった気がする(自戒)
メリット1::コンストラクタと異なり、名前を持つ
コンストラクタと違って、生成されるインスタンスを明確に表現できるのが強み、ってことかな
メリット2:コンストラクタと異なり、その呼び出しごとに新たにオブジェクトを生成する必要がない
Singletonのお話かな。冒頭のBooleanも新しいインスタンス返してないな。
メリット3:コンストラクタと異なり、メソッドの戻り値型の任意のサブタイプのオブジェクトを返せる
タイトルは分かるが、使い所があまり浮かばないな。自然とやってたりするのだろうか
メリット4:返されるオブジェクトのクラスは、入力パラメータの値に応じて呼び出しごとに変えられる
あまりstaticメソッドが返却するオブジェクトを入力パラメータ毎に変更したことがないな。
別言語でEnumのvalueOfを自前実装した時くらいかな。
メリット5:返されるオブジェクトのクラスは、そのstaticファクトリメソッドを含むクラスが書かれた時点で存在する必要さえない
デメリット1:publicあるいはprotectedのコンストラクタを元ないクラスのサブクラスは作れない
うーん。何の問題もないな。
デメリット2:プログラマがstaticファクトリメソッドを見つけることが難しい
「Javadocツールはいつの日かstaticファクトリメソッドに注意を払うかもしれない」
そんな日はまだ来てません(2022年7月19日 現在)
オブジェクトの生成と消滅
多くのコンストラクタパラメータに直面した時はビルダーを検討する
これも当たり前のようにやってたな。
どこで覚えたんだろう。たぶんAndroidのアプリ作ってた時だな。
public class Profile {
private final String firstName;
private final String lastName;
private final String sex;
private final Integer height;
private final Integer weight;
public static class Builder {
// 必須
private final String firstName;
private final String lastName;
private final String sex;
// 任意
private Integer height = null;
private Integer weight = null;
public Builder(String firstName, String lastName, String sex) {
this.firstName = firstName;
this.lastName = lastName;
this.sex = sex;
}
public Builder height(Integer height) {
this.height = height;
return this;
}
public Builder weight(Integer weight) {
this.weight = weight;
return this;
}
public Profile build() {
return new Profile(this)
}
}
private Profile(Builder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.sex = builder.sex;
this.height = builder.height;
this.weight = build.weight;
}
}
オブジェクトの生成と消滅
private のコンストラクタでインスタンス化不可能を強制する
Utilityクラスでよく見るやつね。
おそらくstaticおじさん達も多用したんだろうな。。。(遠い目)
public class StaticOjisan {
private StaticOjisan() {
throw new AssertionError();
}
}
オブジェクトの生成と消滅
資源を直接結びつけるよりも依存性注入を選ぶ
え、これ、みんな息をするように使ってないか。
オブジェクトの生成と消滅
不必要なオブジェクトの生成を避ける
現代ではあまり気にならないだろうけど、パフォーマンスチューニングの技として覚え得ておきたい。
オブジェクトの生成と消滅
使われなくなったオブジェクトの参照を取り除く
GC様に全て委ねています。すみません。
あと配列を直で操作することってもう殆どないんじゃないかな。
オブジェクトの生成と消滅
ファイナライザとクリーナーを避ける
うーん、恥ずかしながらこの辺りも使ったことない、というか意識したことがない。
try-with-resourcesとかは使うけど。
オブジェクトの生成と消滅
try-finallyよりもtry-with-resourcesを選ぶ
この辺は過渡期だどコーディング規約に入ってるレベルではないのか。
まぁあまり理由が説明されることはなかったけど。