KotlinInAction/함수 정의와 호출

함수를 호출하기 쉽게 만들기

webmaster 2022. 7. 26. 18:43
728x90
fun main(args: Array<String>) {
    val list = listOf(1, 2, 3)
    println(list) //[1,2,3]
}
  • 컬렉션에는 toString이 구현이 되어있다
  • 디폴트 toString이 아닌 다른 toString을 쓰고 싶다면 어떻게 해야 할까
  • 자바에서는 구아바나 아파치 커먼즈 같은 서드파티 프로젝트를 추가하거나 직접 관련 로직을 구현해야 한다.
  • 코틀린에서는 이런 요구사항을 해결할 수 있는 함수가 표준 라이브러리에 존재한다.
fun main(args: Array<String>) {
    val list = listOf(1, 2, 3)
    println(joinToString(list, "; ", "(", ")"))
}

fun <T> joinToString(
    collection: Collection<T>, separator : String, prefix: String, postfix : String
) :String {
    val result = StringBuilder(prefix)
    for((index, element) in collection.withIndex()){
        if(index > 0) result.append(separator) //첫 원소 구분자 안붙힌다
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}

너무 복잡하다. -> 4인자를 모두 전달하지 않을 수 없을까?

이름 붙인 인자

해결하고자 하는 첫 조건은 가독성이다 -> 인자로 전달한 각 문자열이 어떤 역할을 하는지 구분할 수가  없다

함수의 시그니처를 봐야지만 알 수 있다(IDE의 힘을 빌리면 가능하지만 함수 호출 코드 자체는 모호하다)

아래와 같이 주석을 남길 수도 있지만 코드가 지저분하다

println(joinToString(list, /* separator */"; ", /* prefix */"(", /* postfix */")"))

코틀린에서는 아래와 같이 가능하다

println(joinToString(list, separator = "; ", prefix = "(", postfix = ")"))
  • 코틀린으로 작성한 함수를 호출할 때는 함수에 전달하는 인자 중 일부의 이름을 명시할 수 있다.
  • 하나라도 이름을 명시했다면 그 뒤에 오는 모든 인자는 이름을 꼭 명시해야 한다
  • 이름 붙인 인자는 디폴트 파라미터 값과 함께 사용할 때 쓸모가 많다

디폴트 파라미터 값

자바에서는 오버 로딩한 메서드가 너무 많아지는 단점이 있다

이런 식의 메서드 들은 하위 호환성을 유지하거나 API 사용자에게 편의를 더하는 등의 이유로 만들어진다

단, 어떤 식의 경우라도 중복이라는 결과는 같으며, 파라미터의 이름, 타입이 반복되고, 모든 오버 로딩 메서드에 설명을 달아야 한다

그리고 인자 중 일부가 생략된 오버로드 함수를 호출할 때는 어떤 함수가 불릴지 모호한 경우가 생긴다

 

fun main(args: Array<String>) {

    println(joinToString(list, ", ", "", ""))
    println(joinToString(list))
    println(joinToString(list, "; "))
}

fun <T> joinToString(
    collection: Collection<T>,
    separator: String = ", ",
    prefix: String = "",
    postfix: String = ""
): String {
    val result = StringBuilder(prefix)
    for ((index, element) in collection.withIndex()) {
        if (index > 0) result.append(separator) //첫 원소 구분자 안붙힌다
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}
  • 코틀린에서는 디폴트 파라미터 값을 지정할 수 있다
  • 모든 인자를 쓸 수도 있고 일부를 생략할 수도 있다
println(joinToString(list, postfix = "; ", prefix = "#"))
  • 일반호출 문법을 사용하려면 함수를 선언할 때와 같은 순서로 인자를 지정해야 한다
    • 뒷부분의 인자들이 생략된다
  • 이름 붙인 인자를 사용하는 경우에는 인자 목록의 중간에 있는 인자를 생략하고 , 지정하고 싶은 인자를 이름을 붙여서 순서와 관계없이 지정할 수 있다
  • 함수의 디폴트 파라미터 값은 함수를 호출하는 쪽이 아니라 함수 선언 쪽에서 지정되는 것을 기억해라
    • 어떤 클래스 안에 정의된 함수의 디폴트 값을 바꾸고 그 클래스가 포함된 파일을 재 컴파일하면 그 함수를 호출하는 코드 중에 값을 지정하지 않은 모든 인자는 자동으로 바뀐 디폴트 값을 적용받는다
  • 자바에서 코틀린 함수를 자주 호출할 경우 @JvmOverloads 어노테이션을 함수에 추가하면 된다
    • 코틀린 컴파일러가 자동으로 맨 마지막 파라미터로부터 파라미터를 하나씩 생략한 오버 로딩한 자바 메서드를 추가해준다

최상위 함수

다양한 정적 메서드를 모아두는 역할만 담당하며 특별한 상태나 인스턴스 메서드는 없는 클래스가 필요할 때가 있다.

JDK에서의 Collection 클래스가 대표적인 예이다.

//join.kt 파일
fun <T> joinToString(
   ...
): String {
   ...
}
  • 코틀린에서는 무의미한 클래스가 필요 없다
    • 함수를 직접 소스 파일의 최상위 수준, 모든 다른 클래스의 밖에 위치시키면 된다.
    • 다른 패키지에서 함수를 사용하고 싶을 때는 그 함수가 정의된 패키지를 임포트 하면 된다.
  • JVM이 클래스 안에 들어있는 코드만을 실행할 수 있기 때문에 컴파일러는 이 파일을 컴파일할 때 새로운 클래스를 정의해준다.

자바 코드

public class JoinKt{
	public static String joinToString(...){ ...}
}

 

  • 코틀린 컴파일러가 생성하는 클래스의 이름은 최상위 함수가 들어있던 코틀린 소스 파일 이름과 대응한다.
  • 코틀린 파일의 모든 최상위 함수는 이 클래스의 정적인 메서드가 된다.
  • 자바에서도 JoinKt.joinToString(..) 와 같이 호출하면 된다.
  • 코틀린에서 최상위 함수가 포함되는 클래스의 이름을 바꾸고 싶다면 파일에 @JvmName 애노테이션을 추가하자
    • 파일의 맨 앞, 패키지 이름 선언 이전에 위치해야 한다

최상위 프로퍼티

var opCount = 0

fun performOperation(){
    opCount++
}

fun reportOperationCount(){
    println("Operation performed $opCount times")
}
  • 최상위 프로퍼티의 경우 정적필드에 저장된다.
  • 최상위 프로퍼티를 활용해 코드에 상수를 추가할 수 있다
  • 최상위 프로퍼티도 다른 프로퍼티 처럼 접근자 메서드를 통해 자바 코드에 노출된다
    • val 같은 경우 getter, var 같은 경우 setter, getter 
  • public static final 로 상수를 정의해야 상수처럼 사용이 가능하다
    • const를 사용하여 public static final 필드로 컴파일이 가능하도록 하자
const val UNIX_LINE_SEPARATOR = "\n"

//자바
public static final UNIX_LINE_SEPARATOR = "\n"
728x90

'KotlinInAction > 함수 정의와 호출' 카테고리의 다른 글

로컬 함수와 확장  (0) 2022.07.29
문자열과 정규식 다루기  (0) 2022.07.29
컬렉션 처리  (0) 2022.07.28
확장 함수와 확장 프로퍼티  (0) 2022.07.27
코틀린에서 컬랙션 만들기  (0) 2022.07.26