다음 코드의 joinToString 함수는 컬렉션의 원소를 StringBuilder의 뒤에 덧붙인다. 이때 원소 사이에 구분자를 추가하고, StringBuilder의 맨 앞과 맨 뒤에는 접두사와 접미사를 추가한다.
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()
}
이 함수는 제네릭하다. 즉, 이 함수는 어떤 타입의 값을 원소로 하는 컬렉션이든 처리할 수 있다.
>>> val list = listOf(1, 2, 3)
>>> println(joinToString(list, "; ", "(", ")"))
(1; 2; 3)
이제 이 함수를 좀 더 개선해서 쉽게 사용하게 만들어보자.
3.2.1 이름 붙인 인자
해결하고픈 첫 번째 문제는 함수 호출 부분의 가독성이다.
joinToString(collection, " ", " ", ".")
이를 해결하기 위해, 코틀린은 함수에 전달하는 인자 중 일부(or 전부)의 이름을 명시할 수 있다.
joinToString(collection, separator = " ", prefix = " ", prefix = ".")
3.2.2 디폴트 파라미터 값
코틀린에서는 함수 선언에서 파라미터의 디폴트 값을 지정할 수 있으므로 자바의 오버로딩이 과도해지는 문제를 피할 수 있다.
디폴트 값을 사용해 joinToString 함수를 개선해보자.
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()
}
자바에는 디폴트 파라미터 값이라는 개념이 없는데, 코틀린에서 만든 함수를 자바에서 호출해야하는 경우는 어떻게 해야할까?
이 경우, @JvmOverloads를 함수에 추가하면 코틀린 컴파일러가 자동으로 모든 경우의 수를 커버하는 오버로딩한 자바 메소드를 추가해준다.
@JvmOverloads // 함수에 추가 fun greet(name: String = "세계", greeting: String = "안녕") { println("$greeting, $name!") }
3.2.3 정적인 유틸리티 클래스 없애기: 최상위 함수와 프로퍼티
아래는 joinToString() 함수를 최상위 함수로 선언한 예제이다.
// join.kt
package strings
fun joinToString(...): String { ... }
이를 컴파일한 결과와 같은 클래스를 자바 코드로 써보면 다음과 같다.
package strings;
public class JoinKt {
public static String joinToString(...) { ... }
}
만약, 자바에서 이 함수를 호출해서 사용한다면 아래와 같다.
import strings.JoinKt;
...
JoinKt.joinToString(list, ", ", "", "");
코틀린 최상위 함수가 포함되는 클래스의 이름을 바꾸고 싶다면 파일에 @JvmName을 추가하면 된다. @JvmName은 파일의 맨 앞, 패키지 이름 선언 이전에 위치해야 한다.
@file:JvmName("StringFunctions") package strings fun joinToSTring(...): String { ... }
이제 다음과 같이 joinToString 함수를 호출할 수 있다.
import strings.StringFunctions; StringFunctions.joinToString(list, ", ", "", "");
최상위 프로퍼티
함수와 마찬가지로 프로퍼티도 파일의 최상위 수준에 놓을 수 있다. 어떤 데이터를 클래스 밖에 위치시켜야 하는 경우는 흔하지는 않지만, 그래도 가끔 유용할 때가 있다.
var opCount = 0
fun performOperation() {
opCount++
// ...
}
이런 프로퍼티의 값은 정적 필드에 저장된다.
최상위 프로퍼티를 활용해 코드에 상수를 추가할 수 있다.
val UNIX_LINE_SEPARATOR = "\n"
기본적으로 최상위 프로퍼티도 다른 모든 프로퍼티처럼 접근자 메소드를 통해 자바 코드에 노출된다(val의 경우 getter, var의 경우 getter&setter). 겉으론 상수처럼 보이는데, 실제로는 getter/setter를 사용해야 한다면 자연스럽지 못하다. 더 자연스럽게 사용하려면 이 상수를 public static final 필드로 컴파일해야 한다. const 변경자를 추가하면 프로퍼티를 public static final 필드로 컴파일하게 만들 수 있다(단, 원시 타입과 String 타입의 프로퍼티만 const로 지정할 수 있다).
const val UNIX_LINE_SEPARATOR = "\n"
이 코드는 다음 자바 코드와 동등한 바이트코드를 만들어낸다.
public static final String UNIX_LINE_SEPARATOR = "\n";
'Kotlin' 카테고리의 다른 글
[Kotlin in Action] 3.4 컬렉션 처리: 가변 길이 인자, 중위 함수 호출, 라이브러리 지원 (0) | 2025.03.14 |
---|---|
[Kotlin in Action] 3.3 메소드를 다른 클래스에 추가: 확장 함수와 확장 프로퍼티 (0) | 2025.03.14 |
[Kotlin in Action] 3.1 코틀린에서 컬렉션 만들기 (0) | 2025.03.14 |
[Kotlin in Action] 2.5 코틀린 예외 처리 (0) | 2025.03.14 |
[Kotlin in Action] 2.4 대상을 이터레이션: while과 for 루프 (0) | 2025.03.14 |
댓글