Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
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
Archives
Today
Total
관리 메뉴

그리미

자바 Record 에 관해서 본문

카테고리 없음

자바 Record 에 관해서

시앤시 2024. 7. 7. 02:22

 

안정적인 프로그래밍을 위해선 불변 객체가 중요하다.

 

Record 를 활용하면 이러한 불변 객체를 만들 수 있으며,

 

개발자가 별도의 toString, hashcode, equals 와 같은 메서드를 만들지 않아도 되는 장점이 있다.

 

사전에 정의된 메서드를 INVOKEDYNAMIC 하기 때문이다.

 

간단히 작성된 학생 클래스로 클래스와 레코드를 비교해보겠습니다.

public class Student {
	private String name;
	private Integer age;

	public Student(String name, Integer age) {
		this.name = name;
		this.age = age;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o)
			return true;
		if (o == null || getClass() != o.getClass())
			return false;
		Student student = (Student)o;
		return Objects.equals(name, student.name) && Objects.equals(age, student.age);
	}

	@Override
	public int hashCode() {
		return Objects.hash(name, age);
	}
}

public record RStudent(
	String name,
	Integer age
) {
}

 

hashcode와 equals 만 바이트코드를 디컴파일해서 확인해보자

// Student 클래스

 public equals(Ljava/lang/Object;)Z
    // parameter  o
   L0
    LINENUMBER 16 L0
    ALOAD 0
    ALOAD 1
    IF_ACMPNE L1
   L2
    LINENUMBER 17 L2
    ICONST_1
    IRETURN
   L1
    LINENUMBER 18 L1
   FRAME SAME
    ALOAD 1
    IFNULL L3
    ALOAD 0
    INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
    ALOAD 1
    INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
    IF_ACMPEQ L4
   L3
    LINENUMBER 19 L3
   FRAME SAME
    ICONST_0
    IRETURN
   L4
    LINENUMBER 20 L4
   FRAME SAME
    ALOAD 1
    CHECKCAST com/c4/week5/Test/Student
    ASTORE 2
   L5
    LINENUMBER 21 L5
    ALOAD 0
    GETFIELD com/c4/week5/Test/Student.name : Ljava/lang/String;
    ALOAD 2
    GETFIELD com/c4/week5/Test/Student.name : Ljava/lang/String;
    INVOKESTATIC java/util/Objects.equals (Ljava/lang/Object;Ljava/lang/Object;)Z
    IFEQ L6
    ALOAD 0
    GETFIELD com/c4/week5/Test/Student.age : Ljava/lang/Integer;
    ALOAD 2
    GETFIELD com/c4/week5/Test/Student.age : Ljava/lang/Integer;
    INVOKESTATIC java/util/Objects.equals (Ljava/lang/Object;Ljava/lang/Object;)Z
    IFEQ L6
    ICONST_1
    GOTO L7
   L6
   FRAME APPEND [com/c4/week5/Test/Student]
    ICONST_0
   L7
   FRAME SAME1 I
    IRETURN
   L8
    LOCALVARIABLE this Lcom/c4/week5/Test/Student; L0 L8 0
    LOCALVARIABLE o Ljava/lang/Object; L0 L8 1
    LOCALVARIABLE student Lcom/c4/week5/Test/Student; L5 L8 2
    MAXSTACK = 2
    MAXLOCALS = 3

  // access flags 0x1
  public hashCode()I
   L0
    LINENUMBER 26 L0
    ICONST_2
    ANEWARRAY java/lang/Object
    DUP
    ICONST_0
    ALOAD 0
    GETFIELD com/c4/week5/Test/Student.name : Ljava/lang/String;
    AASTORE
    DUP
    ICONST_1
    ALOAD 0
    GETFIELD com/c4/week5/Test/Student.age : Ljava/lang/Integer;
    AASTORE
    INVOKESTATIC java/util/Objects.hash ([Ljava/lang/Object;)I
    IRETURN
   L1
    LOCALVARIABLE this Lcom/c4/week5/Test/Student; L0 L1 0
    MAXSTACK = 4
    MAXLOCALS = 1
}

 

// RStudent 레코드 클래스

 

앞서 언급했듯 레코드는 사전 정의된 메서드를 INVOKEDYNAMIC 하다보니, 

클래스에 비해 가볍다

 

equals 와 hashcode 가 자주 호출되는 set 에 넣는 실험을 통해 

이게 성능상 어떤 영항을 주는 지 확인해보자.

 

먼저 Student 객체를 넣어보겠다.

일반 객체를 Set에 넣었을 떄

다음으론 RStudent (Recored 클래스) 를 넣어보겠다.

레코드 객체를 Set 에 넣었을 때

 

각각 50번의 실험 결과

종류 속도
Student 클래스 (일반 클래스) 1.71 ~ 1.85초
RStudent 클래스 (Record 클래스) 1.25 ~ 1.39초

 

RStudentStudent 보다

대략 35% 정도 더 빠른 것을 확인 할 수 있다.