Lombok 라이브러리(이하 롬복)
는 어노테이션을 기반으로 반복되는 코드를 자동완성 해주는 라이브러리입니다. 클래스를 작성할 때 자주 작성하게되는 getter/setter, hashCode(), equals(), toString()
메소드들을 어노테이션을 통해 작성을 생략하고 컴파일 타임에 이들을 자동으로 생성해주는 기능을 제공하고 있습니다.
IntelliJ, Gradle 환경에서 실습합니다.
STS 이클립스의 경우에는 따로 설치 과정을 거쳐야하지만, 인텔리제이같은 경우에는 롬복이 기본 Plugin으로 설치되어서 제공되고 있기에 따로 설치 과정이 필요없습니다. 기본으로 제공될 정도라면 얼마나 이 롬복 라이브러리를 많이 사용하고 있는지 감이 오시나요?Plugins에서 롬복을 검색해보시면 이미 install 및 apply가 되어있음을 볼 수 있습니다. 만약 install이나 apply가 되어있지 않다면 설치 및 적용을 해주세요.
롬복을 사용하기 위해 Member라는 클래스를 하나 만들어줍니다. 그리고 아래와 같이 코드를 적으면 롬복의 어노테이션인 @Data
에 빨간 밑줄이 쳐지게 됩니다.
@Data
public class Member {
private String name;
private int age;
}
여기서 Add 'lombok' to classpath
를 선택하면 자동으로 롬복이 추가되게 됩니다.
그리고 IDE 메뉴에서 Setting -> Build, Execution, Deployment -> Comiler -> Annotation Processors의 Enable annotation processing
을 체크해줍니다.
gradle.build
의 dependencies
에 다음 내용도 추가해줍니다.
dependencies {
implementation 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
//테스트 환경용 롬복. 필요하다면 추가
testImplementation 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
}
이제 롬복을 사용할 준비가 완료되었으니 실습하면서 롬복이 어떤 기능을 가지고 있는지 확인해보겠습니다.
@Data
는 컴파일 과정에서 기본 생성자, getter/setter, hashCode(), equals(), toString()
을 추가해줍니다.
import lombok.Data;
@Data
public class Member {
private String name;
private int age;
}
public class LombokStudy {
public static void main(String[] args) {
Member member = new Member();
member.setName("lombok");
member.setAge(100);
System.out.println(member.getName() + " " + member.getAge());
System.out.println(member.toString());
}
}
위 코드처럼 작성하면 Member
는 분명 필드만 가지고 있는 객체인데 인스턴스화, getter/setter, toString()을 모두 이용할 수 있게 됩니다.
만약 롬복을 사용하지 않는 코드와 비교해보면 다음과 같습니다.
//롬복을 사용하지 않는 코드 public class Member { private String name; private int age; public Member(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } //롬복을 사용한 코드 import lombok.Data; @Data public class Member { private String name; private int age; }
롬복이 정말 간결하고 빠르게 코드를 작성하게 만들어 준다는 것이 느껴지시나요?
롬복이 반복되는 코드들을 줄여서 높은 효율의 생산성(간결한 코드)를 보장해주는 것은 큰 장점입니다.
하지만 간결하게 만들어주는 코드나 작성 기법들이 그렇듯이 오히려 가독성을 해치는 경우가 생기기도 하기에 대부분의 상황에서 롬복을 사용하는 것은 좋지만 100% 좋다라고는 할 수 없습니다.
롬복은 어노테이션 기반으로 작동하는 라이브러리이기 때문에 몇 가지 자주 사용되는 롬복 어노테이션을 소개해드리려고 합니다.
Annotation | 설명 |
---|---|
@NoArgsConstructor | 기본 생성자 생성(매개변수가 없는 생성자) |
@AllArgsConstructor | 모든 필드를 매개변수로 받는 생성자 생성 |
@RequiredArgsConstructor | 기본 생성자를 기반으로 필수 필드(final, @NonNull이 붙은 필드)를 매개변수로 받는 생성자 생성 |
@Getter, @Setter | getter/setter 메소드 자동 생성 |
@EqualsAndHashCode | equals(), hashCode() 메소드 자동 생성 |
@ToString | toString() 메소드 자동 생성 |
@Data | @RequiredArgsConstructor, @Getter, @Setter, @EqualsAndHashCode, @ToString 을 한 번에 사용할 수 있게 해주는 어노테이션 |
@Builder | 클래스에 Builder 추가 |
@Builder
는 따로 설명할 내용이 있어서 이후에 다른 포스트로 따로 다루려고 합니다.
위에서는 예시를 위해 @Data
어노테이션을 사용하긴 했지만, @Data
의 사용은 지양하는 것을 권장하고 있습니다.
@Data
를 사용하면 자동으로 생성된 setter
를 통해 객체에 무분별하게 접근하고 데이터를 변경할 수 있게 되어 객체의 안정성을 떨어뜨리게 됩니다. 누군가가 권한 없이 setter로 사용자 정보같은 것을 바꿔버리면 큰일나겠죠?
만약 setter를 사용해야하는 상황이라면 setXxxxx()
같은 메소드 이름 대신, 메소드 이름에 값을 왜 바꿔야하는지 명시하는 식으로 직접 작성하는 것이 권장된다고 합니다.
양방향 연관관계
는 두 객체가 서로를 참조하는 관계를 의미합니다. 양방향 연관관계를 가진 두 객체가 toString을 가지고 있다면, toString 호출 과정에서 객체1은 객체2를 부르고, 객체2는 다시 객체 1을 불러내면서 무한 반복에 빠지게 됩니다.
양방향 연관관계에서 toString을 사용할 때 이러한 현상을 막기 위해서는 @Data
대신 @ToString
의 exclude
를 이용해서 양방향 연관관계에서 제외시키면 됩니다.
@ToString(exclude="객체1")
public class 객체2 {}