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 |