ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JAVA] Java Record 란?
    DEV/JAVA 2024. 6. 5. 01:41

    Record란?

    변경이 불가한 데이터 객체를 쉽게 만들 수 있도록 해준다. 클래스보다 간결하고 효율적으로 데이터 객체를 생성할 수 있도록 설계되었다. Java14에서 preview로 나왔고 Java16에서 정식기능으로 포함되었다.

     

    목표

    • 데이터를 간결하게 표현하기 위한 방법 제공
    • 개발자가 불변 데이터를 모델링하는데 집중하도록 함
    • 데이터 지향 메서드를 자동으로 구현

    특징

    • 간결성 : 필드를 정의하면 해당 필드를 기반으로 자동으로 메서드가 생성되어 코드의 양을 줄일 수 있고, 불필요한 보일러플레이트 코드를 줄여 가독성을 높여준다.
    • 메서드 자동 생성 : 필드를 기반으로 equals(), hashCode(), toString() 메서드를 자동으로 생성한다.
    • 생성자 자동 생성 : 필드를 기반으로 자동으로 생성자를 생성한다. (기본 생성자는 제공하지 않으므로 필요한 경우 직접 생성해야한다.)
    • 불변성 : 필드가 한번 설정되면 값을 변경할 수 없다. 이는 데이터의 안정성을 높이는데 도움이 된다.
    • fianl 선언 생략 : 불변 객체로서 abstract로 선언할 수 없으며 암시적으로 private final로 선언된다.
    • 패턴 매칭 통합 : Java의 Pattern Matching과 함께 사용될 수 있어, 데이터 추출 및 패턴 일치 검사에 효과적으로 사용될 수 있다.
    • 데이터 전달 : record의 주된 목적은 객체 간에 불변 데이터를 전달하는것으로서 DTO를 표현하는데 적합하다.

     

    보일러 플레이트 코드
    최소한의 변경(인자, 혹은 결과 타입)으로 여러 곳에서 재사용 되면서 반복적으로 비슷한 형태를 가지고 있는 코드
    → getter, setter, equals, hashCode, toString 메서드

     

     

    제약사항

    • abstract일수 없어 다른 클래스를 상속받을 수 없다.
    • 한 번 값이 정해지면 setter를 통해 값을 변경할 수 없다.
    • 레코드 내부에 private final 이외의 멤버 변수(인스턴스 필드)를 선언할 수 없다. 그러나 static 변수는 생성이 가능하다. 이는 헤더에서 정의한 멤버만을 record에서 관리하기 위함이다.

    위의 주요 특징을 제외하고는 자바의 클래스 개발과 동일하게 사용할 수 있다.

    • new 키워드를 통해 객체화 가능
    • static 메소드, static 필드 선언 가능
    • 중첩 클래스 사용 가능 및 제너릭 타입으로 지정 가능
    • 인터페이스 구현 가능

     

    Class (AS-IS)

    import java.util.Objects;
    
    public class User {
        private Long id;
        private String name;
        private int age;
    
        public User(Long id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            User user = (User) o;
            return getAge() == user.getAge() && Objects.equals(getId(), user.getId()) && Objects.equals(getName(), user.getName());
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(getId(), getName(), getAge());
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    User user = new User(1L, "김개발", 25);
    System.out.println(user.getId());
    System.out.println(user.getName()); 
    System.out.println(user.getAge());
    

     

    Record(TO-BE)

    class 대신 record를 사용한다.

    public record User(Long id, String name, int age) { }
    

    → private final 필드 id, name, age를 가진 User record로 간결하게 표현이 가능하다.

    User user = new User(1L, "김개발", 25);
    
    //getter 사용법 : 필드명으로 사용
    System.out.println(user.id());
    System.out.println(user.name());
    System.out.println(user.age());
    //toString(), equals()
    System.out.println(user.toString());
    System.out.println(user.equals(new User(2L,"김개발", 26)));

    레코드명(헤더), {바디}의 구조를 가지는데 헤더에 나열되는 필드를 컴포넌트라고 부른다.

    컴파일러는 헤더를 통해 내부 필드를 추론하고, 코드에 명시적으로 접근자와 생성자, toString(), equals(), hashCode()를 선언하지 않아도 이에 대한 구현을 자동으로 제공한다.

     

    참고포스팅

    https://velog.io/@pp8817/record

    https://blog.naver.com/seek316/223341255150 https://colevelup.tistory.com/28

    댓글

Designed by Tistory.