티스토리 뷰
record 란 무엇일까요?
- 불변(immutable) 데이터 객체를 쉽게 생성할 수 있도록 하는 새로운 유형의 클래스로 일반 class와 다르게 생성자, getter, hashCode(), equals(), toString() 메소드를 제공해줍니다.
- DTO처럼 데이터를 운반하는 특성의 클래스를 구현할 때 반복적으로 작성했던 부분을 없애줍니다.
- JDK14 버전에서 preview로 등장하여 JDK16 버전에서 정식 스펙으로 포함되었습니다.
어떻게 사용하는 걸까요?
선언 방식
record 레코드명(컴포넌트1, 컴포넌트2) {}
class를 사용한 DTO 객체
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
// ... //
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
record 를 이용한 DTO 객체
public record Person(String name, int age) {};
- record가 대신해주는 부분은 다음과 같습니다.
- 모든 컴포넌트를 private final로 필드 선언
- 모든 파라미터를 포함하는 생성자 선언
- 모든 필드의 get 메소드 생성
- 로깅 출력을 위한 toString, 인스턴스 비교를 위한 hashCode, equals 메소드 정의
적용해보기
public class LoginDto {
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public static class Request {
private String username;
private String password;
@Builder
public Request(final String username, final String password) {
this.username = username;
this.password = password;
}
}
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public static class Response {
private Long member_id;
private String username;
private String nickname;
private MemberRoleEnum role;
private PlatformEnum platform;
@Builder
public Response(final Long member_id, final String username, final String nickname, final MemberRoleEnum role, final PlatformEnum platform) {
this.member_id = member_id;
this.username = username;
this.nickname = nickname;
this.role = role;
this.platform = platform;
}
public static Response of(Member member) {
return Response.builder()
.member_id(member.getId())
.username(member.getUsername())
.nickname(member.getNickname())
.role(member.getRole())
.platform(member.getPlatform())
.build();
}
}
}
- 개인 프로젝트에서 사용했던 LoginDto 부분입니다. Request와 Response를 innerClass로 구현하였습니다.
- 만약 또 다른 DTO를 만든다면 필드 선언, @Getter, @NoArgsConstructor 어노테이션 선언, 빌더 패턴 생성자 선언 의 작업을 똑같이 해주어야 합니다.
- 그외 toString과 같은 메소드도 사용한다면 반복적으로 작성을 해주어야겠죠.
- 앞서 보았던 예시처럼 보일러 플레이트를 작성하지 않는 record 형식으로 리팩토링해보겠습니다.
DTO 리팩토링
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public static class Request {
private String username;
private String password;
@Builder
public Request(final String username, final String password) {
this.username = username;
this.password = password;
}
}
- class에서 필드 선언과 생성자를 만들었던 부분을 record에서는 단 한 줄로 간단하게 표현할 수 있습니다.
@Builder
public record Request(String username, String password) {}
- class에서 파라미터라고 부르는 부분을 컴포넌트라고 하는데 컴포넌트를 record 괄호 안에 정의해주면 private final로 필드가 선언된 것처럼 만들어주고 AllArgsConstructor 어노테이션을 사용한 것과 같은 작업을 해줍니다.
- 저같은 경우는 빌더 패턴을 애용하기 때문에 @Builder 어노테이션을 붙여서 커스텀하였습니다.
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public record LoginDto() {
@Builder
public record Request(String username, String password) {}
@Builder
public record Response(Long member_id, String username, String nickname, MemberRoleEnum role, PlatformEnum platform) {
public static Response of(Member member) {
return Response.builder()
.member_id(member.getId())
.username(member.getUsername())
.nickname(member.getNickname())
.role(member.getRole())
.platform(member.getPlatform())
.build();
}
}
}
- 메소드를 정의하는 것도 동일하게 record 안에서 할 수 있습니다.
MemberService
public LoginDto.Response login(LoginDto.Request request) {
Member member = memberRepository.findByUsername(request.username())
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_USER));
- class와 또 다른 차이는 get메소드를 사용할 때입니다.
- class는
request.getUsername()
과 같이 get + 필드명을 사용하지만 record는request.username()
처럼 필드명을 그대로 사용하게 됩니다.
그 외 record 제약 사항
- 레코드는 기본적으로 java.lang.Record 클래스를 상속받기 때문에 다른 클래스를 상속받을 수 없습니다.
- private final 이외의 인스턴스 필드를 선언할 수 없습니다. 다시 말하면 모든 필드는 static이어야 한다는 것입니다.
- 또한 암시적으로 final 이며 추상적(abstract)일 수 없습니다.
- 이러한 레코드의 불변한 상태 조건은 DTO와 같은 불변 데이터 객체를 다루기 적합하다는 것을 의미하는 것 같습니다.
- 위 제약사항 이외에 inner class, 제네릭, 인터페이스 구현 여부, new 키워드를 통한 인스턴스화와 같은 특징들은 모두 일반 class와 동일합니다.
관련 자료
반응형
'개발냥이 > 자바(Java)' 카테고리의 다른 글
[자바] 단위 테스트 도구, JUnit 기초 (0) | 2023.10.12 |
---|---|
[자바] 비트 연산자 알아보기! (2) | 2023.10.05 |
[스프링부트] Logback 설정해보기 (1) | 2023.06.05 |
[자바] 제네릭의 와일드카드 & 공변성 뿌시기 (1) | 2023.05.28 |
[자바] 업캐스팅 & 다운캐스팅 이해하기 (3) | 2023.05.24 |
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- DP
- JavaScript
- SQL
- 타입스크립트
- 자바트리
- 형변환
- BFS
- Queue
- 정렬
- 자바스크립트
- 리액트
- 이분탐색
- dfs
- Nest
- 백준
- java
- 알고리즘
- 프로그래머스
- 스프링부트
- JPA
- 스프링
- CS
- 자바bfs
- Comparator
- Spring
- Algorithm
- SQLD
- 자바dp
- 자바
- 해시맵
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
글 보관함