728x90
회사에서 새로운 프로젝트를 시작하게 되었는데, 그 프로젝트에선 Response 객체를 만들 때 class 대신 record를 쓰더라 이냥 저냥 다른 분들이 쓰신 코드 따라 나도 사용했지만 record의 본질은 하나도 모른 채 사용했었다…
그래서 오늘 정리해보겠다 !
간략한 소개
record는 JDK14에서 preview로 등장하여 JDK16에서 정식 스펙으로 포함되었다.
불변(immutable) 객체를 쉽게 생성할 수 있도록 하는 유형의 클래스
👀 record가 나오기 전에는?
우리가 흔히 아는 DTO 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;
}
}
- 불변 객체로 만들려면 모든 필드에 final 선언
- 필드 값을 모두 포함한 생성자
- 접근자 메서드(getter)
- 클래스의 상속을 제한하려면 클래스 레벨에도 final 선언
DTO를 구현하기 위해서는 getter, setter, equals, hashCode, toString 같은 데이터 처리 혹은 특정 연산을 수행하기 위해 오버라이드 된 메서드를 반복해서 작성하게 된다. 보일러 플레이트 코드가 불필요하게 크다.
보일러 플레이트 코드란?
최소한의 변경(인자, 혹은 결과 타입)으로 여러 곳에서 재사용 되면 반복적으로 비슷한 형태를 가지고 있는 코드
→ getter, setter, equals, hashCode, toString 등이 여기에 해당
🧐 @Data 같은 Lombok을 쓰면 되지 않나요?
Lombok을 쓰면 중복 코드를 줄일 수는 있지만, 근본적으로 자바가 가진 한계를 해결하지 못한다. 그럼 record가 어떻게 해결하는지 보자 !
Record의 특징
- 간결성
- 필드를 정의하면 해당 필드를 기반으로 자동 메서드가 생성된다.
- 메서드 자동 생성
- 생성자 자동 생성
- 불변성
- final 선언 생략
- record 내 각 필드(헤더에 나열한 컴포넌트)는 private final로 정의된다.
- 패턴 매칭 통합
- 데이터 전달
- 상속은 불가능하지만, 인터페이스로 구현 가능
- 레코드 내부에 멤버 변수(인스턴스 필드)를 선언할 수 없다. 그러나 static 변수는 생성이 가능하다. 이는 헤더에서 정의한 멤버만을 record에서 관리하기 위함이다.
- 위의 특징을 제외하고는 class와 동일하게 사용할 수 있다.
- new 키워드를 통해 객체화 가능
- static 메서드, static 필드 선언
- 중첩 클래스 사용 가능 및 제네릭 타입으로 지정 가능
👀 record를 사용한다면?
[record 구조] 레코드명(헤더), {바디}의 구조를 가지는데 헤더에 나열되는 필드를 컴포넌트라고 부른다.
public record Student(String name, int age) {
}
- 필드 캡슐화
- 생성자 메서드
- getter 메서드
- equals 메서드
- hashcode 메서드
- toString 메서드
- 모든 게 자동으로 생성된다. 이것이 가능한 이유는 컴파일 타임에 컴파일러에 의해 생성되기 때문이다.
- (컴파일러 코드가 궁금하다면 들어가서 확인해보자 !)
필드를 가져올 때 getter 형식의 getName()이 아닌 name()으로 사용한다.
Student student = new Student("지해", 26);
System.out.println(student.getName()); // 일반 class
System.out.println(student.name()); // record class
🧐 record를 Entity 클래스로 사용해도 되나요?
- hibernate와 같은 JPA는 프록시 생성을 위해 인수 생성자, non-final 필드, setter 및 non-final 클래스가 없는 엔티티에 의존한다. 즉, 프록시를 생성하기 위해서 entity는 불변이면 안된다. (JPA의 프록시는 1:1 매핑 시 지연 로딩 제공 등 다양하게 쓰인다.)
- 쿼리 결과를 매핑할 때 객체를 인스턴스화 할 수 있도록 매개변수가 없는 생성자가 필요하다. → record는 매개변수가 없는 생성자를 제공하지 않는다. (record는 불변 객체이기 때문에 setter를 사용할 수 없다. 이로 인해 모든 필드의 값을 입력한 후에 생성할 수 있다)
- 위에서 말했 듯 getter 형식의 접근자 메서드를 사용하지 않아서, 쿼리 결과 처리 후 수행할 getter, setter에 접근할 수 없다.
🧐 그럼 record는 언제 써야 적합한가요?
DB에 저장된 데이터의 전송 객체로서 아주 적합하다! 내가 이 글의 서문에서 말했듯이 나는 Response 객체에서 record를 사용했다고 했다.
읽어온 정보를 변경하지 않으려면 record 타입의 DTO가 적격이다. record는 한 번 값이 정해지고 나면 setter를 통해 값을 변경할 수 없는데, 자바 내부에서 데이터 가공 시 중간에 값이 변질될 우려가 없다.
728x90
'Back-End > JAVA' 카테고리의 다른 글
ajax - 댓글 삭제 (0) | 2023.12.13 |
---|---|
페이징 (1) | 2023.12.10 |
List & Map (1) | 2023.12.08 |