BE/Java

[Java] @Builder, @ToString, @EqualsAndHashCode, @Singular

baek-dev 2024. 12. 23. 18:47

롬복에서 제공하는 어노테이션으로, 객체 생성시 복잡한 생성자 호출 대신 가독성 높은 방식으로 객체를 생성할 수 있게 해준다

 

빌더 패턴의 기본 개념

1. 객체 생성의 유연성 제공

  • 필수 필드와 선택적 필드를 구분하여 객체 생성 가능

2. 가독성 향상

  • 매개변수가 많은 생성자보다 각 필드를 명확하게 지정 가능

3. 불변 객체 생성

  • 객체를 생성한 후 내부 상태를 변경하지 않도록 설계 가능

빌더의 사용법

기본 사용법

import lombok.Builder;
import lombok.ToString;

@Builder
@ToString
public class User {
    private String name;
    private int age;
    private String email;
}

public class Main {
    public static void main(String[] args) {
        User user = User.builder()
                        .name("Alice")
                        .age(30)
                        .email("alice@example.com")
                        .build();
        System.out.println(user);
    }
}

출력 :

User(name=Alice, age=30, email=alice@example.com)
  • @Builder : User클래스에 빌더 패턴을 적용
  • builder() : 빌더 객체를 생성
  • 각 필드 메서드 : 원하는 값을 설정
  • build() : 최종적으로 객체를 생성

생성자와 함께 사용

1. @AllArgsConstructor 와 함께 사용

빌더를 모든 필드를 초기화하는 생성자와 함께 사용하여 객체 생성

import lombok.Builder;
import lombok.AllArgsConstructor;

@Builder
@AllArgsConstructor
public class Product {
    private String name;
    private double price;
    private int stock;
}

2. 특정 생성자만 지정

import lombok.Builder;

public class Order {
    private String orderId;
    private String productId;
    private int quantity;

    @Builder
    public Order(String orderId, String productId) {
        this.orderId = orderId;
        this.productId = productId;
        this.quantity = 1; // 기본값 설정
    }
}

 

@ToString, @EqualsAndHashCode

빌더로 생성된 객체는 @ToString, @EqualsAndHashCode 와 함께 사용하여, 디버깅이나 객체 비교시 편리함을 제공한다

import lombok.Builder;
import lombok.ToString;
import lombok.EqualsAndHashCode;

@Builder
@ToString
@EqualsAndHashCode
public class Customer {
    private String id;
    private String name;
    private String phoneNumber;
}

 

@ToString

  • toString() 메서드가 자동으로 생성되어, 객체를 출력하면 필드 값을 문자열로 반환한다
import lombok.ToString;

@ToString
public class Person {
    private String name;
    private int age;
}
Person person = new Person("Alice", 30);
System.out.println(person);
// 출력: Person(name=Alice, age=30)
속성 설명 기본값
exclude 제외할 필드 지정 없음
callSuper 상위 클래스의 toString() 호출 여부 false
includeFieldNames 필드 이름을 포함할지 여부 true

@EqualsAndHashCode

  • equals() 와 hashCode() 메서드를 자동으로 생성
  • 객체를 비교하거나 컬렉션에서 객체를 사용할때 유용
import lombok.EqualsAndHashCode;

@EqualsAndHashCode
public class Person {
    private String name;
    private int age;
}
  • equals() 메서드: 두 객체가 같은지 비교
  • hashCode() 메서드: 객체의 고유한 해시 값을 반환
속성 설명 기본값
exclude 제외할 필드 지정 없음
callSuper 상위 클래스의 equals/hashCode 포함 여부 false
onlyExplicitlyIncluded @EqualsAndHashCode.Include 로 명시적으로 지정된 필드만 포함 false

 

@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Person {
    @EqualsAndHashCode.Include
    private String name;
    private int age;
}
  • name 필드만 비교에 사용된다

복잡한 객체에서의 활용

1. 중첩 객체

import lombok.Builder;
import lombok.ToString;

@Builder
@ToString
public class Car {
    private String model;
    private Engine engine;

    @Builder
    @ToString
    public static class Engine {
        private int horsepower;
        private String type;
    }
}

public class Main {
    public static void main(String[] args) {
        Car.Engine engine = Car.Engine.builder()
                                      .horsepower(500)
                                      .type("V8")
                                      .build();

        Car car = Car.builder()
                     .model("Mustang")
                     .engine(engine)
                     .build();

        System.out.println(car);
    }
}

출력:

Car(model=Mustang, engine=Engine(horsepower=500, type=V8))

@Builder와 @Singular

빌더에서 컬렉션을 다룰때 편리하게 사용

import lombok.Builder;
import lombok.Singular;
import lombok.ToString;

import java.util.List;

@Builder
@ToString
public class Team {
    private String name;

    @Singular
    private List<String> members;
}

public class Main {
    public static void main(String[] args) {
        Team team = Team.builder()
                        .name("Developers")
                        .member("Alice")
                        .member("Bob")
                        .build();

        System.out.println(team);
    }
}

출력:

Team(name=Developers, members=[Alice, Bob])

 

 

@Singular

  • 빌더와 함께 사용하여 컬렉션을 편리하게 초기화할 수 있도록 지원
  • 하나씩 요소를 추가하는 방식으로 빌더를 구성할 수 있다
import lombok.Builder;
import lombok.Singular;
import java.util.List;

@Builder
public class Team {
    private String name;
    @Singular
    private List<String> members;
}
Team team = Team.builder()
                .name("Developers")
                .member("Alice")
                .member("Bob")
                .build();

System.out.println(team);
// 출력: Team(name=Developers, members=[Alice, Bob])
  • 컬렉션 필드를 @Singular로 지정하면 빌더에서 요소를 하나씩 추가 가능
  • 자동으로 빈 컬렉션을 생성(컬렉션 필드가 null이 될 위험 제거)

 


장점과 단점

 

장점

1. 객체 생성의 가독성 증가:

  • 필드 이름을 명시적으로 지정하여 가독성을 향상

2. 불필요한 생성자 오버로딩 제거:

  • 다양한 조합의 생성자를 대체 가능

3. 불변성 유지:

  • 필드 초기화 이후 값 변경 방지

4. 롬복의 간단한 사용법:

  • 코드 작성량 감소

 

단점

1. 추가 라이브러리 필요:

  • 롬복을 사용해야 하므로, 프로젝트에 의존성이 추가됨

2. 런타임 오버헤드:

  • 동적 객체 생성으로 인한 약간의 성능 손실 가능

정리

1. @Builder란?

  • 롬복에서 제공하는 어노테이션으로, 빌더 패턴을 간편하게 구현

2. 활용:

  • 객체 생성 시 가독성을 높이고, 선택적 필드 초기화, 불변성 유지 등

3. 확장 기능:

  • 중첩 객체 빌더, 컬렉션 초기화(@Singular) 등

4. 주의점:

  • 롬복 의존성과 추가적인 컴파일 과정

 

 

 

 

출처 : ChatGPT

'BE > Java' 카테고리의 다른 글

[Java] enum  (1) 2025.01.01
[Java] @IdClass  (0) 2024.12.31
[Java] 프록시  (0) 2024.12.22
[Java] 쓰레드  (0) 2024.12.22
[Java] StringBuffer, StringBuilder  (1) 2024.12.19