Java Library - Lombok이란, Lombok 사용법, @Data, @Getter, @Builder, Lombok 장점, Lombok 단점
Java Library - Lombok이란?
프로젝트 롬복은 표준판 코드를 최소화하거나 제거하는 데 사용되는 인기 있고 널리 사용되는 자바 라이브러리입니다.
개발 시간과 노력을 절약해주며,
annotation(어노테이션, @)을 사용하여 소스 코드 가독성을 증가시켜줍니다.
Lombok 뜻
롬복의 뜻은 인도네시아 서누사텡가라 지방에 있는 섬입니다.
Java 프로그래밍언어가 인도네시아 섬 자바에 따온 만큼, 인도네시아 관련되어서 이름을 이렇게 지은거 같습니다.
이 섬의 위치는 아래와 같습니다.
서쪽으로는 롬복 해협이 발리에서, 동쪽으로는 숨바와 사이에 알라스 해협이 분리되면서 레서 순다 제도의 일부를 이룹니다.
Lombok 사용법 - Lombok 설치
Lombok 설치를 하기 위해서 gradle또는 maven을 활용할 수 있습니다.
maven 사용시 pom.xml의 dependency에 아래 내용을 넣어줍니다.
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
</dependencies>
참고로 제 프로젝트상에서는 아래 스크린샷과 같습니다.
[그림]
gradle 사용시 build.gradle에 아래와 같이 dependency를 추가해줍니다.
repositories {
mavenCentral()
}
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
testCompileOnly 'org.projectlombok:lombok:1.18.24'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.24'
}
lombok에 대한 각 버전별 artifact는 아래 주소에서 확인 및 다운로드 받을 수 있습니다.
https://mvnrepository.com/artifact/org.projectlombok/lombok
Lombok 사용법 - @Getter, @Setter
일반적인 클래스를 만들때, 클래스명 상단에 @Getter와 @Setter를 사용하면
빌드타임에 getter와 setter가 만들어 집니다.
예를 들어, 아래 코드를 고쳐보겠습니다.
public class GetterSetterExample {
private int age = 10;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
protected void setName(String name) {
this.name = name;
}
}
위 코드를 Lombok 의 Getter, Setter annotation(어노테이션)을 사용하면 아래와 같이 작성할 수 있습니다.
@Getter
@Setter
public class GetterSetterExample {
private int age = 10;
private String name;
}
빌드타임에 age와 name에 대해 자동으로 생성이 됩니다.
아래와 같이 특정 필드에 대해서 사용도 가능합니다.
public class GetterSetterExample {
@Getter
private int age = 10;
private String name;
}
이처럼 Lombok은 annotation(@)을 사용하여 코드를 짧게 작성하도록 도와주어
가독성을 향상시키도록 해주는 역할을 합니다.
Lombok의 주요 annotation을 좀 더 살펴보겠습니다.
Lombok 사용법 - @ToString()
@ToString을 사용하면 toString() 메소드를 생성하는데 도움을 줍니다.
디버깅시 각각의 필드값을 쉽게 확인할 수 있도록 도움을 줍니다.
또한, 클래스 안의 필드에 @ToString.Exclude를 사용하면 toString()에 제외할 인자를 설정할 수 있습니다.
예를 들어 아래 코드와 같이 class에 @ToString 어노테이션을 써주고,
name에는 ToString.Exclude를 해줘봅시다.
@ToString
public class ToStringExample {
private String id = 12345;
@ToString.Exclude
private String name = "test";
private Integer[] ids = {54321, 54321};
}
그러면 아래처럼 name은 생략되고,
ToStringExample 클래스에 대한 필드값들을 쉽게 확인할 수 있도록
빌드시 toString() 함수가 생성되어집니다.
public class ToStringExample {
private String id = 12345;
@ToString.Exclude
private String name = "test";
private Integer[] ids = {54321, 54321};
public String toString(){
return "ToStringExample(id=12345, ids=[54321, 54321])";
}
}
Lombok 사용법 - 생성자 관련
생성자 관련된 Lombok의 annotation은 아래와 같은 것들이 있습니다.
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
@NoArgsConstructor 는 말그대로 파라미터가 없는 기본 생성자를 만들어줍니다.
@NoArgsConstructor
public static class NoArgsExample {
private String field;
}
위와 같은 코드를 아래와 같이 컴파일해줍니다.
@NoArgsConstructor
public static class NoArgsExample {
public NoArgsExample(){}
private String field;
}
NoArgsConstructor annotation 을 쓸때와 아닐때의 코드수는 거의 비슷하다고 볼 수 있을거 같습니다.
다음으로, @AllArgsConstructor는 말 그대로 필드의 모든 파라미터를 사용한 생성자를 만드는 어노테이션입니다.
예를들어 아래와 같은 코드를 봅시다.
@AllArgsConstructor
public class AllArgsConstructor {
private String id ;
private String name;
private Integer[] ids ;
}
위 코드는 아래와 같이 컴파일 됩니다.
필드수가 많을 수록 유용하게 쓸 수 있으며,
POJO를 사용하는 spring framework 의 model 클래스 작성시 굉장히 편리하게 사용될 수 있습니다.
public class AllArgsConstructor {
public AllArgsConstructor(String id, String name, Integer[] ids){
this.id = id;
this.name = name;
this.ids = ids;
}
private String id ;
private String name;
private Integer[] ids ;
}
@RequiredArgsConstructor 의 경우는 @NonNull 로 되어있는 필드나,
초기화가 안된 final 필드에 대한 parameter로 받는 생성자를 만들어 냅니다.
예를 들어 아래 코드를 살펴봅시다.
1) id는 final 이 아니니, 포함되지 않습니다.
2) username은 @NonNull이 있으므로 포함됩니다.
3) status는 final이고 초기화되지 않았기에 포함됩니다.
4) value 는 final이나, 초기화가 이미 되었기에 포함되지 않습니다.
@RequiredArgsConstructor
public class RequiredArgsDemo1 {
private Long id;
@NonNull
private String username;
private final boolean status;
private final boolean value = true;
}
따라서 위 코드는 아래와 같이 컴파일됩니다.
public class RequiredArgsDemo1 {
private Long id;
@NonNull
private String username;
private final boolean status;
private final boolean value = true;
public RequiredArgsDemo1(
@NonNull final String username,
final boolean status
) {
this.username = username;
this.status = status;
}
}
Lombok 사용법 - @Data
@Data는 아래 lombok의 annotation들을 한꺼번에 적용시키는 annotation입니다.
@Getter
@Setter
@RequiredArgsConstructor
@ToString
@EqualsAndHashCode
@Data
public class User2 {
private Long id;
private String username;
}
는 아래 코드와 동일합니다.
@Getter @Setter
@RequiredArgsConstructor
@ToString
@EqualsAndHashCode
public class User2 {
private Long id;
private String username;
}
lombok이 없다면 아래와 같이 무지막지하게 긴 코드를 작성해야합니다.
정말로 강력한 어노테이션이라 볼 수 있습니다.
public class User2 {
private Long id;
private String username;
public User2() {
}
public Long getId() {
return this.id;
}
public String getUsername() {
return this.username;
}
public void setId(final Long id) {
this.id = id;
}
public void setUsername(final String username) {
this.username = username;
}
@Override
public boolean equals(final Object o) {
if (o == this)
return true;
if (!(o instanceof User2))
return false;
final User2 other = (User2) o;
if (!other.canEqual((Object) this))
return false;
final Object this$id = this.getId();
final Object other$id = other.getId();
if (this$id == null ? other$id != null : !this$id.equals(other$id))
return false;
final Object this$username = this.getUsername();
final Object other$username = other.getUsername();
if (this$username == null ? other$username != null : !this$username.equals(other$username))
return false;
return true;
}
protected boolean canEqual(final Object other) {
return other instanceof User2;
}
@Override
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $id = this.getId();
result = result * PRIME + ($id == null ? 43 : $id.hashCode());
final Object $username = this.getUsername();
result = result * PRIME + ($username == null ? 43 : $username.hashCode());
return result;
}
@Override
public String toString() {
return "User2(id=" + this.getId() + ", username=" + this.getUsername() + ")";
}
}
Lombok 사용법 - @Builder
@Builder는 클래스에 빌더 패턴을 적용할 수 있게 해주는 annotation입니다.
@Builder
public class BuilderExample {
private String name;
private int age;
}
위 코드는 아래 코드와 같습니다.
코드수를 획기적으로 줄여 빌더패턴 코드를 만들어주게 됩니다.
public class BuilderExample {
private String name;
private int age;
BuilderExample(String name, int age) {
this.name = name;
this.age = age;
this.occupations = occupations;
}
public static BuilderExampleBuilder builder() {
return new BuilderExampleBuilder();
}
public static class BuilderExampleBuilder {
private String name;
private int age;
BuilderExampleBuilder() {
}
public BuilderExampleBuilder name(String name) {
this.name = name;
return this;
}
public BuilderExampleBuilder age(int age) {
this.age = age;
return this;
}
public BuilderExample build() {
return new BuilderExample(name, age);
}
@java.lang.Override
public String toString() {
return "BuilderExample.BuilderExampleBuilder("name = " + this.name + ", age = " + this.age + ")";
}
}
}
총평
이제까지 lombok을 쓰면 얼마나 코드를 생산성있게 짧게 작성할 수 있는지 확인할 수 있었습니다.
하지만 lombok에 대한 단점도 있습니다.
예를 들어 개발자가 원하지 않는 의도를 행하도록 하는 부분이 있을 수 있습니다.
@Builder 에서는 초기화하고 싶지 않은 필드가 null로 초기화 되는 경우가 있고,
@toString에서는 두 클래스가 서로 참조할 때 순환참조하여 stackoverflow가 나타나는 경우가 있으며,
@toString을 포함하는 @Data에서도 순환참조 문제가 발생하는 등 여러 문제점이 발생할 수 있습니다.
따라서 lombok을 사용할 때는 각 어노테이션이 생성하는 코드를 확실히 이해하고 사용하는것이 좋습니다.
개인적으로는 @Getter, @Setter, @AllArgsConstructor 정도로만 사용하면 협업시에도
다른 개발자들이 잘 헷갈리지 않고 좋은 코드를 만들어 낼 수 있지 않을까 싶습니다.
기회가 된다면 lombok 사용시 side effect에 대해서도 상세히 다뤄볼 수 있도록 하겠습니다.
#롬복,#java,#lombok,#@Data,#@AllArgsConstructor,#@Getter,#@Setter,#@ToString,#@NoArgsConstructor,#@RequiredArgsConstructor
댓글