ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] Record Class란?
    Programming Language/Java 2023. 12. 20. 03:21
    728x90

     

    Record란 데이터 클래스로 Java 14에 추가되어 Java 16에 정식으로 포함되었다. Record 클래스를 사용하기 이전에는 변경 불가능한 단순 데이터 클래스를 표현하고자 할 때 불편함이 있었다. 

     

    불변 데이터 객체 User가 있다고 해보자.

    public class User{
    
        private final String name;
        private final String gender;
    
        public Person(String name, String gender) {
            this.name = name;
            this.gender= gender;
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(name, gender);
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            } else if (!(obj instanceof Person)) {
                return false;
            } else {
                Person other = (Person) obj;
                return Objects.equals(name, other.name)
                  && Objects.equals(gender, other.gender);
            }
        }
    
        @Override
        public String toString() {
            return "User[name=" + name + ", gender=" + gender+ "]";
        }
    }

     

    여기서 문제점은 무엇일까?

     

    1. boilerplate code 존재

    boilerplate code란 최소한의 변경으로 여러 곳에서 재사용되며, 반복적으로 비슷한 형태를 띄는 코드를 말한다. 위의 예시를 보면 constructor, equals, hashcode, toString과 같은 메소드들이 존재하는데 이 메소드들은 다른 데이터 클래스에서도 동일하게 나타난다. 데이터 클래스를 작성하고 싶었을 뿐인데 비슷한 코드들을 작성하는 것에 시간을 소요한다.

     

    2. 데이터 클래스라는 클래스의 목적이 모호

    데이터 클래스이지만 추가적인 constructor, equals, hashcode, toString과 같은 코드들로 인해 데이터 클래스라는 사실이 보이지 않는다. 정작 중요한 데이터 클래스의 필드들이 눈에 띄지 않는 것!

     

     

    이를 Record 클래스로 변경해보면 훨씬 차이가 보인다.

    public record User (
            String name,
            String gender
    ) {}
    • boilerplate code가 확연히 사라졌다.
    • 필드에 초점이 맞춰져 데이터 클래스라는 점이 명확하다.
    • 코드가 간결해졌다.

     

     

    Record

    Record 클래스는 순수하게 데이터를 보유하기 위한 특수한 종류의 클래스이다. 필드 유형과 이름만 필요한 불변 데이터 클래스이다. Record 클래스는 여러 특징과 제한사항이 존재한다.

     

    특징

    • 각 필드는 private final로 정의된다. (필드 캡슐화)
    • 모든 필드를 초기화하는 RequiredArgumentConstructor인 public constructor가 생성된다.
    • 각 필드의 getter는 get필드명()이 아닌 필드명을 딴 getter가 생성된다.
    • equals, hashcode, toString 메서드는 Java 컴파일러에 의해 생성된다.
    • static 변수를 가질 수 있고(내부멤버변수X), static & public method를 가질 수 있다. → 객체.static메소드 로 접근 가능
    • new 키워드를 사용해 객체화할 수 있다.
    • 중첩 클래스를 사용할 수 있으며 제네릭 타입으로 지정할 수 있다.
    • 생성자를 명시적으로 만들어서 추가적인 로직을 넣을 수 있다.

     

    제한

    • Record 클래스는 final 클래스로 상속이 불가능하다.
    • 값이 한번 정해지면 setter를 통해 값을 변경할 수 없다. 
    • 다른 클래스를 상속받을 수 없지만, 인터페이스로는 구현이 가능하다. (내부적으로는 java.lang.Record를 상속한 것)

     

     

     

    컴팩트 생성자(Compact Constructor)

    Record는 Java 컴파일러에 의해 모든 필드를 초기화하는 constructor가 생성된다. 만약 Record 필드를 초기화하는 것 이외에 추가적인 작업을 수행해야할 경우 사용자 지정 생성자를 정의할 수 있다.

    클래스 생성자와는 달리 Record의 생성자에는 공식적인 매개변수 목록이 없는데 이를 컴팩트 생성자라고 한다.

    public record User(String name, String gender) {
        public User { // 형태
        }
    }

     

     

    사용자 지정 생성자를 정의할 때 다음과 같은 형태로 가능하다.

     

    1. 생성자 내 추가 로직 구현

    컴팩트 생성자 내에 추가 로직을 작성할 수 있다. 보통 필드에 대한 validation 코드가 작성된다.

    public record User(String name, String gender) {
        public User {
            Objects.requireNonNull(name);
            Objects.requireNonNull(gender);
        }
    }

     

     

    2. 다른 argument 목록 제공

    필드 이외에 다른 argument를 작성할 수 있다.

    public record User(String name, String gender) {
        public User (String name) {
            this(name, "WOMAN")
        }
    }

     

     

    3. 생성자와 동일한 argument 제공

    생성자와 동일한 argument를 작성할 수 있지만, 이 경우 필드를 수동으로 초기화해야한다.

    public record User(String name, String gender) {
        public User (String name, String gender) {
            this.name = name;
    	this.gender = gender;
       }
    }

     

     

    4. 컴팩트 생성자와 동일한 인수목록을 가진 생성자를 선언하면 컴파일 오류 발생

    public record User(String name, String gender) {
        public User { // 컴파일 에러
        }
    }

     

    public record User(String name, String gender) {
        public User {
            Objects.requireNonNull(name);
            Objects.requireNonNull(gender);
        }
    	public User (String name, String gender) { // 컴파일에러
            this.name = name;
    		this.gender = gender;
        }
    }

     

     

     

     

    Record를 JPA Entity 클래스로 사용할 수 있을까?

    Record의 편리함과 데이터 클래스라는 점에서 Entity 클래스로 사용할 수 있지 않을까 생각할 수 있다. 하지만 Record는 Entity 클래스로 사용할 수 없다.

    Record 클래스는 final 클래스로 상속이 불가능하고 abstract로 선언할 수 없다. JPA의 지연로딩 방식을 사용하면 JPA는 Entity 객체의 프록시 객체를 생성한다. 프록시 객체는 원본 객체를 상속하여 생성된 확장 클래스이다. Record는 상속이 불가능하기 때문에 프록시 객체를 만들 수 없어 JPA Entity 클래스로 사용할 수 없다.

     

     

     

     

    Record 사용

    • DTO
      • 데이터 전달을 위한 객체라는 점에서 데이터 클래스와 부합
    • 불변 데이터 객체
    • 등등
    728x90

    'Programming Language > Java' 카테고리의 다른 글

    [Java] Virtual Thread에 대해서  (1) 2024.01.10

    댓글

Designed by Tistory.