覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。 twitter: @yyoshikaw

Lombok - @EqualsAndHashCode

Lombokの@EqualsAndHashCode(lombok.EqualsAndHashCode)アノテーションの利用サンプルです。

クラスに@EqualsAndHashCodeアノテーションを付与することで、対象クラスのequalsメソッドとhashCodeメソッドがクラス内のメンバに応じて適切にオーバーライドされます。

ちなみに、@Data@Valueのアノテーションを付与すると、内部的に@EqualsAndHashCodeアノテーションが付与されたのと同じことが起こります。


デフォルトの@EqualsAndHashCodeを付与

パラメータの指定なしで@EqualsAndHashCodeを付与すると、クラス内の全メンバを利用してequals, hashCodeの処理が生成されます

■@EqualsAndHashCodeを付与したクラス

import java.util.List;

import lombok.EqualsAndHashCode;

@EqualsAndHashCode
public class Person1 {

    private long id;

    private String name;

    private List<String> notes;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public List<String> getNotes() {
        return notes;
    }

    public void setNotes(List<String> notes) {
        this.notes = notes;
    }
}

■利用側のコード

import java.util.Arrays;

public class Person1Client {

    public static void main(String[] args) {
        Person1 p1 = new Person1();
        p1.setId(1L);
        p1.setName("Taro");
        p1.setNotes(Arrays.asList("note1", "note2", "note3"));

        Person1 p2 = p1;

        Person1 p3 = new Person1();
        p3.setId(1L);
        p3.setName("Taro");
        p3.setNotes(Arrays.asList("note1", "note2", "note3"));

        Person1 p4 = new Person1();
        p4.setId(1L);
        p4.setName("Taro");
        p4.setNotes(Arrays.asList("note1", "note2", "note3", "note4"));

        System.out.println("p1#hashCode: " + p1.hashCode());
        System.out.println("p2#hashCode: " + p2.hashCode());
        System.out.println("p3#hashCode: " + p3.hashCode());
        System.out.println("p4#hashCode: " + p4.hashCode());

        System.out.println("p1#equals(p2): " + p1.equals(p2));
        System.out.println("p1#equals(p3): " + p1.equals(p3));
        System.out.println("p1#equals(p4): " + p1.equals(p4));
    }
}

■実行結果

メンバの値が同じならhashCodeの値は一致し、equalsの結果もtrueを返しています。

p1#hashCode: 1348088265
p2#hashCode: 1348088265
p3#hashCode: 1348088265
p4#hashCode: -1365998099
p1#equals(p2): true
p1#equals(p3): true
p1#equals(p4): false

■実際に生成されるソースコード

各メンバの値を使用して、equals, hashCodeの処理が生成されていることが分かります。

import java.util.List;

public class Person1 {
    private long id;
    private String name;
    private List<String> notes;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public List<String> getNotes() {
        return notes;
    }

    public void setNotes(List<String> notes) {
        this.notes = notes;
    }

    @Override
    public boolean equals(final Object o) {
        if (o == this) return true;
        if (!(o instanceof Person1)) return false;
        final Person1 other = (Person1) o;
        if (!other.canEqual((Object) this)) return false;
        if (this.getId() != other.getId()) return false;
        final Object this$name = this.getName();
        final Object other$name = other.getName();
        if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
        final Object this$notes = this.getNotes();
        final Object other$notes = other.getNotes();
        if (this$notes == null ? other$notes != null : !this$notes.equals(other$notes)) return false;
        return true;
    }

    protected boolean canEqual(final Object other) {
        return other instanceof Person1;
    }

    @Override
    public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        final long $id = this.getId();
        result = result * PRIME + (int) ($id >>> 32 ^ $id);
        final Object $name = this.getName();
        result = result * PRIME + ($name == null ? 43 : $name.hashCode());
        final Object $notes = this.getNotes();
        result = result * PRIME + ($notes == null ? 43 : $notes.hashCode());
        return result;
    }
}


equals, hashCodeから除外するフィールドを指定する

@EqualsAndHashCodeを付与するとデフォルトでは全メンバをもとにequals, hashCodeがオーバライドされますが、
excludeパラメータにフィールド名を指定すると、equals, hashCodeの処理から除外することができます。

■@EqualsAndHashCodeを付与したクラス

excludeの対象にnotesを指定しています。

import java.util.List;

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(exclude={"notes"})
public class Person2 {

    private long id;

    private String name;

    private List<String> notes;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public List<String> getNotes() {
        return notes;
    }

    public void setNotes(List<String> notes) {
        this.notes = notes;
    }
}

■実際に生成されるソースコード

equalshashCodeの処理内にnotesフィールドが含まれていないことが分かります。

import java.util.List;

public class Person2 {
    private long id;
    private String name;
    private List<String> notes;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public List<String> getNotes() {
        return notes;
    }

    public void setNotes(List<String> notes) {
        this.notes = notes;
    }

    @Override
    public boolean equals(final Object o) {
        if (o == this) return true;
        if (!(o instanceof Person2)) return false;
        final Person2 other = (Person2) o;
        if (!other.canEqual((Object) this)) return false;
        if (this.getId() != other.getId()) return false;
        final Object this$name = this.getName();
        final Object other$name = other.getName();
        if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
        return true;
    }

    protected boolean canEqual(final Object other) {
        return other instanceof Person2;
    }

    @Override
    public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        final long $id = this.getId();
        result = result * PRIME + (int) ($id >>> 32 ^ $id);
        final Object $name = this.getName();
        result = result * PRIME + ($name == null ? 43 : $name.hashCode());
        return result;
    }
}


equals, hashCodeの対象に含めるフィールドを指定する

ofパラメータを使用することで、equals, hashCodeの処理に含めるフィールドを明示的に指定することができます

■@EqualsAndHashCodeを付与したクラス

import java.util.List;

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(of={"id"})
public class Person3 {

    private long id;

    private String name;

    private List<String> notes;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public List<String> getNotes() {
        return notes;
    }

    public void setNotes(List<String> notes) {
        this.notes = notes;
    }
}

■実際に生成されるソースコード

idフィールドをもとに、equals, hashCodeの処理が生成されていることが分かります

import java.util.List;

public class Person3 {
    private long id;
    private String name;
    private List<String> notes;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public List<String> getNotes() {
        return notes;
    }

    public void setNotes(List<String> notes) {
        this.notes = notes;
    }

    @Override
    public boolean equals(final Object o) {
        if (o == this) return true;
        if (!(o instanceof Person3)) return false;
        final Person3 other = (Person3) o;
        if (!other.canEqual((Object) this)) return false;
        if (this.getId() != other.getId()) return false;
        return true;
    }

    protected boolean canEqual(final Object other) {
        return other instanceof Person3;
    }

    @Override
    public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        final long $id = this.getId();
        result = result * PRIME + (int) ($id >>> 32 ^ $id);
        return result;
    }
}



関連エントリ