728x90
반응형
✅ 오늘의 학습 정리
- INNER JOIN과 LEFT JOIN의 차이를 이해하고, 데이터 조회 시 상황에 맞게 사용할 수 있도록 함.
- containOrNull()을 사용하여 리스트 내 요소를 안전하게 검색하고, 없을 경우 null을 반환하는 방식 학습.
- 리플렉션을 활용한 setPrivateField() 구현 및 이슈 해결
- 리플렉션이 예상대로 동작하지 않을 수 있는 문제를 발견하고 generateSequence를 활용해 해결.
- @MappedSuperclass를 활용한 공통 엔티티 관리 방법 학습
- 테이블이 생성되지 않는 특성과 상속을 통해 코드 중복을 줄이는 방식을 배움.
- generateSequence의 활용 방법
- 무한 시퀀스 생성 및 부모 클래스 탐색 등 다양한 활용법 익힘.
🔹 1. INNER JOIN vs LEFT JOIN 차이
- INNER JOIN: 두 테이블 간 공통된 데이터를 기준으로 교집합을 반환한다. (일치하는 행만 가져옴)
- LEFT JOIN: 왼쪽 테이블의 모든 데이터를 기준으로 하며, 오른쪽 테이블에 매칭되는 데이터가 없으면 NULL을 반환한다. (왼쪽 테이블 기준으로 모든 데이터를 가져옴)
- 비즈니스 활용 예시: 특정 엔티티와 연관된 데이터를 조회할 때, 연관 데이터가 필수인 경우 INNER JOIN을 사용하고, 선택적인 경우 LEFT JOIN을 사용한다.
🔹 2. containOrNull
- 리스트나 컬렉션에서 특정 요소를 포함하는지 확인하고, 없을 경우 null을 반환하는 함수.
- 활용 예시
fun List<String>.containOrNull(value: String): String? = this.find { it == value }
val items = listOf("apple", "banana", "cherry")
val result = items.containOrNull("banana") // "banana"
val notFound = items.containOrNull("grape") // null
기존의 contains()는 Boolean을 반환하는 반면, containOrNull()은 실제 값을 반환하거나 null을 반환한다.
🔹 3. setPrivateField() 리플렉션 이슈
📌 이슈 개요
- 부모 클래스를 따라가며 필드를 찾도록 했지만, 가끔 특정 필드를 찾지 못하는 경우 발생.
- 특정 환경에서는 리플렉션이 예상대로 동작하지 않아 NoSuchFieldException이 발생하기도 함.
- 필드가 존재하는데도 getDeclaredField()가 실패하는 문제 발생.
📌 해결 방법
- 안정적인 필드 탐색을 위해 generateSequence 활용
- Kotlin 리플렉션(kotlin.reflect.full)과 Java 리플렉션(java.lang.reflect)의 차이 고려
- 부모 클래스까지 안전하게 탐색하도록 수정
fun <T : Any> T.setPrivateField(fieldName: String, value: Any) {
generateSequence(this::class.java) { it.superclass }
.firstOrNull { it.declaredFields.any { field -> field.name == fieldName } }
?.getDeclaredField(fieldName)
?.apply {
isAccessible = true
set(this@setPrivateField, value)
} ?: throw NoSuchFieldException("Field $fieldName not found in class hierarchy of ${this::class.simpleName}")
}
이점:
- generateSequence를 활용해 부모 클래스를 자동으로 탐색
- 불필요한 예외 처리 없이, 필드가 존재하는 클래스만 찾을 수 있도록 개선
🔹 4. @MappedSuperclass
- JPA에서 상속을 위한 어노테이션
- 공통 필드를 가지는 부모 클래스를 정의할 때 사용하며, 실제 테이블을 생성하지 않는다.
@MappedSuperclass
open class BaseEntity {
@Column(name = "created_at")
var createdAt: LocalDateTime? = null
@Column(name = "created_by")
var createdBy: String? = null
}
@Entity
class User : BaseEntity() {
@Id
@GeneratedValue
var id: Long? = null
}
이점:
- 공통 속성을 관리할 때, 코드 중복을 줄일 수 있음
- @Entity 대신 @MappedSuperclass를 사용하면 해당 클래스의 테이블이 생성되지 않음
🔹 5. generateSequence
- Kotlin에서 무한 시퀀스를 생성할 때 사용
- 지연 계산을 통해 메모리를 효율적으로 사용할 수 있음
📌 활용 예시 1: 숫자 생성기
val sequence = generateSequence(1) { it + 1 } // 1, 2, 3, 4, ...
println(sequence.take(5).toList()) // [1, 2, 3, 4, 5]
📌 활용 예시 2: 부모 클래스 탐색
generateSequence(this::class.java) { it.superclass }
.takeWhile { it != Any::class.java }
.forEach { println(it.simpleName) }
- 현재 객체의 클래스부터 시작해 상위 클래스를 차례로 탐색
- takeWhile을 활용해 Any::class.java에 도달하면 중단
728x90
반응형
'Blog > TIL' 카테고리의 다른 글
2025-03-14 (금) (0) | 2025.03.14 |
---|---|
2025-03-13 (목) (0) | 2025.03.13 |
2025-03-10 (월) (1) | 2025.03.10 |
2025-03-07 (금) (2) | 2025.03.07 |
2025-03-06 (목) (0) | 2025.03.06 |
댓글