DEVELOP/CONCEPT

record class

콘순이 2025. 4. 24. 21:46

record란?

  • 불변 객체(필드 수정 불가)를 쉽게 생성할 수 있게 해주는 클래스 유형
  • JDK14에서 preview로 등장하여 JDK16+부터 정식 스펙에 포함되었다.

 

record은 무엇을 할까?

  • 필드 캡슐화 (private final)
  • 생성자 메서드
  • Getter 메서드
  • equals() 메서드
  • hashCode() 메서드
  • toString() 메서드

record를 사용하면 위 내용들을 직접 구현하지 않아도, 자동 생성해준다.

 

일반 class vs record class

일반 클래스

public class Student {
	private String name;
    private int age;
    
    public Student(String name, int age) {
    	this.name = name;
        this.age = age;
    }
    
    public String getName() {
    	return name;
    }
    
    public int getAge() {
    	return age;
    }
}

 

record 클래스

public record Student(String name, int age) {
}

 

record를 사용하면, 일반 클래스에서 수동으로 작성하던 구성 요소를 자동으로 제공받을 수 있어 코드가 훨씬 간결해짐.

 

 

record 특징

1. get 메서드는 일반 클래스처럼 getName()이 아닌 필드명과 동일한 메서드 이름을 사용한다.

student.name()  // student.getName() X
student.age()  // student.getAge() X

 

2. 상속 불가

 

  • record는 java.lang.Record를 암묵적으로 상속
  • 다른 클래스를 상속하거나 상속받는 것 불가능
  • 단, 인터페이스 구현은 가능

 

3. 모든 필드는 final (불변성)

  • 자동으로 private final 선언됨
  • 생성 이후 값 변경 불가능
  • → 가변성이 필요한 경우에는 부적합

 

record를 JPA의 Entity 클래스로 사용할 수 없는 이유

보통 JPA 엔티티는 setter나 dirty checking을 통해 필드 값의 변경이 자유롭다. 따라서, 불변성을 가진 record 클래스를 사용하는 건 적합하지 않다. 이 특징은 JPA의 지연 로딩이라는 기능과도 맞지 않다. record 클래스를 사용할 경우, 지연 로딩이나 업데이트 동작이 꼬일 수 있다.

또한, JPA는 기본 생성자(@NoArgsConstructor)을 필요로 하지만, record는 모든 필드를 한꺼번에 초기화 하는 compact constructor(@AllArgsConstructor)만 가지기 때문에 JPA가 내부적으로 프록시 객체나 리플렉션으로 인스턴스를 만들 때 문제가 생긴다.

 

* 프록시 객체: 원본 객체 대신 동작하는 대리 객체로, 지연 로딩 등을 위해 JPA가 내부적으로 생성함
→ record는 필드 수정이 불가능하므로 프록시로 감싸도 제대로 작동하지 않음.

* 리플렉션: 클래스나 메서드 정보를 런타임에 조회하고 조작할 수 있게 해주는 자바의 기능
→ JPA는 리플렉션으로 객체를 생성하고 필드 값을 주입하는데, record는 이를 제한함.

 

결론

record는 DTO, VO, 응답 모델 등 불변 데이터 객체로는 매우 유용하지만,
JPA Entity로는 부적합하다. → 대신 일반 클래스를 사용해야 함.