개인 프로젝트를 하다가 IDE에서 아래와 같은 문구를 발견하게 되었다.

"record 가 뭐지?" 라고 생각한 나는 바로 IDE의 조언대로 객체를 record를 변경해보았다.

어...?
record 에 전혀 모르고 있었던 나는 적잖이 당황했고, 이 record 라는 기능을 알아보기 위해 찾아보고 이해한 것들을 여기에 적어보기로 했다.
record 란?보통 우리가 만드는 데이터 객체는 오직 데이더 (e.g. DB 결과, 쿼리 결과, 등) 를 보관하기 위해 주로 사용된다.
이런 용도로 사용되는 객체들은 불변하게 만드는데, 이런 객체 간의 변경 불가능한 데이터를 전달할 시, Java 14 이전에는 boilerplate field 와 method가 포함된 클래스를 생성해야 해서 코드가 많이 복잡해진다.
하지만, Java 14가 출시되고서 부터 record keyword 를 사용하여 이러한 문제를 해결할 수 있게 되었다.
record는 Java 14 에서 preview 로 나왔고 Java 16 에서 정식 기능으로 포함되었다.
현재 진행 중인 개인 프로젝트를 예로 들면,
public class UserVO {
private final Long id;
private final String username;
private final String email;
public UserVO(Long id, String username, String email) {
this.id = id;
this.username = username;
this.email = email;
}
public Long getId() {
return id;
}
public String getUsername() {
return username;
}
public String getEmail() {
return email;
}
}
사용자의 간단한 정보들을 담기 위해 UserVO 만들어 사용하고 있다. 현재 이 클래스는 필드, 생성자, getter를 모두 담고 있어서 코드가 매우 길다.
여기서 lombok의 @Getter 와 @RequiredArgsConstructor 를 사용하면,
@Getter
@RequiredArgsConstructor
public class UserVO {
private final Long id;
private final String username;
private final String email;
}
코드가 훨씬 간결해진 것을 볼 수 있다.
하지만, 여전히 이런 클래스를 작성할 때 마다, 모든 필드를 명시하고,final로 정의해야 한다.
만약 record 를 사용한다면?
public record UserVO(Long id, String username, String email) {}
이렇게 더 간결하게 작성할 수 있다.
위의 record를 사용해 객체를 생성하는 방법은 간단하다.
UserVO user = new UserVO(1L, "user", "user@gmail.com");
이렇게 클래스와 같은 방식으로 객체를 인스턴스화 할 수 있다.
아래와 같이 필드 이름과 같은 getter method를 사용할 수 있다.
UserVO user = new UserVO(1L, "user", "user@gmail.com");
assertEquals("user", user.name());
assertEquals("user@gmail.com", user.address());
위의 기능들 외에도 더 다양한 기능들을 포함하고 있다
equals()
toString()
hashCode()
Compact Contructor*
Static variables & methods
비공개 필드를 초기화하는 것 이상의 작업 (필드 validation, etc) 을 수행하도록 도와주는 생성자. 클래스 생성자와 달리 레코드 생성자에는 공식적인 매개변수 목록이 없는 것이 특징이다.
아래처럼 validation을 추가하거나,
public record UserVO(Long id, String username, String email) {
public UserVO {
Objects.requireNonNull(username);
Objects.requireNonNull(email);
}
}
또는 아래처럼 다른 argument 목록을 제공하여 다른 argument를 가진 새로운 생성자를 생성할 수도 있다.
public record UserVO(Long id, String username, String email) {
public UserVO(String name) {
this(name, "Unknown");
}
}
record 는 다른 클래스를 상속받을 수 없으며, private final 이외의 인스턴스 필드를 선언할 수 없다. 선언되는 다른 모든 필드는 static 이어야 한다.
레코드는 암시적으로 fianl 이다. abstract 일 수 없다.
record 의 API가 상태 설명에 의해서만 정의되며 나중에 다른 클래스나 레코드에 의해 변경되거나 나아질 수 없음을 강조한다.