아무거나

[Lombok] Lombok 사용시 주의사항 본문

Java & Kotlin/Spring

[Lombok] Lombok 사용시 주의사항

전봉근 2020. 12. 1. 10:00
반응형
  • Lombok 사용시 주의사항 (1.16 기준)
    • lombok.config를 통하여 애노테이션 사용금지 및 각종 설정
        config.stopBubbling = true
        lombok.data.flagUsage=error
        lombok.value.flagUsage=error
        lombok.val.flagUsage=error
        lombok.var.flagUsage=error
        lombok.nonNull.flagUsage=error
        lombok.allArgsConstructor.flagUsage=error
        lombok.requiredArgsConstructor.flagUsage=error
        lombok.cleanup.flagUsage=error
        lombok.sneakyThrows.flagUsage=error
        lombok.synchronized.flagUsage=error
      
        # experimental 전체 금지
        lombok.experimental.flagUsage=error
      
        # 기타 각종 사용해서는 안되는 기능들을 모두 나열할 것. (https://projectlombok.org/features/configuration)
      
    • @AllArgsConstructor, @RequiredArgsConstructor 주의하여 사용
      • 먼저 PriceInfo 클래스를 정의하자
          @AllArgsConstructor
          public static class PriceInfo {
              private int price;
              private int discountPrice;
          }
          
          // 정상가격 3,000원, 할인가격 1,000원
          PriceInfo priceInfo = new PriceInfo(3000, 1000);         
        
      • 만약 필드의 순서가 마음에 안들어 아래와 같이 변경했다고하자.
          @AllArgsConstructor
          public static class PriceInfo {
              private int discountPrice;
              private int price;
          }
          
          // 할인가격 3,000원, 정상가격 1,000원
          PriceInfo priceInfo = new PriceInfo(3000, 1000);          
        
      • 이러한 경우에는 IDE가 제공하는 리팩토링이 작동하지 않을 뿐더러 Lombok 또한 개발자들이 인식하지 못하는 사이에 생성자의 파라미터 순서를 필드 선언 순서에 맞춰 생성자의 매개변수 순서를 변경해버린다. 또한 두 필드는 동일한 데이터 타입이므로 매개변수 순서가 변경되어도 어떠한 오류도 발생하지 않는다.
    • 해결방안
      • @Builder 를 활용하면 매개변수 순서가 아닌 이름으로 값을 설정하기 때문에 리팩토링에 유연하게 대응이 가능하다.
          public static class PriceInfo {
              private int price;
              private int discountPrice;
        
              @Builder
              private PriceInfo(int price, int discountPrice) {
                  this.price = price;
                  this.discountPrice = discountPrice;
              }
          }
        
          // 필드 순서를 변경해도 문제 없음
          PriceInfo priceInfo = PriceInfo.builder().discountPrice(1000).price(3000).build();
        
    • @EqualsAndHashCode
        @EqualsAndHashCode
        public static class PriceInfo {
            private int price;
            private int discountPrice;
        
            public PriceInfo(int price, int discountPrice) {
                this.price = price;
                this.discountPrice = discountPrice;
            }
        }
        
        PriceInfo priceInfo = new PriceInfo(1000L, 19800L, 0L);
        
        Set<PriceInfo> priceInfoSet = new HashSet<>();
        priceInfoSet.add(PriceInfo); // Set에 객체 추가
        
        System.out.println("변경전 : " + priceInfoSet.contains(priceInfo)); // true
        
        priceInfo.setPrice(5000); // price 값 변경
        System.out.println("변경후 : " + priceInfoSet.contains(priceInfo)); // false    
      
      • 동일한 객체임에도 Set 에 저장한 뒤에 필드 값을 변경하면 hashCode가 변경되면서 찾을 수 없게 되어버린다. 그러므로 최소한 꼭 필요하고 일반적으로 변하지 않는 필드에 대해서만 만들도록 노력해야 한다.
    • @Data 사용금지
      • @EqualsAndHashCode와 @RequiredArgsConstructor를 포함하기 때문에 사용을 아예 금지하고 아래와 같이 명시하자.
          @Getter
          @Setter
          @ToString
          public class PriceInfo {
          ...
              // 생성자와 필요한 경우에만 equals, hashCode 직접 작성
          }        
        
    • @Value 사용금지
      • Immutable 클래스를 만들어주는 조합 애노테이션이지만 이 또한 @EqualsAndHashCode, @AllArgsConstructor 를 포함한다. @EqualsAndHashCode는 불변 클래스라 큰 문제가 안되지만 @AllArgsConstructor가 문제가 된다. 그러므로 아래와 같이 사용하자
          @Getter
          @ToString
          public class PriceInfo {
              // private final 로 여러 필드 생성
              // 생성자와 필요한 경우에만 equals, hashCode 직접 작성
          }      
        
    • @Builder를 클래스보다는 직접 만든 생성자나 static 객체 생성 메소드에 붙이는 것을 권장한다.
      • @Builder는 기본적으로 @AllArgsConstructor를 내포하고 있으며 이걸로는 크게 문제가 안생기나 생성자를 private으로 만들기 때문에 외부에서 생성자를 호출할일은 쉽게 생기진 않는다. 그러나 해당 클래스의 다른 메소드에서 이렇게 자동으로 생성된 생성자를 사용할 때 문제를 발생시킬 수 있다.
    • Log는 가급적 @Slf4j를 사용하자
      • @Slf4j는 Logger와 같이 field 변수로 만들 필요가 없어 static method에서도 호출이 가능하다.

 

참고: https://kwonnam.pe.kr

반응형
Comments