3.1 코틀린에서 컬렉션 만들기
- 2.3.3절 참고 : setOf 함수를 사용해 집합 만드는 방법 배웠음
숫자로 이루어진 집합 만들어보기
fun main()
{
val set = hashSetOf(1,7,53)
val list = arrayListOf(1, 7, 53)
val map = hashMapOf(1 to "one", 7 to "seven", 53 to "fifty-three")
println(set.javaClass)
println(list.javaClass)
println(map.javaClass)
}
- map : key - value 쌍의 모임
- map 생성시 사용된 to : 일반 키워드 x, 함수 o
- javaClass : 자바의 getClass()에 해당하는 코틀린 코드
- 위의 코드로 실행하면 ?
-
/* class java.util.HashSet class java.util.ArrayList class java.util.HashMap */
- 코틀린에는 자체 컬렉션 x
- 코틀린에는 자체 컬렉션 제공하지 않는 이유 : 자바코드와의 상호작용을 위해
- 코틀린 컬렉션 클래스 == 자바 컬렉션 클래스
-
- 코틀린 컬렉션 클래스 함수
- last() : 마지막 원소 반환
- max() : 수로 이루어진 컬렉션에서 최대값 반환
fun main() { /*val set = hashSetOf(1,7,53) val list = arrayListOf(1, 7, 53) val map = hashMapOf(1 to "one", 7 to "seven", 53 to "fifty-three") println(set.javaClass) println(list.javaClass) println(map.javaClass)*/ val strings = listOf("a", "b", "c") println(strings.last()) val numbers = setOf(1, 12, 4) println(numbers.maxOrNull()) }
3.2 함수를 호출하기 쉽게 만들기
joinToString()
- 자바컬렉션 디폴트 toString의 출력양식과 다르게 출력하고 싶을 때 사용
//toString 사용시 fun main() { val myList = listOf(1, 4, 13) println(myList.toString()) }
- joinToString() 함수 초기 구현
- fun <T> joinToString (...)
- 제네릭하다.
- 모든 타입의 컬렉션 처리 가능
- fun <T> joinToString (...)
-
fun main() { val myList = listOf(1, 4, 13) println(joinToString(myList, "!", "#", "#")) //출력 : #1!4!13# } 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 이름 붙인 인자
- joinToString 초기 구현의 문제점
- 함수 호출 부분에서 각 문자열이 어떤 역할을 하는지 알기 어려움 ( 가독성이 떨어짐 + 함수호출 코드가 모호함)
- 해결 : 인자에 이름 붙여서 호출하기
- println(joinToString(collection = myList, separator = "!", prefix = "#", postfix = "#"))
- 하나라도 인자에 이름을 명시한다면 그 뒤에 오는 인자도 모두 이름 명시하자 (혼동을 막기 위해)
- 함수 호출 부분에서 각 문자열이 어떤 역할을 하는지 알기 어려움 ( 가독성이 떨어짐 + 함수호출 코드가 모호함)
3.2.2 디폴트 파라미터 값
- 디폴트 파라미터 사용해서 joinToString 함수선언 수정해보기
- fun <T> joinToString(collection: Collection <T>, separator: String = ", ", prefix: String = "", postfix: String = "") : String {...}
- 디폴트 파라미터 값이 있으면 함수 호출시 해당되는 인자를 생략할 수 있다.
- 이름 붙인 인자와 자주 사용함 (디폴트 값을 사용하고 싶은 인자가 호출시 중간 순서일 경우 유용) : println(joinToString(collection = myList, prefix = "#", postfix = "#"))
- 자바에서 디폴트 파라미터값을 사용하는 코틀린 함수를 편하게 호출하는 방법 : @JvmOverloads 애노테이션 함수에 추가하기
- JvmOverloads : 코틀린 컴파일러가 자동으로 맨 마지막 파라미터로부터 파라미터를 하나씩 생략한 오버로딩한 자바메소드를 추가해줌
3.2.3 정적인 유틸리티 클래스 없애기 : 최상위 함수와 프로퍼티
- 최상위 함수 만들기 : 함수를 소스파일의 최상위 수준에 두기 == 해당 소스파일에서 모든 클래스의 외부
- 최상위 프로퍼티
- 프로퍼티도 파일의 최상위 수준에 놓을 수 있음
3.3 메소드를 다른 클래스에 추가: 확장 함수와 확장 프로퍼티
- 확장함수 : 어떤 클래스의 멤버 메소드인 것 처럼 호출가능 but 그 클래스의 밖에 선언된 함수
- 확장함수 생성
- 확장할 클래스 : String
- 수신 객체 타입 : Strng
- 수신 객체 : this
- 확장이 정의될 클래스 == 해당 클래스에서 확장함수를 자신의 함수처럼 사용한다.
- 수신 객체 == 해당 확장 함수를 실제로 자신의 함수로 사용할 객체 == 그 클래스 타입의 인스턴스 객체
- 확장 함수의 사용
- println("Kotlin".lastChar()) //출력 : n //이때 수신 객체는 "Kotlin"
- 확장함수 vs 클래스 내부에 정의된 함수
- 확장함수는 클래스의 함수처럼 사용 가능하지만 클래스 내부에서만 사용 가능한 멤버(접근 지정자 private(해당 함수내에서만), protected(같은 패키지))에는 접근 불가능함
fun String.lastChar(): Char = this.get(this.length -1) //this : 수신 객체 //this 없이도 수신 객체에 접근 가능 //fun Stirng.lastChar(): Char = get(length-1) //수신 객체 타입은 확장이 정의될 클래스의 타입이며, 수신 객체는 그 클래스에 속한 //인스턴스 객체이다.
- package strings fun String.lastChar():Char = this.get(this.length -1)
3.3.1 임포트와 확장함수
- 확장함수 사용하기 위해서는 임포트를 해야한다.
- 확장함수 import 하기
- 확장함수만 import : import strings.lastChar
- strings 전체를 import : import strings.*
- as 키워드 사용 : import strings.lastChar as last
- → println("kotlin".last()) // import 한 소스코드 내에서 last라는 이름으로 사용
3.3.2 자바에서 확장 함수 호출
확장함수가 들어있는 자바 클래스 이름 == 확장 함수가 들어있는 파일 이름
if (확장함수 파일 이름 == StringUtil.kt)
then 확장함수가 들어있는 자바 클래스 이름 = StringUtilKt
3.3.3 확장 함수로 유틸리티 함수 정의
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()
}
//Collection<T> 에 대한 확장함수를 선언한다.
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()
}
3.3.4 확장함수는 오버라이드할 수 없다.
- View- Button (View의 하위클래스)
- Button 에서 View의 click 메소드 오버라이딩
- Button 타입의 변수를 View 타입 변수에 대입하고 click 메소드 호출하면 Button의 클릭 메소드가 호출됨
- → View 타입 변수로 선언되었더라도 실제 타입인 Button에 따라 호출될 메소드가 결정됨
- (동적인 타입에 의해 함수가 결정됨)
- 이름과 파라미터가 완전히 같은 확장함수를 상위클래스와 그 하위클래스에 대해서 정의한다면?
- 동적으로 타입변환 불가능 ( == 오버라이딩 불가능)
- 확장 함수 호출시 수신 객체로 지정한 변수의 정적타입에 의해 어떤 함수가 호출될지 결정됨
3.3.5 확장 프로퍼티
- 확장 프로퍼티
- 이름은 프로퍼티지만 실제로 상태를 가질 수 없다.
- 초기하 코드 사용 불가
- 확장 프로퍼티 선언 : val String.lastChar: Char get() = get(length-1)
- 확장 프로퍼티는 뒷받침하는 필드 x == 기본 게터 구현 제공 불가
- ⇒ 게터 정의 필수
- 변경 가능한 확장 프로퍼티 선언 : 프로퍼티 세터 구현하기
- var StringBuilder.lastChar: Char get() = get(length -1) set(value: Char) { this.setCharAt(length-1, value) }
- 확장프로퍼티의 사용 : 멤버 프로퍼티 사용법과 동일
- println("Kotlin".lastChar)
- 자바에서 확장 프로퍼티 사용 : 게터, 세터 명시적으로 호출해야함
- StringUtilKt.getLastChar("Java")
3.4.1 자바 컬렉션 API 확장
- 어떻게 자바 라이브러리 클래스의 인스턴스인 컬렉션에 대해 코틀린이 새로운 기능을 추가할 수 있을까? → 3장 앞쪽에서 본 last()와 max()는 확장함수였다!!
3.4.2 가변인자 함수 : 인자의 개수가 달라질 수 있는 함수 정의
- vector<int> v(); vector<int> v2(10); vector<int> v3(10, 1);
- listOf 등 컬렉션 생성 함수 정의 : fun listOf<T>(vararg values: T) : List<T> { ... }
- 가변길이 인자 : 메소드를 호출할 때 원하는 개수만큼 값을 인자로 넘기면 컴파일러가 그 값들을 배열에 넣어주는기능
3.4.3 값의 쌍 다루기 : 중위 호출과 구조 분해 선언
val map = mapOf(1 to "one", 7 to "seven", 10 to "ten")
//to 메소드 중위 호출
//객체.메소드명 해당 메소드의 하나뿐인 인자
//val map = mapOf(1.to("one"), 7.to("seven"), 10.to("ten"))
//top 메소드 일반 호출
- 중위 호출
- 인자가 하나뿐인 일반 메소드나 확장함수에 사용 가능
- 중위 호출 허용 : infix 변경자를 함수 선언 앞에 추가하기
- to 함수와 중위호출
- to 함수는 Pair 객체 반환
- Pair : 두 원소로 이뤄진 순서쌍을 표현하는 클래스
- infix fun Any.to(other:Any) = Pair(this, other)
- 구조분해 선언
3.5.1 문자열 나누기
- 자바에서 "1.2.3".split(".") → .을 구분자로 문자열을 분리할 수 없음
- → split의 구분 문자열은 실제로는 정규식이기 때문이다. (.)
- 코틀린에서 : split 확장함수를 오버로딩한 버전으로 해결
3.5.2 정규식과 3중 따옴표 묶은 문자열
- 코틀린에서는 정규식을 사용하지않고도 문자열을 쉽게 파싱할 수 있다.
- 정규식의 단점 : 나중에 알아보기 힘들다.
- 코틀린에서 정규식이 필요할 때 → 코틀린 라이브러리 사용
3.5.3 여러줄 3중 따옴표 문자열
- 3중 따옴표 문자열
- 이스케이프를 피할 때
- 줄바꿈을 포현하는 아무 문자열이나 이스케이프 없이 그대로 들어간다. → 줄바꿈이 있는 프로그램 텍스트를 쉽게 문자열로 만들 수 있다.
- 내부에 문자열 템플릿 사용 가능
3.6 코드 다듬기 : 로컬 함수와 확장
- DRY 원칙 : DONT REPEAT YOURSELF (반복하지 말라)→ 그러나 메소드끼리의 관계 파악이 어려워짐
- → 반복을 피하기 위해 : 메소드 추출 리팩토링 적용해서 긴메소드를 부분부분 나눠 재활용 가능
- 반복을 피할 코틀린의 해법 : 추출한 함수를 원함수 내부에 중첩시키기
- 로컬함수
- 호출 : 원함수 내부에서 호출해야함
- 원함수 내부의 함수 == 해당 함수의 로컬함수
- 자신이 속한 바깥 함수의 모든 파라미터와 변수 사용 가능 (내부함수는 원함수의 파라미터와 변수 사용 가능)
- 로컬 함수를 확장함수로
- 원함수에서 확장을 정의할 클래스를 사용하는 경우
- 로컬함수를 원함수에서 사용하는 클래스의 확장함수로 추출하는 것
'3-1기 스터디 > Kotlin' 카테고리의 다른 글
[7주차] 람다로 프로그래밍(1) (0) | 2021.12.26 |
---|---|
[5주차] 클래스, 객체, 인터페이스(2) (0) | 2021.11.28 |
[4주차] 클래스, 객체, 인터페이스 (0) | 2021.11.21 |
[2주차] 코틀린 기초 (0) | 2021.11.07 |
[1주차] 코틀린이란 무엇이며, 왜 필요한가? (0) | 2021.10.10 |
댓글