IT戦記

ただただがむしゃらにソフト開発をしていたい

Effective Java 読書会 3 日目「それ Apache Commons で出来るよ」

はじめに

じゃっばじゃばにしてやんよー♪っと
( ´ー`)フゥー...(゚Д゚)ハッ!
どーん

今日読んだところ

45 ページ〜 66 ページ

hashCode 2 契約

  • シグニフィカントなフィールドを変更しなければ、いつ hashCode を呼び出しても値は変わらない
  • x.equals(y) が true の場合は、 x.hashCode() == y.hashCode() が true

equals をオーバーライドしたら hashCode もオーバーライドすべき

前述の 2 契約を守るために必要

x.equals(y) が false の場合

かならずしも、 x.hashCode() != y.hashCode() になる必要はないが、
値がバラけているほうが HashMap のキーとして使ったときのパフォーマンスがいい。

パフォーマンスについて

hashCode 関数のコストをケチって HashMap の性能が悪くなったら本末転倒

hashCode の作り方

適当なゼロでない定数に、シグニフィカントなフィールのハッシュ値

result = 31 * result + field.hashCode()

と言う感じで合体させていけばいい

プリミティブな値の hashCode

  • boolean
    • hashCode = x ? 0 : 1;
  • byte, char, short, int
    • hashCode = (int) x;
  • long
    • hashCode = (int) (x ^ (x >>> 32));
  • float
    • hashCode = Float.floatToIntBits(x);
  • double
    • long y = Double.doubleToLongBits(x); hashCode = (int) (y ^ (y >>> 32));

他の hashCode

  • null
    • hashCode = 0;
  • List
    • Arrays.hashCode(x);

でも結局 hashCode に関しては

ここまで読んであれだけど Apache Commons の HashCodeBuilder 使えし!
http://commons.apache.org/lang/api/org/apache/commons/lang/builder/HashCodeBuilder.html
まさに外道

あ、そういえば equals も

EqualsBuilder 使えし!
http://commons.apache.org/lang/api/org/apache/commons/lang/builder/EqualsBuilder.html
な、なんだってー!!

もちろん toString ビルダーもね!

ToStringBuilder 使えし!
http://commons.apache.org/lang/api/org/apache/commons/lang/builder/ToStringBuilder.html
まいりましたーーー!!!

たとえば、以下のようなデータクラス

public class AdministrativeDivision {

    private String unit;

    private String name;
    
    public AdministrativeDivision(String name, String unit) {
        this.unit = unit;
        this.name = name;
    }

    public void setUnit(String unit) {
        this.unit = unit;
    }

    public String getUnit() {
        return unit;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

ちょこちょこっといじって… 

public class AdministrativeDivision {

    // 略

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }

    @Override
    public boolean equals(Object o) {
        return EqualsBuilder.reflectionEquals(this, o);
    }

    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }
}

はい!完成っと!
おおおおおおおおすげーリフレクション楽だー!

シグニフィカントなフィールドが特定されている場合は

以下のような感じ

public class AdministrativeDivision {

    // 略

    @Override
    public String toString() {
        return new ToStringBuilder(this).append("name", name).append("unit", unit).toString();
    }

    @Override
    public boolean equals(Object o) {
        if (o == null) { return false; }
        if (o == this) { return true; }
        if (o.getClass() != getClass()) { return false; }
        AdministrativeDivision rhs = (AdministrativeDivision) o;
        return new EqualsBuilder()
                 .appendSuper(super.equals(o))
                 .append(name, rhs.name)
                 .append(unit, rhs.unit)
                 .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(name).append(unit).toHashCode();
    }
}

すげーよ! Apache Commons 便利すぎるよ!

clone

clone の中で new はしない。
super.clone で生成されたオブジェクトをイジって返す。
持っているリファレンスは clone して super.clone の結果にくっつけてやる。
とかとか。
てか、 clone って使わないよなー。という話に。
static ファクトリメソッドはやしてやったほうがいいんじゃないかという話になった。

compareTo 4 契約

  • signum(x.compareTo(y)) == -signum(y.compareTo(x))
    • x.compareTo(y) が例外をスローする場合は、 y.compareTo(x) も例外をスローしなければならない
    • x.compareTo(y) が例外をスローしない場合は、 y.compareTo(x) も例外をスローしてはいけない
  • (x.compareTo(y) > 0 && y.compareTo(z) > 0) が true なら x.comparetTo(z) > 0 も true (推移的)
  • x.compareTo(y) == 0 が true なら signum(x.comparetTo(z)) == signum(y.compareTo(z)) は必ず true
  • x.compareTo(y) == 0 が true なら x.equals(y) (これは、強く推奨されているが絶対ではない)

double, float の compareTo と equals

double, float は NaN や -0.0 のとき == や < や > などの演算子では、 equals 契約や compareTo 契約を守れないため
Double.equals, Float.equals, Double.compare, Float.compare を使わなければならない

引き算による実装

オーバーフローするのでダメよ。

っていうか

ざゎ…ざゎ…
@hikoma っくす 「CompareToBuilder 使えば」
http://commons.apache.org/lang/api/org/apache/commons/lang/builder/CompareToBuilder.html
きたー!

と言うわけで

今日は、 Apache Commons にじゃっばじゃばにされちゃいました><