1. @ToString : toString 메서드를 오버라이딩 해주는 애너테이션
<< @ToString 애너테이션 예시 >>
package jpaStudy;
import lombok.ToString;
@ToString
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
}
클래스 또는 멤버 변수 마다 @ToString 애너테이션을 사용할 수 있으며 클래스에 @ToString 애너테이션을 사용하면 모든 멤버 변수가 포함된 toString 메서드를 오버라이딩 함
위와 같이 클래스에 @ToString을 사용하면 아래와 같은 toString 메서드가 오버라이딩 됨
package jpaStudy;
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
public String toString() {
return "Member(idx=" + this.idx + ", name=" + this.name + ", tel=" + this.tel + ", age=" + this.age
+ ", height=" + this.height + ", bloodType=" + this.bloodType + ")";
}
}
멤버 변수 마다 @ToString 애너테이션을 사용한다면 방식이 살짝 달라짐
멤버 변수 마다 @ToString 애너테이션을 사용할 때는 아래와 같이 사용함
package jpaStudy;
import lombok.ToString;
@ToString
public class Member {
private int idx;
private String name;
private String tel;
@ToString.Exclude
private int age;
@ToString.Exclude
private double height;
@ToString.Exclude
private char bloodType;
}
우선 클래스에 @ToString 애너테이션을 사용하고 멤버 변수에는 @ToString.Exclude 애너테이션을 사용함
@ToString.Exclude 애너테이션은 생긴것처럼 제외 대상을 지정할 때 사용하는 애너테이션임
위와 같이 특정 멤버 변수에 @ToString.Exclude 애너테이션을 사용하면 해당 멤버 변수만 toString 메서드에서 빠짐
package jpaStudy;
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
public String toString() {
return "Member(idx=" + this.idx + ", name=" + this.name + ", tel=" + this.tel + ", height=" + this.height
+ ", bloodType=" + this.bloodType + ")";
}
}
속성 |
속성 명 | callSuper |
설명 | 상속 관계가 맺어져있을 때 자식 클래스에 붙이는 애너테이션으로 부모 클래스의 toString 메소드를 호출할 지 여부를 지정하는 속성 |
<< callSuper 속성 사용 예시 >>
아래와 같이 @ToString 애너테이션을 갖고 있는 두 클래스가 있음
package jpaStudy;
import lombok.ToString;
@ToString
public class Parent {
private int parentField;
}
package jpaStudy;
import lombok.ToString;
@ToString
public class Child extends Parent {
private int childField;
}
이런 상황에서 자식 클래스가 만들어지는 형태를 보면 아래와 같음
package jpaStudy;
public class Child extends Parent {
private int childField;
public String toString() {
return "Child(childField=" + this.childField + ")";
}
}
이때 자식 클래스의 ToString에서 부모 클래스의 ToString 호출 결과에 본인의 ToString 결과를 합쳐서 return 하고 싶은 경우 callSuper 속성을 사용할 수 있음
package jpaStudy;
import lombok.ToString;
@ToString(callSuper = true)
public class Child extends Parent {
private int childField;
}
이와 같을 때 만들어지는 자식 클래스는 아래와 같음
package jpaStudy;
public class Child extends Parent {
private int childField;
public String toString() {
return "Child(super=" + super.toString() + ", childField=" + this.childField + ")";
}
}
속성 명 | doNotUseGetters |
설명 | toString 메서드 내에서 멤버 변수에 접근할 때 this 로 접근할 지 getter 로 접근할 지 결정하는 속성 기본적으로 this 로 멤버 변수에 접근하며 이 속성의 값을 true로 지정하면 this 대신 getter 로 멤버 변수에 접근함 |
<< doNotUseGetters 속성 사용 예시 >>
package jpaStudy;
import lombok.ToString;
@ToString
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
}
위와 같은 Member 클래스는 아래와 같이 만들어질 것
package jpaStudy;
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
public String toString() {
return "Member(idx=" + this.idx + ", name=" + this.name + ", tel=" + this.tel + ", age=" + this.age
+ ", height=" + this.height + ", bloodType=" + this.bloodType + ")";
}
}
이때 멤버 변수에 접근할 때 this 가 아닌 getter 로 접근하고 싶다면 아래와 같이 doNotUseGetters 속성을 사용할 수 있음
단, 이 속성을 사용하려면 멤버 변수에 Getter 메서드가 필요함
package jpaStudy;
import lombok.Getter;
import lombok.ToString;
@ToString(doNotUseGetters = false)
@Getter
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
}
위와 같이 doNotUseGetters 속성을 사용하면 아래와 같이 toString 메서드가 만들어짐
package jpaStudy;
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
public String toString() {
return "Member(idx=" + this.getIdx() + ", name=" + this.getName() + ", tel=" + this.getTel() + ", age="
+ this.getAge() + ", height=" + this.getHeight() + ", bloodType=" + this.getBloodType() + ")";
}
// Getter
}
속성 명 | exclude |
설명 | toString 메서드에서 제외할 멤버 변수를 지정하는 속성 멤버 변수의 이름은 배열 형식으로 지정하며 위에서 알아본 @ToString.Exclude 와 같은 역할을 함 또한 롬복은 곧 이 속성을 Deprecated 할 예정이니 이 속성을 사용하지 말고 @ToString.Exclude 애너테이션을 사용할 것을 권장함 |
<< exclude 속성 예시 >>
package jpaStudy;
import lombok.ToString;
@ToString(exclude = {"idx", "name", "tel"})
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
}
위와 같이 toString 메서드에서 제외할 멤버 변수명을 하나 이상 지정할 수 있음
위와 같이 exclude 속성을 사용했을 때 만들어지는 클래스는 아래와 같음
package jpaStudy;
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
public String toString() {
return "Member(age=" + this.age + ", height=" + this.height + ", bloodType=" + this.bloodType + ")";
}
}
@ToString 애너테이션에 exclude 속성 대신 롬복에서 권장하는 방법인 멤버 변수에 @ToString.Exclude 를 사용하자
package jpaStudy;
import lombok.ToString;
@ToString
public class Member {
@ToString.Exclude
private int idx;
@ToString.Exclude
private String name;
@ToString.Exclude
private String tel;
private int age;
private double height;
private char bloodType;
}
속성 명 | includeFieldNames |
설명 | toString 메서드에서 멤버 변수의 이름을 포함할 지 여부를 지정하는 속성 |
<< includeFieldNames 속성 예시 >>
package jpaStudy;
import lombok.ToString;
@ToString
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
}
위와 같이 @ToString 애너테이션을 사용했을 때 어떤 클래스가 만들어질 지는 너무 잘 알고 있으니 따로 설명하진 않겠음
toString 메서드가 반환하는 문자열에서 멤버 변수 이름은 제외하고 싶다면 includeFieldNames 속성을 사용함
package jpaStudy;
import lombok.ToString;
@ToString(includeFieldNames = false)
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
}
위와 같이 includeFieldNames 속성을 사용했을 때 아래와 같이 클래스가 만들어짐
package jpaStudy;
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
public String toString() {
return "Member(" + this.idx + ", " + this.name + ", " + this.tel + ", " + this.age + ", " + this.height + ", "
+ this.bloodType + ")";
}
}
속성 명 | of |
설명 | toString 메서드에서 포함할 멤버 변수를 지정하는 속성 멤버 변수의 이름은 배열 형식으로 지정하며 이 속성 대신 멤버 변수에 @ToString.Include 애너테이션을 지정할 수 있음 또한 롬복은 곧 이 속성을 Deprecated 할 예정이니 이 속성을 사용하지 말고 @ToString.Include 애너테이션을 사용할 것을 권장함 |
<< of 속성 예시 >>
package jpaStudy;
import lombok.ToString;
@ToString(of = {"idx", "name", "age"})
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
}
위와 같이 of 속성을 사용해 toString이 반환할 멤버 변수를 지정할 수 있음
그러나 롬복이 권장하는 방법은 아님
of 속성과 동일한 역할을 하지만 롬복이 권장하는 방법은 아래와 같음
package jpaStudy;
import lombok.ToString;
@ToString(onlyExplicitlyIncluded = true)
public class Member {
@ToString.Include
private int idx;
@ToString.Include
private String name;
private String tel;
@ToString.Include
private int age;
private double height;
private char bloodType;
}
위와 같이 @ToString.Include 애너테이션을 사용하면 아래와 같이 클래스가 만들어짐
package jpaStudy;
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
public String toString() {
return "Member(idx=" + this.idx + ", name=" + this.name + ", age=" + this.age + ")";
}
}
여기서 onlyExplicitlyIncluded 속성은 밑에서 설명함
속성 명 | onlyExplicitlyIncluded |
설명 | @ToString.Exclude, @ToString.Include 애너테이션 적용 여부를 지정하는 속성 |
<< onlyExplicitlyIncluded 속성 사용 예시 >>
이 속성의 기본값은 false이며 이 속성의 값이 true이면 @ToString.Include 애너테이션이 동작하고 이 속성의 값이 false이면 @ToString.Exclude 애너테이션이 동작함
@ToString.Include 애너테이션을 사용하고 싶다면 반드시 클래스명 위에 @ToString(onlyExplicitlyIncluded = true) 애너테이션을 달아줘야함


@ToString.Exclude 애너테이션을 사용하고 싶다면 반드시 클래스명 위에 @ToString 또는 @ToString(onlyExplicitlyIncluded = false) 애너테이션을 달아줘야함
@ToString.Exclude 애너테이션의 선택지가 두 개( @ToString, @ToString(onlyExplicitlyIncluded = false) ) 인 이유는 onlyExplicitlyIncluded 속성의 기본값이 false이기 때문 즉 선택지 두 개가 같은 것

2. @EqualsAndHashCode : equals 메서드와 hashcode 메서드를 오버라이딩 해주는 애너테이션
<< @EqualsAndHashCode 애너테이션 예시 >>
package jpaStudy;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
}
위와 같이 @EqualsAndHashCode 애너테이션을 사용하면 아래와 같은 클래스가 만들어짐
package jpaStudy;
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Member)) {
return false;
} else {
Member other = (Member) o;
if (!other.canEqual(this)) {
return false;
} else if (this.idx != other.idx) {
return false;
} else if (this.age != other.age) {
return false;
} else if (Double.compare(this.height, other.height) != 0) {
return false;
} else if (this.bloodType != other.bloodType) {
return false;
} else {
Object this$name = this.name;
Object other$name = other.name;
if (this$name == null) {
if (other$name != null) {
return false;
}
} else if (!this$name.equals(other$name)) {
return false;
}
Object this$tel = this.tel;
Object other$tel = other.tel;
if (this$tel == null) {
if (other$tel != null) {
return false;
}
} else if (!this$tel.equals(other$tel)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof Member;
}
public int hashCode() {
int PRIME = true;
int result = 1;
int result = result * 59 + this.idx;
result = result * 59 + this.age;
long $height = Double.doubleToLongBits(this.height);
result = result * 59 + (int) ($height ^ $height >>> 32);
result = result * 59 + this.bloodType;
Object $name = this.name;
result = result * 59 + ($name == null ? 43 : $name.hashCode());
Object $tel = this.tel;
result = result * 59 + ($tel == null ? 43 : $tel.hashCode());
return result;
}
}
이 글을 읽는 분들은 이미 자바를 충분히 익혔을 것이므로 Equals 메서드와 hashCode 메서드에 대해서 따로 설명하진 않음
멤버 변수에 static 키워드가 붙으면 @EqualsAndHashCode 애너테이션은 어떻게 반응할까?
멤버 변수에 static, transient 키워드가 붙으면 @EqualsAndHashCode 애너테이션의 대상에서 빠짐
아래와 같이 간단하게 static, transient 키워드가 붙은 멤버 변수만 가지고 있는 클래스의 경우를 보자
package jpaStudy;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode
public class Member {
private static int idx;
private transient String name;
}
멤버 변수에 static, transient 키워드가 붙은 멤버 변수는 이 애너테이션의 대상에서 빠진다고 했으므로 위 Member 클래스는 아래와 같이 만들어짐
package jpaStudy;
public class Member {
private static int idx;
private transient String name;
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Member)) {
return false;
} else {
Member other = (Member) o;
return other.canEqual(this);
}
}
protected boolean canEqual(Object other) {
return other instanceof Member;
}
public int hashCode() {
int result = true;
return 1;
}
}
equals 메서드에서는 멤버 변수에 대한 비교는 빠지고 인스턴스 자체만 비교하는 코드가 생성됨
hashCode 메서드에서는 멤버 변수에 대한 해시화가 빠져 1만 return 함을 알 수 있음
transient 키워드에 대한 자세한 설명은 아래 블로그를 참고하자
https://nesoy.github.io/articles/2018-06/Java-transient
속성 |
속성 명 | cacheStrategy |
설명 | 이 인스턴스의 해시값을 기억할지 여부를 지정하는 속성 해시값은 인스턴스의 고유한 값이므로 인스턴스 내 멤버 변수의 값이 변하지 않는다면 hashcode 메서드는 항상 같 은 값을 반환할 것 이러한 점을 활용할 수 있도록 hashcode 메서드를 처음 호출했을 때 계산한 해시값을 기억해두고 hashcode 메서드를 두번째 호출하는 시점부터는 기억해둔 해시값을 반환함 이 속성에 대해서 자세히 알아보기 전에는 메모이제이션 역할이라고 생각했으나 메모이제이션이 아닌 속성명 그대로 이 속성은 캐싱 역할임 |
<< cacheStrategy 속성 예시 >>
아래와 같이 cacheStrategy 속성을 사용한 클래스를 보자
package jpaStudy;
import lombok.EqualsAndHashCode;
import lombok.EqualsAndHashCode.CacheStrategy;
@EqualsAndHashCode(cacheStrategy = CacheStrategy.LAZY)
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
}
cacheStrategy 속성을 사용했을 경우 hashcode 메서드는 아래와 같이 만들어짐
package jpaStudy;
public class Member {
private transient int $hashCodeCache;
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
// equals 메서드 생략
public int hashCode() {
if (this.$hashCodeCache != 0) {
return this.$hashCodeCache;
} else {
int PRIME = true;
int result = 1;
int result = result * 59 + this.idx;
result = result * 59 + this.age;
long $height = Double.doubleToLongBits(this.height);
result = result * 59 + (int) ($height ^ $height >>> 32);
result = result * 59 + this.bloodType;
Object $name = this.name;
result = result * 59 + ($name == null ? 43 : $name.hashCode());
Object $tel = this.tel;
result = result * 59 + ($tel == null ? 43 : $tel.hashCode());
if (result == 0) {
result = Integer.MIN_VALUE;
}
this.$hashCodeCache = result;
return result;
}
}
}
여기서 멤버 변수의 변화에 주목해야함
처음 계산한 해시값을 기억하기 위해 $hashCodeCache 멤버 변수가 추가됬음
그리고 hashcode 메서드를 처음 호출할 때만 이 인스턴스의 해시값을 비교하고 두 번째 호출부터는 계산해둔 해시값을 반환함
즉, 처음 hashcode 메서드를 호출했을 때와 그 이후 hashcode 메서드를 호출했을 때 멤버 변수의 값이 바뀌면 hashcode 메서드는 잘못된 해시값을 반환함
속성 명 | onParam |
설명 | equals 메서드에 애너테이션을 붙이고 싶을 때 사용하는 속성 생성자와 관련된 롬복 애너테이션에서 onConstructor 속성과 같은 역할을 하는 속성 ( onConstructor 속성에 대해서 모른다면 https://codingaja.tistory.com/135 이 글 참고 ) |
<< onParam 속성 예시 >>
package jpaStudy;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
@EqualsAndHashCode(onParam=@__({@NonNull}))
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
}
위와 같이 equals 메서드에 특정 애너테이션을 달 수 있음
위와 같은 경우 아래와 같이 클래스가 만들어짐
package jpaStudy;
import lombok.NonNull;
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
public boolean equals(@NonNull Object o) {
// 생략
}
// canEquals 메서드 생략
// hashCode 메서드 생략
}
속성 명 | callSuper |
설명 | 상속 관계가 맺어져있을 때 자식 클래스에 붙이는 애너테이션으로 부모 클래스의 equals 메소드와 hashcode 메서드를 호출할 지 여부를 지정하는 속성 |
속성 명 | doNotUseGetters |
설명 | equals 메서드와 hashcode 메서드 내에서 멤버 변수에 접근할 때 this 로 접근할 지 getter 로 접근할 지 결정하는 속성 위에서 알아본 @ToString 애너테이션의 doNotUseGetters 속성과 같음 |
속성 명 | exclude |
설명 | equals 메서드와 hashcode 메서드에서 제외할 멤버 변수를 지정하는 속성 위에서 알아본 @ToString 애너테이션의 exclude 속성과 같음 |
속성 명 | of |
설명 | equals 메서드와 hashcode 메서드에 포함할 멤버 변수를 지정하는 속성 멤버 변수의 이름은 배열 형식으로 지정하며 이 속성 대신 멤버 변수에 @EqualsAndHashCode.Include 애너테이션을 지정할 수 있음 또한 롬복은 곧 이 속성을 Deprecated 할 예정이니 이 속성을 사용하지 말고 @EqualsAndHashCode.Include 애너테이션을 사용할 것을 권장함 위에서 알아본 @ToString 애너테이션의 of 속성과 같음 |
속성 명 | onlyExplicitlyIncluded |
설명 | @EqualsAndHashCode.Exclude, @EqualsAndHashCode.Include 애너테이션 적용 여부를 지정하는 속성 위에서 알아본 @ToString 애너테이션의 onlyExplicitlyIncluded 속성과 같음 |
5. @With : 불변 ( Immuable ) 객체를 만들 때 사용하는 애너테이션으로 Setter와 비슷하지만 완전히 다른 동작을 하는 with 메서드를 생성해주는 애너테이션
Setter 는 해당 객체의 멤버 변수 값을 바꿔주기만 하기 때문에 Setter 메서드의 반환 타입은 void 임
with 메서드는 해당 객체가 가지고 있는 멤버 변수의 값에 with로 지정한 멤버 변수의 값을 바꾼 새로운 객체를 반환하는 메서드임
따라서 with 메서드의 반환 타입은 클래스임
<< @With 애너테이션 예시 >>
우선 @With 애너테이션을 사용하려면 모든 멤버 변수를 초기화할 수 있는 생성자가 필요함
package jpaStudy;
import lombok.AllArgsConstructor;
import lombok.With;
@AllArgsConstructor
@With
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
}
위와 같이 @With 애너테이션은 모든 멤버 변수를 초기화하는 @AllArgsConstructor 애너테이션과 함께 사용하며 @With 애너테이션을 사용한 클래스는 아래와 같이 만들어짐
package jpaStudy;
public class Member {
private int idx;
private String name;
private String tel;
private int age;
private double height;
private char bloodType;
public Member(int idx, String name, String tel, int age, double height, char bloodType) {
this.idx = idx;
this.name = name;
this.tel = tel;
this.age = age;
this.height = height;
this.bloodType = bloodType;
}
public Member withIdx(int idx) {
return this.idx == idx ? this : new Member(idx, this.name, this.tel, this.age, this.height, this.bloodType);
}
public Member withName(String name) {
return this.name == name ? this : new Member(this.idx, name, this.tel, this.age, this.height, this.bloodType);
}
public Member withTel(String tel) {
return this.tel == tel ? this : new Member(this.idx, this.name, tel, this.age, this.height, this.bloodType);
}
public Member withAge(int age) {
return this.age == age ? this : new Member(this.idx, this.name, this.tel, age, this.height, this.bloodType);
}
public Member withHeight(double height) {
return this.height == height
? this
: new Member(this.idx, this.name, this.tel, this.age, height, this.bloodType);
}
public Member withBloodType(char bloodType) {
return this.bloodType == bloodType
? this
: new Member(this.idx, this.name, this.tel, this.age, this.height, bloodType);
}
}
각 멤버 변수 이름에 맞는 with 메서드가 생성되며 with 메서드가 반환하는 값은 전달 받은 값을 갖고 있는 새로운 객체임
이렇게 불변 객체를 만들고 싶을 때 간단하게 @With 애너테이션을 사용할 수 있음
@With 애너테이션은 위와 같이 클래스에 붙여서 해당 클래스가 갖고 있는 모든 멤버 변수에 맞는 with 메서드를 생성할 수도 있지만 멤버 변수에 @With 애너테이션을 붙여 특정 멤버 변수만 with 메서드가 생성되도록 할 수 있음
package jpaStudy;
import lombok.AllArgsConstructor;
import lombok.With;
@AllArgsConstructor
public class Member {
@With
private int idx;
private String name;
@With
private String tel;
private int age;
private double height;
private char bloodType;
}
참고
- https://mangkyu.tistory.com/131
- https://tecoble.techcourse.co.kr/post/2021-04-26-defensive-copy-vs-unmodifiable/
속성 |
속성 명 | onMethod |
설명 | with 메서드에 애너테이션을 추가하고 싶을 때 사용하는 속성 생성자 관련된 애너테이션의 onConstructor 속성과 같은 역할을 하는 속성 |
속성 명 | onParam |
설명 | with 메서드의 파라미터에 애너테이션을 추가하고 싶을 때 사용하는 속성 @Setter 애너테이션의 onParam 속성과 같은 역할을 하는 속성 |
속성 명 | value |
설명 | with 메서드에 접근 제어자를 지정하는 속성 @Getter, @Setter 애너테이션의 value 속성과 같은 역할을 하는 속성 |
'기타' 카테고리의 다른 글
롬복 사용 / 자주 사용하는 롬복 애너테이션 정리 (Lombok Annotation ) - 메서드 관련 애너테이션 (1) / Getter, Setter (5) | 2023.06.17 |
---|---|
롬복 사용 / 자주 사용하는 롬복 애너테이션 정리 (Lombok Annotation ) - 생성자 관련 애너테이션 (0) | 2023.06.15 |
이클립스 디컴파일러 설치하기 ( Eclipse Decompiler ) (1) | 2023.06.14 |
롬복 ( Lombok ) 이란? / 롬복 설치 및 적용 (0) | 2023.06.14 |
Eclipse에서 Gradle로 자바 프로젝트 생성하기 (0) | 2023.06.13 |