Backend/Kotlin

[Kotlin] 확장함수 언제 어떻게 사용해야 할까?

findmypiece 2021. 12. 24. 11:08
728x90

코틀린에는 확장함수 라는 기능이 있다. 자바에서는 메소드를 사용할 때 파라미터는 반드시 메소드의 인자로 포함되어야 한다. 즉, 호출 단계에서 메소드가 우선 작성되고 재료가 되는 파라미터가 그곳에 포함되는 방식이다. 

 

예를 들면 아래와 같다.

public String format(LocalDate localDate, String pattern){
	return localDate.format(DateTimeFormatter.ofPattern(format));
}

String dateStr = format(LocalDate.now(), "yyyy-MM-dd")

 

코틀린에서도 위와 같은 방식으로 구현해도 되지만 아래와 같이 확장함수 방식으로 구현할 수도 있다.

fun LocalDate.format(pattern: String): String = this.format(DateTimeFormatter.ofPattern(pattern))

val dateStr = LocalDate.now().format("yyyy-MM-dd")

특별한 것은 없다. 단지 메소드 호출에 대한 문법적 편의를 제공할 뿐이다. 다만 위의 같은 직렬화 함수의 경우 기존 메소드 방식보다 확장함수를 통해 연결해서 사용하는 것이 더 자연스러워 보인다.

 

확장함수의 또 다른 장점은 기본타입이 모두 null 을 포함하지 않는 코틀린과 궁합이 잘 맞는다는 것이다. 코틀린에서는 자바와 달리 기본타입들이 기본적으로 null 을 포함하고 있지 않다. 자바에서는 String 타입에서 null 과 문자열을 모두 받을 수 있지만 코틀린에서는 String 타입에서 null 은 허용하지 않는다. null 도 받으려면 String? 처럼 정의해야 한다.

 

이에 함수 파라미터 정의시 String 과 같이 하면 명시적으로 null 아닌 데이터만 사용하도록 강제할 수 있다. 이 경우 함수를 호출하는 쪽에서는 파라미터로 사용할 데이터가 null을 포함한 데이터라면 null 이 아닐 경우에만 함수가 호출하도록 처리를 해줘야 하는데 확장함수를 사용할 경우 아래와 같이 ?. 만으로 간단하게 처리가 가능하다.

fun String.parseLocalDate(pattern: String): LocalDate = LocalDate.parse(this, DateTimeFormatter.ofPattern(pattern))

val dateStr? = null

val localDate = dateStr?.parseLocalDate("yyyy-MM-dd")

 

만약 확장함수가 아니라면 아래와 같이 if문을 사용하던가 아래와 같이 let 함수를 활용해야 한다.

fun parseLocalDate(dateStr: String, pattern: String): LocalDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(pattern))

val dateStr? = null

val localDate = dateStr?.let{ parseLocalDate(it, "yyyy-MM-dd") }

 

기존 메소드 방식 외에 확장함수라는 추가 선택지가 생긴 것이고 필요에 따라 이를 적절하게 활용하면 된다. 내가 생각하는 적절한 사용처는 단일 파라미터를 재료로 해서 무언가 처리를 하는 경우이다. 우리가 흔히 정의하는 유틸함수 대부분이 여기에 속할 것이다.

 

하지만 확장함수가 장점만 있는 것은 또 아니다. 위에서 정의한 String.parseLocalDate 를 사용할 때 아래와 같이 모든 String 타입에 대해 기본적으로 IDEA 에 자동완성 기능이 활성화 된다.

 

이에 편의성은 증가했지만 이와 함께 코딩실수를 유발할 수 있는 확률도 증가한 셈이다. 위 함수는 String 타입 중에서도 날짜형 포맷을 가진 데이터에 대해서만 적용되어야 하는데 확장함수에서는 타입을 제한할 순 있지만 실제 값까지 제한하는 방법은 없다.

 

728x90