Khi làm với với các đối tượng Java, rất nhiều trường hợp chúng ta cần phải định nghĩa các phương thức toString(), equals() và hashCode()… Những phương thức này có thể được thêm vào các đối tượng Java một cách tự động bằng cách sử dụng Project Lombok. Cách làm sẽ như thế nào? Trong bài viết này, mình sẽ hướng dẫn các bạn!
Đầu tiên, mình sẽ tạo một Maven project để làm ví dụ:
với Project Lombok dependency như sau:
1 2 3 4 5 6 |
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> <scope>provided</scope> </dependency> |
Các bạn hãy nhớ là chúng ta cần phải install Project Lombok plugin vào trong IDE của chúng ta để IDE có thể hiểu và không bị lỗi compile. Xem hướng dẫn cài đặt Project Lombok plugin trong IntelliJ IDE ở đây nhé các bạn!
Bây giờ, ví dụ mình có class Student với một số thông tin như sau: name, code, dateOfBirth. Nếu không sử dụng Project Lombok, mình phải khai báo các phương thức toString(), equals() và hashCode() (các phương thức Getter, Setter và constructor mình đã định nghĩa với Project Lombok) như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
package com.huongdanjava.lombok; import lombok.*; import java.util.Date; @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class Student { private String name; private transient String code; private Date dateOfBirth; public Student(String name) { this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; if (!name.equals(student.name)) return false; if (!code.equals(student.code)) return false; return dateOfBirth.equals(student.dateOfBirth); } @Override public int hashCode() { int result = name.hashCode(); result = 31 * result + code.hashCode(); result = 31 * result + dateOfBirth.hashCode(); return result; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", code='" + code + '\'' + ", dateOfBirth=" + dateOfBirth + '}'; } } |
Chúng ta có thể để cho Project Lombok tự động làm việc này bằng cách sử dụng annotation @ToString và @EqualsAndHashCode như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package com.huongdanjava.lombok; import lombok.*; import java.util.Date; @Getter @Setter @NoArgsConstructor @AllArgsConstructor @ToString @EqualsAndHashCode public class Student { private String name; private transient String code; private Date dateOfBirth; public Student(String name) { this.name = name; } } |
- @ToString: annotation này sẽ giúp chúng ta generate phương thức toString() với tất cả các field của đối tượng Java. Chúng ta sẽ không cần phải quan tâm tới phương thức này mỗi khi chúng ta thêm mới hoặc loại bỏ một số field cho đối tượng Java.
- @EqualsAndHashCode: annotation này sẽ giúp chúng ta generate phương thức equals() và hashCode() với tất các field không phải là static hoặc transient của đối tượng Java một cách tự động.
Bây giờ, nếu các bạn kiểm tra thư mục /target/classes/com/huongdanjava/lombok, các bạn sẽ thấy nội dung của Student class như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.huongdanjava.lombok; import java.beans.ConstructorProperties; import java.util.Date; public class Student { private String name; private transient String code; private Date dateOfBirth; public Student(String name) { this.name = name; } public String getName() { return this.name; } public String getCode() { return this.code; } public Date getDateOfBirth() { return this.dateOfBirth; } public void setName(String name) { this.name = name; } public void setCode(String code) { this.code = code; } public void setDateOfBirth(Date dateOfBirth) { this.dateOfBirth = dateOfBirth; } public Student() { } @ConstructorProperties({"name", "code", "dateOfBirth"}) public Student(String name, String code, Date dateOfBirth) { this.name = name; this.code = code; this.dateOfBirth = dateOfBirth; } public String toString() { return "Student(name=" + this.getName() + ", code=" + this.getCode() + ", dateOfBirth=" + this.getDateOfBirth() + ")"; } public boolean equals(Object o) { if(o == this) { return true; } else if(!(o instanceof Student)) { return false; } else { Student other = (Student)o; if(!other.canEqual(this)) { return false; } else { Object this$name = this.getName(); Object other$name = other.getName(); if(this$name == null) { if(other$name != null) { return false; } } else if(!this$name.equals(other$name)) { return false; } Object this$dateOfBirth = this.getDateOfBirth(); Object other$dateOfBirth = other.getDateOfBirth(); if(this$dateOfBirth == null) { if(other$dateOfBirth != null) { return false; } } else if(!this$dateOfBirth.equals(other$dateOfBirth)) { return false; } return true; } } } protected boolean canEqual(Object other) { return other instanceof Student; } public int hashCode() { int PRIME = true; int result = 1; Object $name = this.getName(); int result = result * 59 + ($name == null?43:$name.hashCode()); Object $dateOfBirth = this.getDateOfBirth(); result = result * 59 + ($dateOfBirth == null?43:$dateOfBirth.hashCode()); return result; } } |
Các bạn có thể thấy, bởi vì field code trong class Student của mình được khai báo với từ khoá transient nên khi generate phương thức equals() và phương thức hashCode(), field này đã không được include.
Bây giờ, nếu chúng ta có 2 đối tượng Student khác code nhưng cùng name và dateOfBirth thì khi so sánh 2 đối tượng này, chúng sẽ bằng nhau.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package com.huongdanjava.lombok; public class Example { public static void main(String[] args) { Student student1 = new Student(); student1.setName("Khanh"); student1.setCode("abc"); Student student2 = new Student(); student2.setName("Khanh"); student2.setCode("bcd"); System.out.println(student1.equals(student2)); } } |
Kết quả:
Các bạn có thể loại bỏ một số field mà chúng ta muốn chúng không được include khi generate các phương thức toString(), equals() hay hashCode(). Để làm được điều này, các bạn cần khai báo thêm thuộc tính “exclude” trong các annotation @ToString và @EqualsAndHashCode.
Ví dụ như giờ mình muốn exclude field dateOfBirth trong class Student, mình sẽ khai báo như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package com.huongdanjava.lombok; import lombok.*; import java.util.Date; @Getter @Setter @NoArgsConstructor @AllArgsConstructor @ToString(exclude = "dateOfBirth") @EqualsAndHashCode(exclude = "dateOfBirth") public class Student { private String name; private transient String code; private Date dateOfBirth; public Student(String name) { this.name = name; } } |
Bây giờ, nếu các bạn kiểm tra thư mục /target/classes/com/huongdanjava/lombok, các bạn sẽ thấy class Student có nội dung như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.huongdanjava.lombok; import java.beans.ConstructorProperties; import java.util.Date; public class Student { private String name; private transient String code; private Date dateOfBirth; public Student(String name) { this.name = name; } public String getName() { return this.name; } public String getCode() { return this.code; } public Date getDateOfBirth() { return this.dateOfBirth; } public void setName(String name) { this.name = name; } public void setCode(String code) { this.code = code; } public void setDateOfBirth(Date dateOfBirth) { this.dateOfBirth = dateOfBirth; } public Student() { } @ConstructorProperties({"name", "code", "dateOfBirth"}) public Student(String name, String code, Date dateOfBirth) { this.name = name; this.code = code; this.dateOfBirth = dateOfBirth; } public String toString() { return "Student(name=" + this.getName() + ", code=" + this.getCode() + ")"; } public boolean equals(Object o) { if(o == this) { return true; } else if(!(o instanceof Student)) { return false; } else { Student other = (Student)o; if(!other.canEqual(this)) { return false; } else { Object this$name = this.getName(); Object other$name = other.getName(); if(this$name == null) { if(other$name != null) { return false; } } else if(!this$name.equals(other$name)) { return false; } return true; } } } protected boolean canEqual(Object other) { return other instanceof Student; } public int hashCode() { int PRIME = true; int result = 1; Object $name = this.getName(); int result = result * 59 + ($name == null?43:$name.hashCode()); return result; } } |