• 티스토리 홈
  • 프로필사진
    알쓸개잡
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
알쓸개잡
  • 프로필사진
    알쓸개잡
    • 분류 전체보기 (92)
      • 스프링부트 (52)
      • AWS (5)
      • 쿠버네티스 (7)
      • 자바 (19)
      • 인프라 (0)
      • ETC (8)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      • 반응형
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • java record 용법 - from jdk 14
        2023년 08월 19일
        • 알쓸개잡
        • 작성자
        • 2023.08.19.:53

        jdk 14 에서 새로운 타입 으로 record 가 preview 형태로 도입되었습니다. Enum 타입과 마찬가지로 record 타입은 몇가지 제약사항을 가지고 있으며 불변의 데이터 셋을 정의하는데 상당한 간소함을 제공합니다.

        JEP 359 에 기술된 내용을 보면 record 의 도입배경과 목적 외에 여러 관련 사항들을 확인해 볼 수 있습니다. 

        이번 포스팅에서는 record의 제약사항 및 용법에 대해서 알아보겠습니다.

         

        record 의 도입배경과 목적

        불변의 데이터 셋 (data carrier) 역할을 하는 클래스의 경우에도 생성자, 접근자, equals(), hashCode(), toString() 등 반복적인 코드를 많이 작성해야 하는 불편함과 함께 record 는 불변하는 데이터 집합을 보다 쉽고, 명확하고, 간결하게 하기 위한 목적이 있습니다. 

        Lombok 과 같이 데이터를 간소화 할 수 있는 annotation 을 정의하면 코드를 간소화 할 수는 있지만 해당 클래스가 불변의 데이터 셋 역할을 한다는 설계 의도를 명확하게 파악할 수는 없습니다. record 의 사용은 불변의 데이터 셋을 나타내는 명확한 설계 의도를 나타낼 수 있습니다.

         

        record 제약사항

        • 다른 클래스를 확장할 수 없습니다.
        • private final 필드 이외의 인스턴스 필드를 선언할 수 없습니다.
        • private final 필드가 아닌 다른 모든 필드는 static 이어야 합니다.
        • record 는 abstract 가 될 수 없으며 암묵적으로 final 입니다. (다른 클래스를 확장할 수 없음과 연결됩니다.)
        • record 의 구성요소는 암묵적으로 final 입니다.

         

        record 일반사항

        • class 내에 선언할 수 있으며 중첩된 record 는 암묵적으로 static 입니다.
        • record 는 inteface 를 구현할 수 있습니다.
        • 일반 class 와 마찬가지로 new 키워드로 record 를 인스턴스화 합니다.
        • record 본문에서 static method, static fields, static initializers, constructors, instance method 및 중첩된 유형을 선언할 수 있습니다.
        • record 및 record 개별 구성 요소에 annotation 을 붙일 수 있습니다.

         

        record 기본 용법

        package com.example.test.record;
        
        import lombok.Builder;
        
        import java.util.UUID;
        
        final public class Student {
        
        	private final UUID uuid;
        	private final String name;
        	private final String grade;
        
        	@Builder
        	public Student(UUID uuid, String name, String grade) {
        		this.uuid = uuid;
        		this.name = name;
        		this.grade = grade;
        	}
        
        	public UUID uuid() {
        		return uuid;
        	}
        
        	public String name() {
        		return name;
        	}
        
        	public String grade() {
        		return grade;
        	}
        }

        Student class 는 uuid(), name(), grade() 3개의 getter 메소드와 모든 요소를 파라미터로 가지는 생성자로 구성되어 있습니다.

        위 클래스를 record 를 사용하면 아래와 같이 선언할 수 있습니다.

        package com.example.test.record;
        
        import lombok.Builder;
        
        import java.util.UUID;
        
        @Builder
        public record Student(UUID uuid, String name, String grade) {}

        record 는 아래의 내용을 자동으로 처리한다.

        • 각 구성요소를 private final 필드로 처리합니다.
        • 각 구성요소의 이름과 동일한 public getter 메소드를 제공합니다. uuid(), name(), grade()
        • 모든 구성요소를 포함하는 public 생성자를 제공합니다.
        • 모든 구성 요소에 대한 equals(), hashCode(), toString() 를 생성합니다.

        equals(), hashCode(), toString() 에 대한 내용은 아래 테스트 코드를 통해서 검증이 가능합니다.

        @Test
        void record_test() {
            UUID uuid = UUID.randomUUID();
            String name = "student1";
            String grade = "A";
        
            Student record = Student.builder()
                .uuid(uuid)
                .name(name)
                .grade(grade)
                .build();
        
            Student record2 = Student.builder()
                .uuid(uuid)
                .name(name)
                .grade(grade)
                .build();
        
            Assertions.assertThat(record.hashCode()).isEqualTo(record2.hashCode());
            Assertions.assertThat(record.toString()).isEqualTo(record2.toString());
            Assertions.assertThat(record.equals(record2)).isTrue();
        }

         

        Compact Constructors

        record 에서 자동 생성한 생성자가 각 필드를 초기화 하는 것 이상의 작업을 수행하도록 하려면 record 에 대한 사용자 지정 생성자를 정의 할 수 있습니다. 이 생성자 정의를 Compact Constructor 라고 하며 argument 정의가 없습니다.

        public record Student(UUID uuid, String name, String grade) {
        	public Student {
        		Objects.requireNonNull(uuid);
        		Objects.requireNonNull(name);
        		Objects.requireNonNull(grade);
        	}
        }

        또한 record 의 모든 필드에 대한 public 생성자 이외에 생성자 구현을 사용자 정의 할 수 있습니다.

         

         

        public record Student(UUID uuid, String name, String grade) {
        	public Student(String uuid) {
        		this(uuid, "unknown", "unknown");
        	}
        }

        record 가 생성한 public 생성자와 동일한 argument 를 사용하여 생성자를 생성할 수 있지만, 이를 위해서는 각 필드를 수동으로 초기화 해야 합니다.

         

        public record Student(UUID uuid, String name, String grade) {
        	public Student(UUID uuid, String name, String grade) {
        		this.uuid = uuid;
        		this.name = name;
        		this.grade = grade;
        	}
        }

         

        Compact 생성자와 모든 argument 목록을 정의한 생성자가 함께 정의된 경우에는 compile error 가 발생합니다.

        //compile error!!!
        public record Student(UUID uuid, String name, String grade) {
        	public Student {
        		Objects.requireNonNull(uuid);
        		Objects.requireNonNull(name);
        		Objects.requireNonNull(grade);
        	}
            
            public Student(UUID uuid, String name, String grade) {
            	this.uuid = uuid;
                this.name = name;
                this.grade = grade;
            }
        }

         

        Static 변수와 메소드

        private final 필드 이외의 필드는 static 필드여야 하고, record 는 static 메소드를 가질 수 있습니다.

        package com.example.test.record;
        
        import lombok.Builder;
        
        import java.util.UUID;
        
        @Builder
        public record Student(UUID uuid, String name, String grade) {
        	public static String UNKNOWN_NAME = "unknown";
            
            public static Student unknownStudent(UUID uuid, String grade) {
            	return Student.builder()
        			.uuid(uuid)
        			.name(UNKNOWN_NAME)
        			.grade(grade)
        			.build;
            }
        }

         

        @Test
        void record_static_method_test() {
            UUID uuid = UUID.randomUUID();
            String grade = "A";
            StudentRecord unknownStudent = StudentRecord.unknownStudent(uuid, grade);
            Assertions.assertThat(unknownStudent.name()).isEqualTo(StudentRecord.UNKNOWN_NAME);
        }

         

        지금까지 java record 에 대해서 알아 보았습니다. 도움이 되었기를 바랍니다.

        반응형
        저작자표시 비영리 변경금지 (새창열림)

        '자바' 카테고리의 다른 글

        jdk pattern matching for instanceof  (0) 2023.08.26
        java switch expression - from jdk 14  (0) 2023.08.20
        java Array vs ArrayList  (0) 2023.08.19
        CompletableFuture 를 알아보자  (0) 2023.08.06
        byte 배열에서 charset 정보 detecting 하기  (0) 2023.08.04
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바