본문 바로가기

TIL

TIL) Kotlin : runCatching, DTO/Entity 작성 팁

1. Kotlin : runCatching

 

runCatching 은 try-catch 를 대체할 수 있는 코틀린의 문법이다.

 

결론부터 말하면, try-catch 문은 실패시의 핸들링을 처리할 수 있었다면, runCatching 은 성공시, 실패시 둘 다 처리할 수 있다.

 

@InlineOnly
@SinceKotlin("1.3")
public inline fun <T, R> T.runCatching(block: T.() -> R): Result<R> {
    return try {
        Result.success(block())
    } catch (e: Throwable) {
        Result.failure(e)
    }
}

 

보다시피, 리턴 타입은 Result 라는 객체이며, 

전달받은 내용을 실행해서, 

성공한다면 Result.success() 를 통해 성공했다는 내용을 담은 Result 객체,

실패한다면 Result.failure() 를 통해 에러 내용을 담은 Result 객체를 반환한다.

 

기본 문법

  • runCatching { } : 중괄호 안에 try 하고자 하는 구문을 작성
  • onSuccess { } : 위 runCatch 구문이 성공시 매핑할 구문을 작성. it 은 위 구문의 결과.
  • onFailure { } : 위 runCatch 구문이 실패시 매핑할 구문을 작성. it 은 위 구문에서 던진 Throwable 객체.
  • also { } : 기존 try-catch-finally 에서 finally 에서 작성하던 구문을 작성할 수 있음.

 

복잡한 상황

  • map { } : 성공한 값에 대해 한번더 가공이 가능. 여기서 예외가 발생하면 runCatching 구문 밖으로 예외를 던짐.
  • mapCatching { } : 성공한 값에 대해 한번더 가공이 가능. 여기서 예외가 발생하면 runCatching 구문 밖으로 예외를 던지지 않고, 그 예외를 담은 Result 객체 반환. 이후 onFailure 등으로 다시 잡아서 처리가능.
  • recover { } : 실패한 값에 대해 한번더 핸들링이 가능. 여기서 예외가 발생하면 runCatching 구문 밖으로 예외를 던짐.
  • recoverCatching { } :실패한 값에 대해 한번더 핸들링이 가능. 여기서 예외가 발생하면 runCatching 구문 밖으로 예외를 던지지 않고, 그 예외를 담은 Result 객체 반환. 이후 onFailure 등으로 다시 잡아서 처리가능.

 

runCatching 구문의 return 값이 필요할때

  • getOrNull() : 위에서 반환된 Result 객체가 성공객체 일 때 값 반환. 실패면 null
  • getOrDefault(~) : 위에서 반환된 Result 객체가 성공객체 일 때 값 반환. 실패면 뒤에 정의한 값 반환.
  • getOrThrow() : 위에서 반환된 Result 객체가 성공객체 일 때 값 반환. 실패면 Result 객체의 예외 throw.
  • getOrElse { } : 위에서 반환된 Result 객체가 성공객체 일 때 값 반환. 실패면 뒤에 정의한 구문 실행.

 

Result 객체는 함수의 반환형으로 쓰일 수 없다.

https://rannte.tistory.com/entry/kotlinruncatching

 

[번역][Kotlin] Try-catch를 쓰기 힘들다면 runCatching을 써보자! - Qiita

ㅅException이 Throw여부에 따라 각각 어떤 코드를 실행하고 싶을때가 있죠. try-catch(-finally)로 구현하기 힘들때가 있습니다. try-catch(-finally)는 Exception이 Throw되었을때의 처리(또는 throw여부에..

rannte.tistory.com

 

 

 

 

 

2. DTO/Entity 작성 팁

 

Entity

  1. DB 에 걸려있는 제약조건과 같이 맞춰준다. (nullable, unique ... )
  2. 객체 생성 제약
    1. @NoArgsConstructor(access = AccessLevel.PROTECTED) 과 같은 롬복 에너테이션으로 객체의 직접 생성을 외부에서 하지 못하게 제약할 수 있다.
    2. 직접 생성을 하지 못하고, 빌더패턴이나 정적 팩터리 메서드 패턴을 사용해서 생성할 수 있게 할 수 있다.
      1. 빌더패턴과 정적 팩터리 메서드 패턴의 장점은 이펙티브 자바 1, 2장에 자세히 나와 있다.

 

 

Dto

  1. RequestBody / ResponseBody 를 Entity 객체로 바로 받지 말고, DTO 로 받자.
    1. 해당 요청에 필요한 정보만 취급하는 것이 안전하다. 예를 들어 User 객체의 이름을 바꾸는 API 에는 id 값과 비밀번호, 바꿀 이름만 필요할 것이다.
    2. 응답도 마찬가지.
  2. setter 를 이용한 변경보단 dto 를 이용한 변경.
    1. JPA 를 사용하면 setter 로 객체의 값을 바꾸면 값이 변경된다. 
      1. 모든 setter 가 있는 필드들이 변경가능한 상태가 된다. -> 추적할 포인트가 많아진다.
      2. 기획의도상 변경가능하지 못하는 필드도 변경가능한 상태가 된다.
    2. DTO를 통해 값을 변경하자.
      1. 엔티티 객체에 DTO 를 받아서 자기 값을 수정하는 메서드를 작성한다
        1. -> 객체지향적 관점에서도 객체의 상태를 바꾸는 동작은 객체 자신에게 있는게 맞다.
        2. 원하는 값을 수정하는 특정 메서드를 만듦으로서 객체의 수정 포인트를 한정지을 수 있다.

 

// Entity 클래스에 DTO 를 이용해서 변환 메서드 추가
fun updateName(dto: UserDto) {
	this.name = dto.name
}


// 서비스 로직
fun updateName(dto: UserDto): User {
	val user = findById(dto.id)
    user.updateName(dto) // 위 메서드를 이용
    return user
}

https://cheese10yun.github.io/spring-jpa-best/

 

Spring-Jpa Best Practices Step-01 - REST API - Yun Blog | 기술 블로그

Spring-Jpa Best Practices Step-01 - REST API - Yun Blog | 기술 블로그

cheese10yun.github.io