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 속성과 같은 역할을 하는 속성
728x90
LIST