웹사이트 검색

Java 14 레코드 클래스


Java 14에서는 레코드라는 클래스를 만드는 새로운 방법을 도입했습니다. 이 자습서에서는 다음을 배웁니다.

  • Java 레코드가 필요한 이유
  • 레코드 생성 및 활용 방법
  • 레코드 클래스 재정의 및 확장

권장 자료: Java 14 기능

Java 레코드가 필요한 이유는 무엇입니까?

Java에 대한 일반적인 불만 중 하나는 장황함입니다. 간단한 POJO 클래스를 만들어야 하는 경우 다음과 같은 상용구 코드가 필요합니다.

  • 비공개 필드
  • Getter 및 Setter 방법
  • 생성자
  • hashCode(), equals() 및 toString() 메서드.

이 장황함은 프로젝트 롬복에 대한 관심이 높은 이유 중 하나입니다.

사실, 이러한 일반 메서드를 매번 작성하는 데 따른 순전한 좌절감은 Eclipse 및 IntelliJ IDEA와 같은 Java IDE에서 생성하는 바로 가기로 이어집니다.

다음은 클래스에 대한 의식 메서드를 생성하는 Eclipse IDE 옵션을 보여주는 스크린샷입니다.

Java 레코드는 POJO 클래스를 생성하기 위한 간결한 구조를 제공하여 이러한 장황함을 제거하기 위한 것입니다.

Java 레코드를 만드는 방법

Java 레코드는 JEP 359에 따라 개발된 미리 보기 기능입니다. 따라서 Java 프로젝트에서 레코드를 생성하려면 두 가지가 필요합니다.

  1. JDK 14가 설치되었습니다. IDE를 사용하는 경우 Java 14도 지원해야 합니다. Eclipse와 IntelliJ 모두 이미 Java 14에 대한 지원을 제공하므로 여기까지는 괜찮습니다.
  2. 미리보기 기능 활성화: 기본적으로 미리보기 기능은 비활성화되어 있습니다. Project Java Compiler 설정에서 Eclipse에서 활성화할 수 있습니다.

--enable-preview -source 14 옵션을 사용하여 명령줄에서 Java 14 미리 보기 기능을 활성화할 수 있습니다.

Employee 모델 클래스를 만들고 싶다고 가정해 보겠습니다. 다음 코드와 같이 표시됩니다.

package com.journaldev.java14;

import java.util.Map;

public class Employee {

	private int id;
	private String name;
	private long salary;
	private Map<String, String> addresses;

	public Employee(int id, String name, long salary, Map<String, String> addresses) {
		super();
		this.id = id;
		this.name = name;
		this.salary = salary;
		this.addresses = addresses;
	}

	public int getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public long getSalary() {
		return salary;
	}

	public Map<String, String> getAddresses() {
		return addresses;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((addresses == null) ? 0 : addresses.hashCode());
		result = prime * result + id;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + (int) (salary ^ (salary >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Employee other = (Employee) obj;
		if (addresses == null) {
			if (other.addresses != null)
				return false;
		} else if (!addresses.equals(other.addresses))
			return false;
		if (id != other.id)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		if (salary != other.salary)
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + ", addresses=" + addresses + "]";
	}

}

휴, 70줄 이상의 자동 생성 코드입니다. 이제 기본적으로 동일한 기능을 제공하는 Employee Record 클래스를 만드는 방법을 살펴보겠습니다.

package com.journaldev.java14;

import java.util.Map;

public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
}

와우, 이보다 더 짧을 수는 없습니다. 나는 이미 레코드 수업을 좋아합니다.

이제 javap 명령을 사용하여 레코드가 컴파일될 때 장면 뒤에서 무슨 일이 일어나는지 알아봅시다.

# javac --enable-preview -source 14 EmpRecord.java
Note: EmpRecord.java uses preview language features.
Note: Recompile with -Xlint:preview for details.

# javap EmpRecord      
Compiled from "EmpRecord.java"
public final class EmpRecord extends java.lang.Record {
  public EmpRecord(int, java.lang.String, long, java.util.Map<java.lang.String, java.lang.String>);
  public java.lang.String toString();
  public final int hashCode();
  public final boolean equals(java.lang.Object);
  public int id();
  public java.lang.String name();
  public long salary();
  public java.util.Map<java.lang.String, java.lang.String> addresses();
}
# 

더 자세한 내부 정보를 보려면 -v 옵션과 함께 javap 명령을 실행하십시오.

# javap -v EmpRecord 

레코드 클래스에 대한 중요 사항

  1. 레코드 클래스는 최종 클래스이므로 확장할 수 없습니다.
  2. 레코드 클래스는 암시적으로 java.lang.Record 클래스를 확장합니다.
  3. 레코드 선언에 지정된 모든 필드는 최종 필드입니다.
  4. 레코드 필드는 변경 불가능하고 유형에 따라 다릅니다. 예를 들어 주소 필드에 액세스한 다음 업데이트하여 주소 필드를 변경할 수 있습니다.
  5. 레코드 정의에 지정된 모든 필드로 단일 생성자가 생성됩니다.
  6. Record 클래스는 필드에 대한 접근자 메서드를 자동으로 제공합니다. 메서드 이름은 일반 및 기존 getter 메서드가 아니라 필드 이름과 동일합니다.
  7. Record 클래스는 hashCode(), equals() 및 toString() 구현도 제공합니다.

Java 프로그램에서 레코드 사용

EmpRecord 클래스를 사용하는 간단한 예를 살펴보겠습니다.

package com.journaldev.java14;

public class RecordTest {

	public static void main(String[] args) {
		
		EmpRecord empRecord1 = new EmpRecord(10, "Pankaj", 10000, null);
		EmpRecord empRecord2 = new EmpRecord(10, "Pankaj", 10000, null);

		// toString()
		System.out.println(empRecord1);
		
		// accessing fields
		System.out.println("Name: "+empRecord1.name()); 
		System.out.println("ID: "+empRecord1.id());
		
		// equals()
		System.out.println(empRecord1.equals(empRecord2));
		
		// hashCode()
		System.out.println(empRecord1 == empRecord2);		
	}
}

산출:

EmpRecord[id=10, name=Pankaj, salary=10000, addresses=null]
Name: Pankaj
ID: 10
true
false

Record 개체는 모든 모델 클래스, 데이터 개체 등과 동일한 방식으로 작동합니다.

레코드 생성자 확장

때때로 우리는 생성자에 대한 유효성 검사 또는 로그인을 원합니다. 예를 들어 직원 ID와 급여는 음수가 아니어야 합니다. 기본 생성자에는 이 유효성 검사가 없습니다. 레코드 클래스에서 소형 생성자를 만들 수 있습니다. 이 생성자의 코드는 자동 생성 생성자의 시작 부분에 배치됩니다.

public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
	
	public EmpRecord {
		if (id < 0)
			throw new IllegalArgumentException("employee id can't be negative");

		if (salary < 0)
			throw new IllegalArgumentException("employee salary can't be negative");
	}

}

다음 코드와 같이 EmpRecord를 생성하는 경우:

EmpRecord empRecord1 = new EmpRecord(-10, "Pankaj", 10000, null);

다음과 같이 런타임 예외가 발생합니다.

Exception in thread "main" java.lang.IllegalArgumentException: employee id can't be negative
	at com.journaldev.java14.EmpRecord.<init>(EmpRecord.java:9)

레코드 클래스에 메서드가 있을 수 있습니까?

예, 레코드에 메서드를 만들 수 있습니다.

public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {

	public int getAddressCount() {
		if (this.addresses != null)
			return this.addresses().size();
		else
			return 0;
	}
}

그러나 레코드는 데이터 매체를 의미합니다. 레코드 클래스에 유틸리티 메서드가 있는 것을 피해야 합니다. 예를 들어 위의 메서드는 유틸리티 클래스에서 만들 수 있습니다.

레코드 클래스에 메서드가 있어야 한다고 생각한다면 레코드 클래스가 정말 필요한지 신중하게 생각해야 할까요?

결론

Java 레코드는 핵심 프로그래밍 기능에 환영받는 추가 기능입니다. 이것을 "명명된 튜플\이라고 생각할 수 있습니다. 이것은 모든 상용구 코드를 피하면서 압축된 구조로 데이터 캐리어 객체를 생성하기 위한 것입니다.