매일 매일, 차곡 차곡 쌓기



완벽하지 않은 것을 두려워 말며,
완성도를 높히는데 집중하자.

개발 언어/코틀린

3장. 함수 정의와 호출

blockbuddy93 2024. 3. 27. 12:38

3.1 코틀린에서 컬렉션 만들기

  • 코틀린 컬렉션은 자바 컬렉션과 같은 클래스이다.
  • 하지만 코틀린에서는 자바보다 더 많은 기능을 쓸 수 있다.
val strings = listOf ("first”, "second”, ”fourteenth")
printin (strings. last ()) // fourteenth

val numbers = setOf (1, 14, 2)
printin (numbers.max())  // 14

 

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

  • 자바 컬렉션에는 기본적으로 toString 구현이 들어있다. 코틀린을 이용해서 joinToString 함수 구현하기
// joinToString() 함수의 초기 구현
//<T> 제네릭 타입
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()
}

 

3.2.1 이름 붙인 인자

  • 코틀린에서는 함수를 호출할 때, 인자에 이름을 붙여서 호출이 가능하다.
  • 호출시 인자 중 어느 하나라도 이름을 명시한다면, 혼동을 막기 위해 그 뒤에 오는 모든 인자의 이름을 명시해야 한다.
fun main() {
    val list = listOf(1, 2, 3)
    println(joinToString(list, ";", "(", ")"))

// 이름을 붙인 인자
    println(joinToString(list, separator = ";", prefix = "(", postfix = ")"))
}

 

3.2.2 디폴트 파라미터 값

  • 자바에서는 일부 클래스에서 오버로딩한 메소드가 너무 많다. 그렇기 때문에 개발자들이 반복적인 설명 주석을 달아야하는 경우가 많다.
  • 코틀린에서는 함수를 선언할 때, 파라미터의 디폴트 값을 지정할 수 있어서, 이런 오버로드를 피할 수 있다.

 

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, ";", "(", ")"))
println(joinToString(list))
println(joinToString(list, "; "))

 

  • 자바에는 디폴트 파라미터 값이라는 개념이 없다.
  • 코틀린 함수를 자바에서 호출한 경우, 코틀린 함수가 디폴트 파라미터 값을 제공하더라도 모든 인자를 명시해야 한다.
  • 자바에서 코틀린 함수를 자주호출해야한다면, @JvmOverloads 어노테이션을 함수에 추가하자.
  • @JvmOverloads를 추가하면, 코틀린 컴파일러가 자동으로 맨 마지막 파라미터부터 파라미터를 하나씩 생략한 오버로딩한 자바 메서드를 추가해 준다.

 

3.2.3 정적인 유틸리티 클래스 없애기 : 최상위 함수와 프로퍼티

  • 자바에서는 모든 코드를 클래스의 메서드로 작성해야 하는데, 실전에서는 어느 한 클래스에 포함되지 어려운 코드들이 많다.
  • 그래서 Utill 클래스를 만들게 되는데, 코틀린에서는 이런 고민을 할 필요가 없다.
  • 함수를 직접 소스파일의 최상위 수준, 모든 다른 클래스 밖에 위치키시면 되기 때문이다.
package strings;

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

 

 

  • 함수와 마찬가지로 프로퍼티도 파일의 최상위 수준에 놓을 수 있다.
  • 이것을 최상위 프로퍼티라고 하며 프로퍼티 값은 정적필드에 저장된다.
val opCount=0   // 최상위 프로퍼티 선언

fun performOperation() {
	opCount++   // 최상위 프로퍼티 값 변경
  // ...
}

fun reportOperationCount() {
  println("Operation performed $opCount times")  // 최상위 프로퍼티 값 읽기
}
  • const 키워드를 사용하면 자바의 상수, pulbic static final 필드로 컴파일하게 만들 수 있다.
  • 단 primitive type과 String 타입의 프로퍼티만 가능하다

 

3.3 메서드를 다른 클래스에 추가 : 확장 함수와 확장 프로퍼티

  • 확장 함수란?
    • 어떤 클래스의 멤버 메서드처럼 호출할 수 있지만, 클래스 밖에서 선언된 함수
    • 확장함수를 만들려면 추가하려는 함수 이름 앞에 그 함수가 확장할 클래스 이름을 덧붙인다.
    • 클래스 이름을 수신 객체 타입, 확장 함수가 호출되는 대상이 되는 값을 수신 객체

 

package strings
fun String.lashChar(): Char = this.get(this.length - 1)

println("Kotlin".lastChar())

 

  • String 이 수신 객체 타입. "Kotlin" 이 수신 객체
  • 확장 함수 내부에서는 수신 객체의 메서드나 프로퍼티를 사용할 수 있다.
  • 하지만 클래스 내부에만 사용할 수 있는 private 멤버나 protected 멤버를 사용할 수 없기 떄문에 캡슐화를 지킨다.

 

3.3.1 임포트와 확장 함수

  • 확장 함수를 사용하기 위해서는 Import를 해줘야만 한다.
  • 코틀린 문법상 확장 함수는 반드시 짧은 이름을 써야 한다. import 할 때 일므을 바꾸는 것이 확장함수 이름의 충돌을 피할 수 있는 유일한 방법이다.

 

import strings.lastChar
// import strings.*
// import string.lastChar as last   // 별칭 사용 가능

val c = "Kotlin".lastChar()
// val c = "Kotlin".last()

 

3.3.2 자바에서 확장 함수 호출

  • 확장함수는 수신 객체를 첫번째로 받는 정적 메서드이다. 이런 설계로 확장 함수를 자바에서 사용하기 편하다.
  • 확장함수를 StringUtil.kt 파일에 정의했다면 다음과 같이 호출할 수 있다.
char c = StringUtilKt.lastChar("Java");

 

3.3.3 확장 함수로 유틸리티 함수 정의

  • joinsToString 함수를 확장함수로 만들어서 코틀린 라이브러리가 제공하는 함수처럼 만들기
fun <T> Collection<T>.joinToString(
    separator: String = ", ",
    prefix: String = "",
    postfix: String = ""
): String {
    val result = StringBuilder(prefix)

    for ((index, element) in this.withIndex()) {
        if (index > 0) result.append(separator)
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}

fun main() {
    val list = listOf(1, 2, 3)
    println(list.joinToString("; ", "(", ")"))
		// (1; 2; 3)
}

 

  • 확장 함수는 단지 정적 메서드 호출에 대한 문법적인 편의일 뿐이다.
  • 클래스가 아닌데 구체적인 타입을 수신 객체 타입으로 지정할 수 있다.
  • 따라서 문자열의 컬렉션에 대해서만 호출하려면 다음과 같이 정의하면 된다.

 

fun <String>.joinToString(
    separator: String = ", ",
    prefix: String = "",
    postfix: String = ""
) = joinToString(separator, prefix, postfix)

fun main() {
    printin (listOf ("one", "two", "eight").join (" "))
		// (1; 2; 3)
}

 

3.3.4 확장함수는 오버라이드 할수 없다.

  • 확장함수는 정적 메서드 Static한 특징을 가지고 있기 때문에 오버라이드 할 수 없다.

 

3.3.5 확장 프로퍼티

  • 확장 프로퍼티를 추가하면 기존 클래스 객체에 대한 프로퍼티 형식의 구문을 사용할 수 있다.
  • 하지만, 기존 클래스의 프로퍼티처럼 완벽한 프로퍼티 기능을 지원하지는 못한다.
  • 확장 프로퍼티는 아무런 상태를 가질 수 없다.
  • 최소한의 getter는 꼭 정의해야 한다.
  • 초기화 코드를 쓸 수 없다.

 

// 확장 프로퍼티 선언
val String.lastChar: Char
	get() = get(length - 1 )

// 변경 가능한 확장 프로퍼티 선언
var StringBuilder.lastChar: Char
    get() = get(length - 1)
    set(value: Char) {
        this.setCharAt(length - 1, value)
    }

val sb = StringBuilder("Kotlin?")
    sb.lastChar = '!'
    println(sb) // Kotlin!

 

3.4 컬렉션 처리 : 가변 길이 인자, 중위 함수 호출, 라이브러리 지원

3.4.1 자바 컬렉션

  • 코틀린은 자바 컬렉션 라이브러리를 확장해서 사용한다.

 

3.4.2 가변 인자 : 인자의 개수가 달라질 수 있는 함수

//리스트 함수는 원하는 만큼 원소를 인자 값으로 전달할 수 있다.
val lislt = listOf(2, 3, 5, 7, 11)

fun listOf<T>(vararg values: T): List<T> {...}

 

  • 자바의 가변길이 인자 키워드 "..."
  • 코틀린의 가변인자 키워드 "varargs"
  • 이미 배열에 들어있는 원소를 가변 길이 인자로 넘길 때
  • 자바의 경우 배열을 그냥 넘긴다.
  • 코틀린의 경우 배열을 스프레드 연산자 * 를 사용  하여 명시적으로 풀어서 배열의 각원소가 인자로 전달되게 한다. 
fun main(args: Array<String>){
	val list = listOf("args: ", *args)
	println(list)
}

 

3.4.3 값의 쌍 다루기 : 중위 호출과 구조 분해 선언

  • 중위 호출 : to
  • 수신 객체 (공백) to
  • 인자가 하나뿐인 일반 메서드, 인자가 하나뿐인 확장함수에 중위호출 사용 가능
  • 함수에 infix 키워드를 붙이면, 중위 호출해서 사용 가능하다.

 

val map = mapOf(1 to "one", 2 to "two", 3 to "three")

1.to("one")  // 'to' 메소드 일반적인 호출 방식
2.to "two"  // 'to' 메소드를 중위 호출 방식으로 호출

infix fun Any.to(other: Any) = Pair(this, other)
val (number, name) = 1 to "one"  // 구조분해

for((index, element) in collection.withIndex()){
	println("$index: $element")
}

 

 

 

'개발 언어 > 코틀린' 카테고리의 다른 글

2장. 코틀린 기초  (0) 2024.03.26
1장. 코틀린이란 무엇이며 왜 필요한가?  (0) 2024.03.25