본문 바로가기
Back-End/JAVA

[Java] record가 뭐야?

by 호강하는 지해 2025. 3. 25.
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;
	}
}
  1. 불변 객체로 만들려면 모든 필드에 final 선언
  2. 필드 값을 모두 포함한 생성자
  3. 접근자 메서드(getter)
  4. 클래스의 상속을 제한하려면 클래스 레벨에도 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