정구리의 우주정복

[Spring] @Builder 파헤치기 본문

JAVA/PROJECT

[Spring] @Builder 파헤치기

Jungry_ 2024. 5. 29. 22:24
반응형

항상 습관처럼 @Builder 와 @NoArgsConstructor ,@AllArgsConstructor 를 썼는데 왜 둘을 같이 써야하는지, 어떤 원리로 동작하는지도 모르고있었다

나는 바보 ! lombok 개발자 !!

 

알아보도록 하자

 

틀리거나 문제가 있다면 댓글로 알려주세요 감사합니다땡큐

@Builder 의 역할


  • 생성자를 메서드 체인을 사용해서 호출할 수 있는 빌더 클래스를 생성해준다
  • 순서도 상관없고, 값을 넣지 않은 경우 default 값이 들어가게 된다

@Builder 장점


  • 쉽게 빌더 패턴을 사용할 수 있음 (객체 생성 후 값을 변경되지 않게 할 수 있다)
  • 유연한 객체 생성 (필드 순서에 상관없음, 필요한 필드만 생성 가능)
  • 옵션 값 처리 (필수 값만 넣어주고 나머지는 기본값을 사용가능함)

 

@Builder 사용법


사용법은 어렵지 않음

@Builder 붙여주기 + 생성자 가 있으면 된다

 

Recommend.java

@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Recommend {
    private final int id; // primitive type
    private final String title; // wrapper class
    private final boolean content;

    @Override
    public String toString() {
        return "Recommend{" +
                "id='" + id + '\'' +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

 

생성자는 @AllArgsConstructor(access = AccessLevel.PRIVATE) 로 만들었다

 

내용 잘 보여줄라고 toString 하나정도 넣었음 !

 

TestController.java

    @GetMapping("/test")
    public String test() {
        Recommend recommend = Recommend.builder()
                .id(1)
                .title("title")
                .content(true)
                .build();

        return recommend.toString();
    }

 

 

 

실행시 결과 값

 

Recommend{id='1', title='title', content='true'}

 

값을 넣지 않으면 어떻게 될까 ?

    @GetMapping("/test")
    public String test() {
        Recommend recommend = Recommend.builder()
                .build();

        return recommend.toString();
    }

 

원시타입은 default 값이, 래퍼클래스는 null 이 들어가는 것을 확인할 수 있다

Recommend{id='0', title='null', content='false'}

 

 

@Builder 원리


builder 를 비슷하게 만들어보며 원리를 공부해보자 !

@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Recommend {
    private final int id; // primitive type
    private final String title; // wrapper class
    private final Boolean content;

    @Override
    public String toString() {
        return "Recommend{" +
                "id='" + id + '\'' +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                '}';
    }

 

 

이녀석을 어노테이션 없는 상태로 만들어보자

 

public class Recommend {
    private final int id;
    private final String title;
    private final boolean content;

    // @AllArgsConstructor(access = AccessLevel.PRIVATE)
    private Recommend(int id, String title, boolean content) {
        this.id = id;
        this.title = title;
        this.content = content;
    }


    // @Builder
    public static class Builder {
        private int id;
        private String title;
        private boolean content;

        public Builder id(int id) {
            this.id = id;
            return this;
        }

        public Builder title(String title) {
            this.title = title;
            return this;
        }

        public Builder content(boolean content) {
            this.content = content;
            return this;
        }

        public Recommend build() {
            return new Recommend(id, title, content);
        }
    }

    // .builder() 로 사용하기 위함
    public static Builder builder() {
        return new Builder();
    }

    @Override
    public String toString() {
        return "Recommend{" +
                "id='" + id + '\'' +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

 

생성자를 private 로 만든것은 public 으로 하면 

 

    @GetMapping("/test")
    public String test() {
        Recommend recommend = Recommend.builder()
                .build();
        
        Recommend recommend1 = new Recommend(1,"seo",false);

        return recommend.toString();
    }

 

builder 를 사용하지 않고 new . . . 이런식으로 생성이 가능하기 때문에 막아주려고 private 를 사용했다

 

builder().id().content().build() 

이런식으로 사용하기 위해서

 

    public static Builder builder() {
        return new Builder();
    }

 

를 넣어줬다

 

이거 없으면

 

    @GetMapping("/test")
    public String test() {
        Recommend recommend = Recommend.builder()
                .build();

        Recommend.Builder builder = new Recommend.Builder();
        Recommend recommend1 = builder.id(1).content(false).build();

        return recommend.toString();
    }

 

이렇게 만들어줘야함

 

 

 

@Builder


  • @NoArgsConstructor, @RequiredArgsConstructor 어노테이션을 사용하고 @AllArgsConstructor를 함께 사용하지 않으면, 컴파일러 오류가 발생할 수 있다. 그 이유는 모든 인수 생성자가 있다고 가정하고 이를 사용하는 코드를 생성하므로 이 생성자가 없으면 오류가 발생하는 것이다. (출처)

지식이 늘었다

 

Setter 를 사용하면 언제든 값을 바꿀 수 있는 문제가 있는데

Builder 를 사용해서 값을 변경할 수 없도록 하면서 유연하게 객체 생성이 가능해지게 되었다 !

심지어 가독성도 좋아졌다 ! 굉장히 좋군 !

반응형
Comments