Lombok 어노테이션 사용법

·2023년 7월 16일
0

프로젝트 공부

목록 보기
17/33

Lombok이란?

Lombok은 자바 컴파일 시점에서 특정 어노테이션으로 해당 코드를 추가할 수 있는 라이브러리

1. @Data 사용 지양

@Data 는 @ToString, @EqualsAndHashCode, @Getter, @Setter, @RequiredArgsConstructor을 모두 포함하는 강력한 어노테이션이다

발생 가능한 문제

1. 무분별한 Setter 남용

Setter는 그 의도가 분명하지 않고 객체를 언제든지 변경할 수 있는 상태가 되어서 객체의 안전성이 보장받기 힘들다.

불필요한 변경 포인트를 제공하지 않음으로써 안정성을 취할 수 있다.

2. @ToString : 양방향 연관관계 시 순환 참조

@ToString : 클래스 인스턴스의 데이터를 문자열로 반환하는 메서드

Member 와 Coupon 이 1:N 양방향으로 매핑되어 있는 상황을 가정할 수 있다.

이때, ToString을 호출하면 무한 순환 참조가 발생한다.

이러한 문제를 해결하기 위해서는 @ToString(exclude = "coupons") 처럼 어노테이션을 사용해서 특정 항목을 제외시키는 방법을 사용할 수 있다.

3. @EqualsAndHashCode

@EqualsAndHashCode는 상당히 고품질의 euqals()와 hashCode() 메소드를 만들어준다. 따라서 잘 사용하면 좋지만, 남발하면 심각한 문제가 생긴다.

특히 문제가 되는 점은 Mutable 객체에 아무런 파라미터 없이 그냥 사용하는 경우이다.

@EqualsAndHashCode
public static class Order {
    private Long orderId;
    private long orderPrice;
    private long cancelPrice;
    public Order(Long orderId, long orderPrice, long cancelPrice) {
        this.orderId = orderId;
        this.orderPrice = orderPrice;
        this.cancelPrice = cancelPrice;
    }
}
Order order = new Order(1000L, 19800L, 0L);
Set<Order> orders = new HashSet<>();
orders.add(order); // Set에 객체 추가
System.out.println("변경전 : " + orders.contains(order)); // true
order.setCancelPrice(5000L); // cancelPrice 값 변경
System.out.println("변경후 : " + orders.contains(order)); // false

위와 같이 동일한 객체여도 필드 값을 변경시키면 hashCode가 변경되면서 찾을 수 없는 값이 되버린다.

핵심은, 어노테이션 자체의 문제라기 보다는 변경 가능한 필드에 이를 남발함으로써 생기는 문제이다.

  • Immutable 클래스를 제외하고는 아무 파라미터 없는 @EqualsAndHashCode 사용은 지양한다.
  • 항상 @EqualsAndHashCode(of={“필드명시”}) 형태로 동등성 비교에 필요한 필드를 명시하는 형태로 사용한다.
  • 실무에서는 누군가는 이에 대해 실수하기 마련인지라 차라리 사용을 완전히 금지시키고, 꼭 필요한 필드를 지정하는 것이 나을 수도 있다.

생성자 자동 생성 어노테이션

😳@NoArgsConstructor 접근 권한 최소화 - PROTECTED 사용

JPA에서는 프록시를 생성을 위해서 기본 생성자를 반드시 하나를 생성해야한다. 이때 접근 권한이 protected 이면 된다. 굳이 외부에서 생성을 열어둘 필요가 없다.

  • public으로 설정하면 안정성을 심각하게 떨어트린다
  • private으로 설정하면 JPA가 프록시를 만들 때 접근하지 못해 객체를 생성하지 못하게 된다
  • 그냥 @NoArgsConstructor(access = AccessLevel.PROTECTED)를 쓰자

@NoArgsConstructor(access = AccessLevel.PROTECTED)와 함께 @Builder를 사용하면 반드시 필요한 값이 있어야 객체가 생성됨을 보장할 수 있어 안정성을 높일 수 있다. (참고 - @Builder란?, @NonNull?)

@AllArgsConstructor 사용 지양

@AllArgsConstructor는 모든 필드 값을 파라미터로 받아야 하는 생성자를 만드는 어노테이션이다.
만약 User testUser = new User(이기태, 25)과 같이 모든 필드 값을 쓰지 않고(생일을 쓰지 않는다던가) 생성을 한 경우 자동으로 Null Check를 해서 에러를 발생시킨다

매우 편리하게 생성자를 만들어주지만, 별 생각없이 작성한 코드가 치명적인 버그를 만들어낼 수도 있다.

@AllArgsConstructor
public static class Person {
    private String firstName;
    private String lastName;
}
// 성은 권, 이름은 현수
Person me = new Person("권", "현수");

만약 누군가가 실수로 아래와 같이 바꾼다면 lombok이 개발자도 인식하지 못하는 사이에 파라미터 순서를 바꿔놓는다.

@AllArgsConstructor
public static class Person {
    private String lastName;
    private String firstName;
}

😳@RequiredArgsConstructor

@RequiredArgsConstructor는 final이 붙거나 @NotNull 이 붙은 필드의 생성자를 자동 생성해주는 롬복 어노테이션이다.

  • Service와 Controller에서 사용된다. 참고🔗
@RequiredArgsConstructor
public class User{
	@NonNull
	private Long id;
	private String name;
	private String password;
	@NonNull
	private Integer age;
}

이런 Entity가 있을 경우 @RequiredArgsConstructor는

public User(Long id, Integer age){
	this.id = id;
	this.age = age;
}

이런 생성자를 만들어낸다.

before - 필드 주입방식을 사용한 Service

@Service
public class BannerServiceImpl implements BannerService {
    
    private BannerRepository bannerRepository;
    
    private CommonFileUtils commonFileUtils;
    
    @Autowired
    public BannerServiceImpl(BannerRepository bannerRepository, 
    						CommonFileUtils commonFileUtils) {
        this.bannerRepository = bannerRepository;
        this.commonFileUtils = commonFileUtils;
    }
    					...
}

after - @RequiredArgsConstructor를 활용한 생성자 주입

@Service
@RequiredArgsConstructor
public class BannerServiceImpl implements BannerService {
    
    private final BannerRepository bannerRepository;
    
    private final CommonFileUtils commonFileUtils;
        				...
}

참고
올바른 Lombok 사용법
AllArgsConstructor, NoArgsConstructor, RequiredArgsConstructor

profile
개발자가 되고싶은 낭랑 24세

0개의 댓글

관련 채용 정보