본문 바로가기
공부/Kotlin

3장. 함수 정의와 호출

by JERO__ 2022. 6. 7.

다루는 내용

  • 컬렉션, 문자열, 정규식 다루기 위한 함수
  • 이름 붙인 인자, 디폴트 파라미터 값, 중위 호출 문법
  • 확장 함수, 확장 프로퍼티를 사용해 자바 라이브러리 적용
  • 최상위 및 로컬 함수와 프로퍼티를 사용해 코드 구조화

컬렉션 만들기

setOf vs hashSetOf

  • setOf : immutable
  • hash : mutable
val setOfStrings: Set<String> = setOf("A", "B", "C")
val hashSetOfStrings: HashSet<String> = hashSetOf("A", "B", "C")

컬렉션만들기

  • 리스트
val list = arrayListOf(1, 7, 13)
val map = hashMapOf(1 to "one", 7 to "seven")

모두 java.util 에서 지원하는 것

코틀린이 자신만의 컬렉션 기능을 제공하지 않는다. 기존 자바 컬렉션을 활용한다. 코틀린이 자체 컬렉션을 제공하지 않는 이유는?

  • 표준 자바 컬렉션을 활용하면 자바 코드와 상호작용하기 쉽다.
  • 서로 변환할 필요 없다.

함수 호출 쉽게 만들기

1. 이름 붙인 인자

리스트 출력시 default 출력 형식인 [1, 2, 3] 을 고치기

fun <T> joinToString(
    collection: Collection<T>,
    separator: String,
    prefix: String,
    postfix: String
): String {
    val result = StringBuilder(prefix)
    for ((index, value) in collection.withIndex()) {
        if (index > 0) result.append(separator)
        result.append(value)
    }
    result.append(postfix)
    return result.toString()
}
  • 사용 (1;2;3)
val list = listOf(1, 2, 3)
print(joinToString(list, ";", "(", ")"))

→ 각 문자열이 어떤 역할을 하는지 구분할 수 있는가? 함수 호출 코드 자체는 여전히 모호하다.

  • 개선하기
val list = listOf(1, 2, 3)
print(joinToString(list, separator = ";", prefix = "(", postfix = ")"))

→ 호출 시 인자 중 하나라도 이름을 명시한다면, 혼동을 막기 위해 모든 인자에 이름을 명시하자.

2. 디폴트 파라미터 사용하기

fun <T> joinToString(
    collection: Collection<T>,
    separator: String = ";",
    prefix: String = "(",
    postfix: String = ")"
): String {}
  • 함수 선언쪽에서 지정된다.

3. 정적인 유틸 클래스 없애기 : 최상위 함수, 최상위 프로퍼티

  • 코틀린에서는 무의미한 클래스가 없다.
    • 자바에서는 utils와 같이 다양한 정적 메서드를 모아두는 역할만 담당하고, 특별한 상태나 인스턴스 메서드는 없는 클래스가 생긴다.
  • 함수를 소스 파일의 최상위 수준, 모든 다른 클래스의 밖에 위치시킨다.

최상위함수 : 클래스가 없다

package strings

fun <T> joinToString(
    collection: Collection<T>,
    separator: String = ";",
    prefix: String = "(",
    postfix: String = ")"
): String {
    val result = StringBuilder(prefix)
    for ((index, value) in collection.withIndex()) {
        if (index > 0) result.append(separator)
        result.append(value)
    }
    result.append(postfix)
    return result.toString()
}

최상위 프로퍼티

var opCount = 0
fun perFormOperation() {
    opCount++
}

확장함수와 확장프로퍼티

확장함수

어떤 클래스의 멤버 메서드인 것처럼 호출할 수 있지만, 그 클래스 밖에 선언된 함수

fun String.lastChar(): Char = this.get(this.length - 1)
println("kotlin".lastChar())
// this 없이 사용 가능하다.
fun String.lastChar(): Char = get(length - 1)
  • 확장함수는 오버라이드할 수 없다.
    • 확장 함수는 클래스 밖에 선언된다. (정적)

확장 프로퍼티

  • 상태를 저장할 적절한 방법이 없다.
  • 아무 상태도 가질 수 없다.
var StringBuilder.lastChar: Char
    get() = get(length - 1)
    set(value: Char) {
        this.setCharAt(length - 1, value)
    }

// main
val sb = StringBuilder("kotlin?")

println(sb.lastChar)   // ?
sb.lastChar = '!'
println(sb)            // kotlin!
  • 게터는 꼭 정의해야 한다.
  • 초기화가 필요없다.

컬렉션 처리

중위 호출

메서드 인자 사이에 메서드 이름을 넣는다.

다음 두 호출은 동일하다

// to 함수는 Pair를 반환한다. key, value에도 초기화가 가능하다.
1.to("one")
1 to "one"

문자열 나누기

println("12.345-6.A".split(".", "-"))
// [12, 345, 6, A]

3중 따옴표로 묶은 문자열

  • \\가 필요없다.
  • 일반문자열 : C:\\\\Users\\\\yole\\\\kotlin-book
"""C:\\Users\\yole\\kotlin-book"""

로컬 함수 중복 제거

  • 중복된 코드
fun saveUser(user: User) {
    if (user.name.isEmpty()) {
        throw IllegalArgumentException("ERROR")
    }
    is (user.address.isEmpty()){
        throw IllegalArgumentException("ERROR")
    }
}
  1. 로컬 함수
fun saveUser(user: User) {
    fun validate(value: String) {
        if (value.isEmpty()) {
            throw IllegalArgumentException("ERROR")
        }
    }
    validate(user.name)
    validate(user.address)
}
  1. 로컬함수 → 확장함수
fun saveUser(user: User) {
    user.validateBeforSave()
}

fun User.validateBeforSave() {
    fun validate(value: String) {
        if (value.isEmpty()) {
            throw IllegalArgumentException("ERROR")
        }
    }
    validate(name)
    validate(address)
}

kotlin in action 책을 통한 공부입니다.

 

댓글