코틀린 컬렉션은 자바 컬렉션과 똑같은 클래스이다. 표준 자바 컬렉션을 활용하면 자바 코드와 상호 작용하기 훨씬 더 쉽다. 각각의 언어에서 호출할 때, 컬렉션을 서로 변환할 필요가 없다.
But, 코틀린에서는 자바보다 더 많은 기능을 쓸 수 있다.
val strings = listOf ("first”, "second”, ”fourteenth")
printin (strings. last ()) // fourteenth
val numbers = setOf (1, 14, 2)
printin (numbers.max()) // 14
자바 컬렉션에는 기본적으로 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()
}
코틀린에서는 함수를 호출할 때, 인자에 이름을 붙여서 호출이 가능하다.
호출시 인자 중 어느 하나라도 이름을 명시한다면, 혼동을 막기 위해 그 뒤에 오는 모든 이니자의 이름을 꼭 명시해야한다.
fun main() {
val list = listOf(1, 2, 3)
println(joinToString(list, ";", "(", ")"))
// 이름을 붙인 인자
println(joinToString(list, separator = ";", prefix = "(", postfix = ")"))
}
자바에서는 일부 클래스에서 오버로딩한 메소드가 너무 많다. 그렇기 때문에 개발자들이 반복적인 설명 주석을 달아야하는 경우가 많다.
코틀린에서는 함수를 선언할 때, 파라미터의 디폴트 값을 지정할 수 있어서, 이런 오버로드를 피할 수 있다.
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
를 추가하면, 코틀린 컴파이리러가 자동으로 맨 마지막 파라미터부터 파라미터를 하나씩 생략한 오버로딩한 자바 메소드를 추가해준다.
자바에서는 모든 코드를 클래스의 메소드로 작성해야하는 데, 실전에서는 어느 한 클래스에 포함하기 어려운 코드들이 많다. 그래서 Utill 클래스를 만들기도 한다.
하지만, 코틀린에서는 이런 고민을 할 필요가 없다.
→ 함수를 직접 소스파일의 최상위 수준, 모든 다른 클래스의 밖에 위치시키면 된다.
package strings;
public class JoinKt {
public static String joinToString (. . .) { ... }
}
최상위 프로퍼티
함수와 마찬가지로 프로퍼티도 파일의 최상위 수준에 놓을 수 있다.
이런 프로퍼티 값은 정적 필드에 저장된다.
val opCount=0 // 최상위 프로퍼티 선언
fun performOperation() {
opCount++ // 최상위 프로퍼티 값 변경
// ...
}
fun reportOperationCount() {
println("Operation performed $opCount times") // 최상위 프로퍼티 값 읽기
}
const
키워드를 사용하면 java의 상수, public static final 필드
로 컴파일하게 만들 수 있다. (단, primitive type과 String 타입의 프로퍼티만 가능)
확장함수란 ?
package strings
fun String.lashChar(): Char = this.get(this.length - 1)
println("Kotlin".lastChar())
String
이 수신 객체 타입, “Kotlin”
이 수신 객체
확장 함수를 사용하기위해서는 import를 해줘야만 한다.
코틀린 문법상 확장 함수는 반드시 짧은 이름을 써야한다. import 할 때 이름을 바구는 것이 확장 함수 이름을 충돌할 수 있는 유일한 방법이다.
import strings.lastChar
// import strings.*
// import string.lastChar as last // 별칭 사용 가능
val c = "Kotlin".lastChar()
// val c = "Kotlin".last()
확장함수는 수신 객체를 첫번째로 받는 정적 메소드이다. 이런 설계로 확장 함수를 자바에서 사용하기 편하다. 확장함수를 StringUtil.kt
파일에 정의했다면 다음과 같이 호출할 수 있다.
char c = StringUtilKt.lastChar("Java");
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)
}
확장함수는 정적 메소드 (static)특징을 가지고 있기 때문에 오버라이드를 할 수 없다.
확장 프로퍼티를 추가하면 기존 클래스 객체에 대한 프로퍼티 형식의 구문을 사용할 수 있다.
하지만, 기존 클래스의 프로퍼티처럼 완벽한 프로퍼티의 기능을 지원하지는 못한다.
// 확장 프로퍼티 선언
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!
코틀린은 자바 컬렉션 라이브러리를 확장해서 사용한다.
//리스트 함수는 원하는 만큼 원소를 인자 값으로 전달할 수 있다.
val lislt = listOf(2, 3, 5, 7, 11)
fun listOf<T>(vararg values: T): List<T> {...}
자바의 가변길이 인자 → 키워드 ...
ex) String ...str
코틀린의 가변길이 인자 varargs
ex ) vararg values : T
이미 배열에 들어있는 원소를 가변 길이 인자로 넘길 때
자바의 경우 → 배열을 그냥 넘긴다.
코틀린의 경우 → 배열을 명시적으로 풀어서 배열의 각 원소가 인자로 전달되게 한다. 스프레드 연산자 사용 *
fun main(args: Array<String>){
val list = listOf("args: ", *args)
println(list)
}
중위 호출 : 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")
}
참고 : Pair 는 코틀린의 표준 라이브러리
to 함수를 이용해서 순서쌍을 만든다음 구조 분해를 통해, 그 순서쌍을 풀었다.
출처 : (서적) Kotlin in Action 드미트리 제메로프, 스베트라나 이사코바 저자 /오현석 옮김