본문 바로가기
  • 개발하는 곰돌이
Programming Language/Kotlin & Java

[Java] Java 14부터 추가된 Record 타입과 Kotlin의 Data Class 비교

by 개발하는 곰돌이 2023. 6. 14.

목차

    들어가기 전에

    자바 14부터 코틀린의 Data 클래스와 유사한 Record라는 클래스가 추가되어 자바 16에서 정식으로 지원되기 시작했다. 그동안 자바에서 DTO 등의 클래스를 만들 때는 Lombok의 도움을 받아 @Data 어노테이션을 붙이는 경우가 많았지만 Record 클래스가 추가되어 이러한 필요성이 줄어들게 되었다.

     

    하지만 자바의 Record 클래스와 코틀린의 Data 클래스는 비슷하지만 다른 점이 있다. 이에 대해 정리해본다.

    Record 클래스의 기본 구조와 사용법

    Record 클래스는 아래와 같은 구조로 선언된다.

    public record Member(
            String account,
            String name,
            int age
    ) {
        ...
    }

    클래스 명 뒤에 소괄호로 메소드의 파라미터를 지정하듯이 클래스의 필드들을 정의한다. 이 때 필드 앞에 접근 지정자는 입력할 수 없다.

     

    Record 클래스의 선언 방식은 코틀린 클래스의 선언 방식과 굉장히 유사한 것을 볼 수 있다. 코틀린 클래스와 마찬가지로  Record 클래스 선언의 소괄호 내부에 있는 필드들은 모두 생성자의 파라미터가 된다. 다만 클래스 내에 다른 내용이 없으면 중괄호를 생략할 수 있는 코틀린 클래스와는 달리 Record 클래스는 클래스 내에 다른 내용이 없더라도 중괄호가 반드시 있어야 한다.

     

    Record 클래스의 프로퍼티를 가져다 쓸 때는 일반적인 클래스의 Getter 형식인 getXXX()가 아니라 필드의 이름 그대로 XXX()를 사용한다. 위의 Member 객체에서 name을 조회하고 싶다면 member.name()과 같이 사용하면 된다.

     

    Record 클래스는 Data 클래스와 마찬가지로 toString(), equals(), hashCode()가 정의되어 있다.

    Record 클래스는 toString(), equals(), hashCode()가 자동으로 정의된다.

    Record 클래스의 특징

    그럼 이제 자바 Record 클래스와 코틀린 Data 클래스의 특징을 비교해보자.

    Record 클래스는 모든 프로퍼티가 final이다.

    프로퍼티를 선언할 때 valvar 모두 사용할 수 있는 코틀린의 Data 클래스와 달리 자바의 Record 클래스는 모든 필드가 묵시적으로 final로 선언된다.

     

    모든 필드가 final이니, 당연히 Setter도 존재하지 않고 객체의 불변성이 어느정도 보장된다. Record 클래스를 선언할 때 필드에 final이 붙지 않았다고 직접 Setter를 만들거나 상태값을 변경하는 메소드를 만들려고 하면 컴파일 에러가 발생한다.

    Record 클래스의 프로퍼티는 final이기 때문에 변경할 수 없다.
    IDE가 자동으로 만들어주는 Setter도 없다.

    물론 Record 클래스의 필드에 객체가 있다면 완벽한 불변성이 보장되지 않을 수 있다. 원시 타입이 아닌 모든 객체는 참조 주소를 전달하는 Call by Reference로 동작하기 때문에 객체를 단순히 조회한 후 상태값을 바꾸면 원본 객체의 상태값이 바뀌게 된다. 이 경우에는 필드로 포함된 객체도 불변 객체여야 불변성을 보장할 수 있다.

    객체를 필드로 가지는 Record 클래스는 해당 객체까지 불변이 아니면 변조될 수 있다.

    Record 클래스는 상속이 불가능하다

    코틀린의 Data 클래스는 다른 클래스를 상속받을 수 있고, (권장되는 것도 아니고 약간의 편법을 사용해야하긴 하지만) 다른 클래스에서 상속받을 수 있는 것과 달리 Record 클래스는 다른 클래스를 상속받을 수 없으며, 다른 클래스에서 Record 클래스를 상속받을 수도 없다.

    Record 클래스는 다른 클래스를 상속받을 수 없다.
    다른 클래스에서도 Record 클래스를 상속받을 수 없다.

    Record 클래스가 다른 클래스를 상속받을 수 없는 이유는 사실 Record라는 추상 클래스를 상속받아서 구현되기 때문이다. 클래스는 하나의 클래스로부터만 상속받을 수 있는데 이미 상속을 받고 있으니 다른 클래스를 상속받을 수 없는 것이다.

    java.lang에 있는 추상 클래스인 Record

    Record 클래스는 copy() 메소드가 없다

    그 외에도 원칙적으로 모든 것이 final인 Record 클래스의 특성 상 copy()는 굳이 지원하지 않는다.

    마치며

    자바의 Record 클래스는 코틀린의 Data 클래스와 유사하지만 조금 더 안전한 사용을 위해서인지 여러 제약을 두었다는 점이 흥미로웠다. 코틀린에서는 val의 사용을 권장하면서도 var도 사용할 수 있던 것과 달리 아예 final로 제한을 해버렸다는 점에서 불변성에 초점을 둔게 아닐까 싶다.

     

    실제로는 추상 클래스를 상속받아 구현되고 있다는 점도 꽤나 재밌는 점이다. record라는 키워드가 추가되어 언어 차원에서 추가된 기능인가 했는데 사실은 상속받아서 구현되고 있었다는게 오묘한 느낌이다.

    참조링크

     

    Java Language Updates

    Record classes, which are a special kind of class, help to model plain data aggregates with less ceremony than normal classes.

    docs.oracle.com

     

    JEP 395: Records

    JEP 395: Records OwnerGavin BiermanTypeFeatureScopeSEStatusClosed / DeliveredRelease16Componentspecification / languageDiscussionamber dash dev at openjdk dot java dot netRelates toJEP 359: Records (Preview)JEP 384: Records (Second Preview)Reviewed

    openjdk.org

     

    댓글