0Pricing
Java Academy · 강의

레코드 소개

레코드를 간결한 불변 데이터 보유자로 선언하고 자동 생성되는 구성 요소를 이해합니다.

레코드 소개은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

레코드 소개

Java Records(Java 16 이상)는 변경할 수 없는 데이터 전달 클래스를 간결하게 선언하는 방법입니다. 생성자, 접근자, equals, hashCode, toString과 같은 반복 코드를 자동으로 생성합니다.

레코드 선언하기

record 키워드 뒤에 레코드 이름과 컴포넌트 목록을 작성합니다. 각 컴포넌트는 private final 필드와 public 접근자 메서드가 됩니다.

record Point(double x, double y) {}

Point p = new Point(3.0, 4.0);
System.out.println(p.x());      // 3.0 (accessor, not getX())
System.out.println(p.y());      // 4.0
System.out.println(p);          // Point[x=3.0, y=4.0]
System.out.println(p.equals(new Point(3.0, 4.0))); // true

자동 생성되는 멤버

컴파일러는 모든 레코드에 canonical 생성자, public 접근자, equals(), hashCode(), toString()을 자동으로 생성합니다. 이러한 항목을 직접 작성할 필요가 없습니다.

record Product(String name, double price, int stock) {}

Product p1 = new Product("Widget", 9.99, 100);
Product p2 = new Product("Widget", 9.99, 100);

System.out.println(p1.name());          // Widget
System.out.println(p1.price());         // 9.99
System.out.println(p1.equals(p2));      // true (structural)
System.out.println(p1.hashCode() == p2.hashCode()); // true
System.out.println(p1);                 // Product[name=Widget, price=9.99, stock=100]

레코드는 변경할 수 없습니다

레코드 컴포넌트는 final입니다. 생성된 후에는 수정할 수 없으므로 레코드는 변경할 수 없는 값 객체를 모델링합니다.

record Money(long cents, String currency) {}

Money price = new Money(999, "USD");
// price.cents = 500; // Compile error — final field!

// To "update" a record, create a new one
Money discounted = new Money(price.cents() - 100, price.currency());
System.out.println(discounted); // Money[cents=899, currency=USD]

레코드는 Object만 확장합니다

레코드는 암시적으로 java.lang.Record를 확장하며 다른 클래스를 확장할 수 없습니다. 인터페이스는 구현할 수 있습니다.

interface Describable { String describe(); }

record Circle(double radius) implements Describable {
    public String describe() {
        return String.format("Circle with radius %.1f", radius);
    }

    public double area() {
        return Math.PI * radius * radius;
    }
}

Circle c = new Circle(5.0);
System.out.println(c.describe()); // Circle with radius 5.0
System.out.printf("Area: %.2f%n", c.area()); // Area: 78.54

컬렉션에서 레코드 사용하기

레코드는 모든 컴포넌트를 기준으로 equals와 hashCode를 올바르게 구현하므로 Map의 키와 Set의 요소로 사용할 수 있습니다.

import java.util.*;

record Coordinate(int row, int col) {}

Map<Coordinate, String> grid = new HashMap<>();
grid.put(new Coordinate(0, 0), "Origin");
grid.put(new Coordinate(1, 2), "Target");

// Lookup with equal-valued record works correctly
System.out.println(grid.get(new Coordinate(0, 0))); // Origin
System.out.println(grid.get(new Coordinate(1, 2))); // Target

Set<Coordinate> visited = new HashSet<>();
visited.add(new Coordinate(3, 3));
System.out.println(visited.contains(new Coordinate(3, 3))); // true

DTO로 사용하는 레코드

레코드는 REST API의 데이터 전송 객체(DTO)에 적합합니다. 동작 없이 계층 간에 데이터를 전달하기 때문입니다.

record CreateUserRequest(String email, String displayName, String plan) {}

record UserResponse(long id, String email, String displayName,
                    String plan, String createdAt) {}

// Simulating a service call
static UserResponse createUser(CreateUserRequest req) {
    long id = 42L;
    return new UserResponse(id, req.email(), req.displayName(),
        req.plan(), java.time.Instant.now().toString());
}

CreateUserRequest req = new CreateUserRequest("alice@example.com", "Alice", "PRO");
UserResponse resp = createUser(req);
System.out.println(resp);

레코드 분해하기

레코드는 패턴 매칭과 잘 어울립니다. switch 표현식에서 레코드를 분해할 수 있습니다(Java 21 이상).

sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
record Triangle(double base, double height) implements Shape {}

static double area(Shape s) {
    return switch (s) {
        case Circle(double r)            -> Math.PI * r * r;
        case Rectangle(double w, double h) -> w * h;
        case Triangle(double b, double h) -> 0.5 * b * h;
    };
}

System.out.printf("%.2f%n", area(new Circle(5)));         // 78.54
System.out.printf("%.2f%n", area(new Rectangle(4, 6)));   // 24.00

레코드 직렬화

레코드는 Serializable을 구현하도록 선언하면 자연스럽게 직렬화할 수 있습니다. JSON 라이브러리(Jackson, Gson)와도 별도의 설정 없이 잘 작동합니다.

// With Jackson (add @JsonProperty if needed)
import com.fasterxml.jackson.databind.ObjectMapper;

record OrderSummary(String orderId, double total, String status) {}

ObjectMapper mapper = new ObjectMapper();
OrderSummary order = new OrderSummary("ORD-001", 149.99, "SHIPPED");

String json = mapper.writeValueAsString(order);
System.out.println(json);
// {"orderId":"ORD-001","total":149.99,"status":"SHIPPED"}

OrderSummary restored = mapper.readValue(json, OrderSummary.class);
System.out.println(order.equals(restored)); // true

중첩 레코드

레코드는 다른 레코드를 컴포넌트로 포함하여 풍부하고 변경할 수 없는 객체 그래프를 구성할 수 있습니다.

record Address(String street, String city, String country) {}
record Customer(long id, String name, Address address) {}

Address addr = new Address("123 Main St", "New York", "US");
Customer customer = new Customer(1L, "Alice", addr);

System.out.println(customer.name());              // Alice
System.out.println(customer.address().city());   // New York
System.out.println(customer);                    // Customer[id=1, name=Alice, address=Address[street=123 Main St, city=New York, country=US]]

레코드의 제한 사항

레코드에는 알아 두어야 할 몇 가지 제한이 있습니다:

  • 다른 클래스를 확장할 수 없습니다(암시적으로 Record를 확장합니다)
  • 컴포넌트는 항상 final이므로 변경 가능한 상태를 가질 수 없습니다
  • 컴포넌트 목록 외부에 인스턴스 필드를 선언할 수 없습니다
  • abstract로 선언할 수 없습니다
// Records CAN have static fields and methods
record Temperature(double celsius) {
    static final double ABSOLUTE_ZERO = -273.15;

    public double toFahrenheit() {
        return celsius * 9.0/5.0 + 32;
    }

    public static Temperature fromFahrenheit(double f) {
        return new Temperature((f - 32) * 5.0/9.0);
    }
}
System.out.println(Temperature.fromFahrenheit(98.6)); // Temperature[celsius=37.0]

빠른 확인

Java 컴파일러는 레코드에 어떤 멤버를 자동으로 생성하나요?

복습: 레코드 소개

핵심 내용:

  • 레코드는 반복 코드를 최소화하면서 변경할 수 없는 데이터 전달 객체를 선언합니다
  • 자동 생성 항목: canonical 생성자, 접근자, equals, hashCode, toString
  • 컴포넌트는 final이므로 레코드는 설계상 변경할 수 없습니다
  • 레코드는 인터페이스를 구현할 수 있지만 클래스를 확장할 수 없습니다
  • DTO, 값 객체, API 응답에 적합합니다
  • 구조적 동등성 덕분에 HashMap의 키와 HashSet의 요소로 올바르게 작동합니다

자주 묻는 질문

“레코드 소개” 강의는 무료인가요?

네 — “레코드 소개” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“레코드 소개”에서 뭘 배우나요?

레코드를 간결한 불변 데이터 보유자로 선언하고 자동 생성되는 구성 요소를 이해합니다. 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Java Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.

“레코드 소개” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 레코드 소개
  2. 간결한 생성자와 유효성 검사
  3. 레코드의 사용자 정의 메서드
  4. 레코드, 클래스, Lombok 비교
← Java Academy(으)로 돌아가기