Java Library - Lombok이란, Lombok 사용법, @Data, @Getter, @Builder, Lombok 장점, Lombok 단점
Java Library - Lombok이란? 프로젝트 롬복은 표준판 코드를 최소화하거나 제거하는 데 사용되는 인기 있고 널리 사용되는 자바 라이브러리입니다. 개발 시간과 노력을 절약해주며, annotation(어노테이션, @)을 사용하여 소스 코드 가독성을 증가시켜줍니다.
Lombok 뜻 롬복의 뜻은 인도네시아 서누사텡가라 지방에 있는 섬입니다. Java 프로그래밍언어가 인도네시아 섬 자바에 따온 만큼, 인도네시아 관련되어서 이름을 이렇게 지은거 같습니다. 이 섬의 위치는 아래와 같습니다. 서쪽으로는 롬복 해협이 발리에서, 동쪽으로는 숨바와 사이에 알라스 해협이 분리되면서 레서 순다 제도의 일부를 이룹니다.
Lombok 사용법 - Lombok 설치 Lombok 설치를 하기 위해서 gradle또는 maven을 활용할 수 있습니다. maven 사용시 pom.xml의 dependency에 아래 내용을 넣어줍니다.
1 2 3 4 5 6 7 8 <dependencies > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.24</version > <scope > provided</scope > </dependency > </dependencies >
gradle 사용시 build.gradle에 아래와 같이 dependency를 추가해줍니다.
1 2 3 4 5 6 7 8 9 10 11 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가 만들어 집니다. 예를 들어, 아래 코드를 고쳐보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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(어노테이션)을 사용하면 아래와 같이 작성할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Getter @Setter public class GetterSetterExample { private int age = 10 ; private String name; } 빌드타임에 age와 name에 대해 자동으로 생성이 됩니다. 아래와 같이 특정 필드에 대해서 사용도 가능합니다. ```java 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를 해줘봅시다.
1 2 3 4 5 6 7 @ToString public class ToStringExample { private String id = 12345 ; @ToString .Exclude private String name = "test" ; private Integer[] ids = {54321 , 54321 }; }
그러면 아래처럼 name은 생략되고, ToStringExample 클래스에 대한 필드값들을 쉽게 확인할 수 있도록 빌드시 toString() 함수가 생성되어집니다.
1 2 3 4 5 6 7 8 9 10 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은 아래와 같은 것들이 있습니다.
1 2 3 @NoArgsConstructor @AllArgsConstructor @RequiredArgsConstructor
@NoArgsConstructor 는 말그대로 파라미터가 없는 기본 생성자를 만들어줍니다.
1 2 3 4 @NoArgsConstructor public static class NoArgsExample { private String field; }
위와 같은 코드를 아래와 같이 컴파일해줍니다.
1 2 3 4 5 @NoArgsConstructor public static class NoArgsExample { public NoArgsExample () {} private String field; }
NoArgsConstructor annotation 을 쓸때와 아닐때의 코드수는 거의 비슷하다고 볼 수 있을거 같습니다.
다음으로, @AllArgsConstructor는 말 그대로 필드의 모든 파라미터를 사용한 생성자를 만드는 어노테이션입니다. 예를들어 아래와 같은 코드를 봅시다.
1 2 3 4 5 6 @AllArgsConstructor public class AllArgsConstructor { private String id ; private String name; private Integer[] ids ; }
위 코드는 아래와 같이 컴파일 됩니다. 필드수가 많을 수록 유용하게 쓸 수 있으며, POJO를 사용하는 spring framework 의 model 클래스 작성시 굉장히 편리하게 사용될 수 있습니다.
1 2 3 4 5 6 7 8 9 10 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로 받는 생성자를 만들어 냅니다.
예를 들어 아래 코드를 살펴봅시다.
id는 final 이 아니니, 포함되지 않습니다. username은 @NonNull이 있으므로 포함됩니다. status는 final이고 초기화되지 않았기에 포함됩니다. value 는 final이나, 초기화가 이미 되었기에 포함되지 않습니다. 1 2 3 4 5 6 7 8 @RequiredArgsConstructor public class RequiredArgsDemo1 { private Long id; @NonNull private String username; private final boolean status; private final boolean value = true ; }
따라서 위 코드는 아래와 같이 컴파일됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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입니다.
1 2 3 4 5 6 7 8 9 10 @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode @Data public class User2 { private Long id; private String username; }
는 아래 코드와 동일합니다.
1 2 3 4 5 6 7 8 @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode public class User2 { private Long id; private String username; }
lombok이 없다면 아래와 같이 무지막지하게 긴 코드를 작성해야합니다. 정말로 강력한 어노테이션이라 볼 수 있습니다.
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 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입니다.
1 2 3 4 5 @Builder public class BuilderExample { private String name; private int age; }
위 코드는 아래 코드와 같습니다. 코드수를 획기적으로 줄여 빌더패턴 코드를 만들어주게 됩니다.
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 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