티스토리 뷰

 

Lombok(롬복) 이란?

Lombok 은 자바의 Annotation processsor 라는 기능을 이용하여 컴파일 시점에 Lombok의 어노테이션을 읽어서, 다양한 메서드와 생성자를 자동으로 생성해 주는 라이브러리이다. (Getter, Setter, Equals, ToString 등과 같은 코드를 자동완성 해준다.)

 

쉽게 얘기하여, 개발자가 해야하는 기본적이고 반복적인 작업들을 정해진 위치에 @(어노테이션)만 붙여주면 Lombok 이 이런 일들을 대신 해주는 것이다.

 

이렇게 설명해도 정확이 와닿지 않을 수 있으니 아래에 글을 통해 쉽게 이해할 수 있도록 정리를 하였다.

 

Lombok 기능에 대해 정리하기 전에 Lombok 을 설치 및 적용하는 방법에 대해 알아보자.

 


 

 

IntelliJ(인텔리제이) Lombok 설치 및 적용 방법

 

1-1. 인텔리제이의 build.gradle의 dependency에 아래와 같이 코드를 추가해준다.

dependencies {
    // lombok 라이브러리
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    
    // lombok 테스트 라이브러리
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
}

 

lombok 테스트 라이브러리는 테스트 코드를 작성할 때, 테스트에서 lombok을 사용할 수 있게 해준다.

 

 

1-2. build.gradle의 configurations에 아래와 같이 코드를 추가해준다.

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

 

나는 스프링 부트(3.2버전)를 통해 프로젝트를 생성해서 기본적으로 configrations가 추가가 되어 있었다.

 

귀여운 코끼리

 

(중요)코드를 추가하고 난 이후 오른쪽 상단에 뜨는 귀여운 코끼리를 눌러서 적용해준다. 

 

 

2. Lombok 플러그인 설치

 

Settings -> plugin 검색 후 lombok 을 검색하여 플러그인을 설치한다.

 

 

3. Annotaion Processiong 설정

Setting -> annotation processors 검색 후, 맨 위에 Enable annotation processing 활성화 후 적용

 

이렇게까지 하면 모든 lombok 설치 및 적용이 완료된다.

 

다음은 Lombok의 자주 사용하는 어노테이션(@, Annotation) 을 알아보도록 하자.

 


 

Lombok 에서 자주 사용하는 어노테이션(@, Annotation)

 

@Getter

@Getter 어노테이션이 붙은 클래스 내 모든 필드의 Getter 메서드를 자동으로 생성 해준다.

class LombokAnnotationClass {
    String name;

    public String getName() {
        return name;
    }
}
@Getter
class LombokAnnotationClass {
    String name;
    
}

 

 

 

@Setter 

@Setter 어노테이션이 붙은 클래스 내 모든 필드의 Setter 메서드를 자동으로 생성 해준다.

class LombokAnnotationClass {
    String name;

    public void setName(String name) {
        this.name = name;
    }
}

 

@Getter 와 @Setter 는 클래스 이름 위에 적용시키면 모든 변수들에 적용이 가능하며, 변수 이름 위에 적용시킬 경우 해당 변수들에서만 적용이 가능하다.

 

 

 

@ToString 

@ToString 어노테이션을 사용하면 이름 그대로 toString() 을 자동으로 생성 해준다.

기존에는 아래 코드처음 개발자가 직접 toString()을 직접 생성해 주어야 한다.

class LombokAnnotationClass {

    String name;	

    @Override
    public String toString() {
        return "Test{" +
                "name='" + name + '\'' +
                '}';
    }
}

 

 

 

@RequiredArgsConstructor

@RequiredArgsConstructor 어노테이션은 final 또는 @NonNull 키워드가 붙은 필드에 대해서 생성자를 자동으로 만들어준다.

class LombokAnnotationClass {
    private final String name;
	
    // @RequiredArgsConstructor 어노테이션 사용 시 생략 가능
    public LombokAnnotationClass(String name) {
    	this.name = name;
    }
}

 

final 혹은 @NonNull 키워드가 붙은 필드가 세 개라면 세 개의 필드값을 받는 생성자를 만들어 준다.

class LombokAnnotationClass {
    private final String name;
    private final int age;
    private final String sex
	
    // @RequiredArgsConstructor 어노테이션 사용 시 생략 가능
    public LombokAnnotationClass(String name, int age, String sex) {
    	this.name = name;
        this.age = age;
        this.sex = sex;
    }
}

 

위 코드는 아래와 같이 어노테이션을 사용하여 생략이 가능하다.

@RequiredArgsConstructor
class LombokAnnotationClass {
    private final String name;
    private final int age;
    private final String sex;

}

 

작성한 코드에는 안보이지만 lombok 에서 알아서 만들어 주었다.

 

실제로 인텔리제이에서 해당 코드를 빌드 후 build/classes/java/main 에 들어가보면 생성자가 생성되어 있는 것을 확인할 수 있다. 궁금하면 확인해 보자.

 

@RequiredArgsConstructor 같은 경우에는 스프링에서 의존성 주입(Dependancy Injection, DI)을 해줄 때 자주 사용하는 어노테이션이다. 

DI 는 주로 생성자에서 많이 이루어지는 데, 반복적으로 모든 클래스에 생성자를 만들고 외부 객체들을 주입하는 코드를 개발자가 하나하나 작성해야하는 수고스러움이 있다. 

이런 반복적인 작업들을 Lombok을 이용하여 코드를 깔끔하게 작성할 수 있다.

 

그리고 다음 예제에서부터는 After 코드는 작성하지 않도록 하겠다. (그냥 생략해주면 되기 때문)

 

 

@EqualsAndHashCode

이름 그대로 equals(), hashCode() 메소드를 생성해주는 어노테이션이다.

아래의 코드를 Lombok이 자동으로 생성 해준다.

 

혹시나, class LombokAnnotationClass { String name; }

이 부분도 자동으로 생성해준다고 생각하는 사람은 없겠지..?

class LombokAnnotationClass {
    String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Test test = (Test) o;
        return Objects.equals(name, test.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

 

여기에서 equals() 는 이름 그대로 2개의 값이 같은 값인지 비교하는 메소드다.

== 와 헷갈릴 수 있는 데, == 은 주소 값을 비교하는 연산자이고, equals()는 값 자체를 비교하는 것이다.

 

public class LombokAnnotationClass {
    public static void main(String[] args) {
        String name1 = "baek";
        String name2 = "baek";

        System.out.println("name1 == name2 : " + name1 == name2);  //false 
        System.out.println("name1.equals(name2) : " + name1.equals(name2)); //true
    }
}

 

대충 요런 느낌? 그래서 둘 다 값이 동일한지 비교하는 기능이지만 다른 결과를 출력한다.

 

hashCode() 에서 hashcode 라는 것은 객체를 식별하는 정수값이고, hashCode()는 이 값을 return 하는 메서드이다.

2개의 객체가 같은 객체인지 판별할 때 사용하는 메서드이다.

 

 

@Data

@Data 어노테이션을 사용하면 위에서 설명한 5개의 어노테이션을 한번에 설정해준다.

(@Getter, @Setter, @RequiredArgsConstructor, @ToString, @EqualsAndHashCode)

 

 

@NoArgsConstructor

@NoArgsConstructor 는 어떠한 변수도 사용하지 않는 기본 생성자를 자동으로 생성해준다.

 

 

@AllArgsConstructor

모든 필드에 대해서 생성자를 자동으로 생성해준다.

 

 

@Builder

@Builder 어노테이션을 사용하면 해당 클래스의 객체의 생성에 Builder 패턴을 적용시켜준다.

모든 변수들에 대해 build 하기를 원하면 클래스 위에 @Builder를 붙이면 되지만, 특정 변수만을 build 하기 원한다면 생성자를 작성하고 그 위에 @Builder 를 붙여주면 된다.

 

생성자 파라미터가 적다면 상관없지만, 생성자 파라미터로 받아야하는 값이 많아진다면 각 값들이 어떤 값을 의미하는 지 힘들어진다.

이를 빌더 패턴으로 구현한다면 각 값들은 빌더의 각 값들의 이름이 어떤 값으로 셋팅이 되는지, 각각 무슨 값을 의미하는지 파악하기가 쉬워진다. 

따라서 생성자로 설정해야하는 값이 많을 경우 빌더를 쓰는 것이 생성자보다 가독성이 좋다.

(나도 포스팅을 정리하면 처음 사용해보는 어노테이션이라 이해도가 낮다)

//@Builder //모든 변수를 초기화 하는 builder 생성 시 클래스 레벨에 선언
@Getter // 아래의 코드에서 출력을 확인하기 위해 사용
class LombokAnnotationClass {
    private String name;
    private int age;
    private String sex;
    
    @Builder // 특정 변수만을 초기화 하려면 특정 생성자에 선언
    public LombokAnnotationClass(String name, int age) {
    	this.name = name;
        this.age = age;
}

 

@Builder 를 선언하면 아래의 코드가 자동으로 생성된다.

public class LombokAnnotationClass {
    private String name;
    private int age;
    private String sex;

    public LombokAnnotationClass(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static LombokAnnotationClassBuilder builder() {
        return new LombokAnnotationClassBuilder();
    }
    
     public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }

    public String getSex() {
        return this.sex;
    }

    public static class LombokAnnotationClassBuilder {
        private String name;
        private int age;

        LombokAnnotationClassBuilder() {
        }

        public LombokAnnotationClassBuilder name(final String name) {
            this.name = name;
            return this;
        }

        public LombokAnnotationClassBuilder age(final int age) {
            this.age = age;
            return this;
        }

        public LombokAnnotationClass build() {
            return new LombokAnnotationClass(this.name, this.age);
        }

        public String toString() {
            return "LombokAnnotationClass.LombokAnnotationClassBuild(name=" + this.name + ", age=" + this.age + ")";
        }
    }
}

 

빌더를 생성하고 아래와 같이 사용하면 된다.

public class AnnotationController {

    public static void main(String[] args) {
    
    	// 빌더 패턴을 이용한 객체 생성
        LombokAnnotationClass lc = LombokAnnotationClass.builder()
            .name("어노테이션")
            .age(10)
            .build();
        System.out.println(lc.getName());
        System.out.println(lc.getAge());
    }
}

// 출력결과
// 어노테이션
// 10

 


 

Lombok 사용 시 주의사항

Lombok이 많은 기능들을 편리하게 제공해주는 장점이 있지만, 그렇기 때문에 개발자가 의도하지 않은 동작들이 일어날 수 있다.

그래서 개발자는 Lombok을 사용할 때 주의해서 사용해야 한다. 

(보통 @Getter, @Setter, @RequiredArgsConstructor 정도만 자주 사용한다.)

 

주의사항들 및 잘못 사용할 경우에 어떤 이슈가 있는지는 따로 정리해서 포스팅을 할 예정이다.