인프런/실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java

2) 자바 어플리케이션을 코틀린으로 리팩토링(2)

backend dev 2025. 1. 15.

 

Optional 처리 , findById 처리, 반복되는 로직 처리

 

 

코틀린에서는 ?를 이용하여 해당 타입의 nullable 여부를 정하니까

 

interface BookRepository : JpaRepository<Book, Long> {

    fun findByName(bookName: String): Book?
}

반환값을 Optional이 아닌 Book?으로 해서 nullable하다는걸 정의할 수있다.

 

@Transactional
fun returnBook(request: BookReturnRequest) {
    val user = userRepository.findByName(request.userName) ?: throw IllegalArgumentException()
    user.returnBook(request.bookName)
}

 

Elvis연산자인 ?: 를 이용하여 null이라면 뒤의 동작을 하게끔해서 예외처리를 한다. 

 

하지만 

?: throw IllegalArgumentException()

이런 코드가 반복되는것을 확인할 수 있고

 

 

다음과 같이 리팩토링 할 수있다.

유틸용 코틀린파일을 생성하고

package com.group.libraryapp.util

fun fail(): Nothing {
    throw IllegalArgumentException()
}

다음과 같이 코드를 구성한후

@Transactional
fun deleteUser(name: String) {
    val user = userRepository.findByName(name) ?: fail()
    userRepository.delete(user)
}

이런식으로 사용할 수 있다.

 

코드가 깔끔해지며, null에 대한 처리를 한곳에서 정의하고 사용할 수 있다.

 

 

 

그리고 아직 findById에 대해서는 리팩토링을 진행하지못했다.

 

spring data jpa에서 기본 제공하고있는 findById 같은 함수 경우

 

Optional을 반환하고 있기 때문이다. 

null을 반환해야 ?: fail()로 코드가 수정이 가능하다.

 

스프링에서는 해당 문제를 해결하기 위해 확장함수를 만들어 놨다.

@Transactional
fun updateUserName(request: UserUpdateRequest) {
    val user = userRepository.findByIdOrNull(request.id) ?: fail()
    user.updateName(request.name)
}

 

해당 함수를 사용해서 해결 가능하다.

 

 

추가적으로 

fun<T,ID>CrudRepository<T,ID>.findByIdOrThrow(id:ID): T{
    return this.findByIdOrNull(id) ?: fail()
}

 

직접 CrudRepository의 확장함수를 정의한다면

@Transactional
fun updateUserName(request: UserUpdateRequest) {
    val user = userRepository.findByIdOrThrow(request.id)
    user.updateName(request.name)
}

 

뒤에 fail부분까지 줄일 수 있다.

 

 

 

 

 

댓글