코틀린에는 배열을 생성하고 싶을 경우, arrayOf 함수를 이용해 배열을 만들고 Array 클래스에 들어 있는 속성과 메소드를 이용할 수 있다.
코틀린에서 배열을 다루는 방법과 자바에서 배열을 다루는 방법은 서로 약간 다르다.
자바에서 배열 인스턴스화
String[] strings = new String[4];strings[0] ="an";strings[0] ="array";strings[0] ="of";strings[0] ="strings";// 또는 더 쉽게Strings ="an array of strings".split(" ");
코틀린에서 배열 인스턴스화
val strings =arrayOf("this", "is", "an", "array", "of", "strings")// 또는 널로만 채워진 배열을 생성할 수 있다. val nummStringArray =arrayOfNulls<String>(5)
코틀린의 Array 클래스에는 public 생성자가 하나만 있다. 이 생성자는 다음의 두 인자를 받는다.
Int 타입의 size
init, 즉 (Int) → T 타입의 람다
Array 클래스 생성자의 두 번째 인자인 람다는 배열을 생성할 때 인덱스마다 호출된다.
val squares =Array(5) { i -> (i * i).toString() }// results// {"0", "1", "4", "9", "16"}
코틀린에는 오토박싱과 언박싱 비용을 방지할 수 있는 기본 타입을 나타내는 클래스가 있다. booleanArrayOf, byteArrayOf, shortAr, rayOf, charArrayOf, intArrayOf, longArrayOf, floatArrayOf, doubleArrayOf 등이 있다.
코틀린에는 명시적인 기본 타입은 없지만 값이 널 허용 값인 경우 생성된 바이트코드는 Integer와 Double 같은 자바 래퍼 클래스를 사용하고, 널 비허용 값인 경우 생성된 바이트코드는 int와 double 같은 기본 타입을 사용한다.
indices, withIndex
배열의 확장 메소드는 대부분 컬렉션에 있는 이름이 같은 확장 메소드와 동일하게 동작한다. 하지만 배열에는 두어 개의 고유한 확장 함수가 존재한다. 예를 들어 배열의 적법한 인덱스 값을 알고 싶다면 다음과 같이 indices 속성을 사용하자
val list =ArrayOf("Hello", "World", "!")for (i in list.indicies) {println(list[i])}//results// Hello// World// !
for-in 루프를 사용하지만 배열의 인덱스 값도 같이 사용하고 싶다면 withIndex 함수를 사용하자
val strings =arrayOf("this", "is", "an", "array", "of", "strings")for((index, value) in strings.withIndex()) {println("index $index maps to $value")}
컬렉션 생성하기
기본적으로 코틀린 컬렉션은 '불변'이다 그런 의미에서 컬렉션은 원소를 추가하거나 제거하는 메소드를 지원하지 않는다.
불변 컬렉션 생성
listOf
setOf
mapOf
var numList =listOf(3, 1, 4, 5, 9)var numSet =setOf(3, 1, 4, 1, 5, 9)// numSet.size == 5 -> truevarmapOf(1 to "one", 2 to "Two", 3 to "three")
컬렉션을 변경하는 메소드는 다음과 같은 팩토리 메소드에서 제공하는 '가변(mutable)' 인터페이스에 들어 있다.
가변 컬렉션 생성
mutableListOf
mutableSetOf
mutableMapOf
var numList =mutableListOf(3, 1, 4, 5, 9)var numSet =mutavleSetOf(3, 1, 4, 1, 5, 9)varmutableMapOf(1 to "one", 2 to "Two", 3 to "three")
키 리스트가 있을 경우 각가의 키와 생성한 값을 연관시켜서 맵을 만들고 싶을 경우 associate, associateWith 함수를 활용하라
val keys ='a'..'f'val map = keys.associate { it to it.toString().repeat(5).capitalize() }println(map)// results// {a=Aaaaa, b=Bbbbb, c=Ccccc, d=Ddddd, e=Eeeee}val map2 = keys.associateWith { it.toString().repeat(5).capitalize() }
컬렉션이 빈 경우 기본값 리턴하기
컬렉션이나 문자열이 비어 있는 경우에는 ifEmpty와 ifBlank 함수를 사용해 기본값을 리턴한다.
// 빈 컬렉션에 기본 리스트를 제공funonSaleProduct_ifEmptyCollection(products: list<Product>) = products.filter { it.onSale } .map { it.name } .ifEmpty { listOf("none") } // filter한 리스트가 비었을 경우 .joinToString(separator =", ")// 빈 문자열에 기본 문자열을 제공funonSaleProduct_ifEmptyString(products: list<Product>) = products.filter { it.onSale } .map { it.name } .joinToString(separator =", ") .ifEmpty { "none" } // filter한 후에 결과 String이 비었을 경우// 빈 문자일 경우 기본 문자열 제공val blank =" "val blankOrDefault = blank.ifBlank { "default" }println(blankOrDefault) // default
주어진 범위로 값 제한하기
값이 주어졌을 때, 주어진 값이 특정 범위 안에 들면 해당 값을 리턴하고 그렇지 않다면 범위의 최솟값 또는 최댓값을 리턴할 경우 kotlin.ranges를 사용한다.
@Testfun`coerceIn given a range`() {val range =3..8assertThat(5, `is`(5.coerceIn(range))) // trueassertThat(range.start, `is`(1.coerceIn(range))) // trueassertThat(range.endInclusive, `is`(9.coerceIn(range))) // true}@Testfun`coerceIn given min and max`() {val min =2val max =6assertThat(5, `is`(5.coerceIn(min, max))) // trueassertThat(min, `is`(1.coerceIn(min, max))) // trueassertThat(max, `is`(9.coerceIn(min, max))) // true}
sortBy와 sortWith 함수는 자신의 원소를 제자리에서 정렬하므로 변경 가능 컬렉션을 요구한다.
비교 후 같은 값일 경우에 새로운 비교를 적용하는 thenBy 함수를 사용해 Comparator를 생성할 수 있다.
val comparator =compareBy<Golfer>(Golfer::score) .thenBy(Golfer::last) .thenBy(Golfer::first)golfers.wortedWith(comparator) .forEach(::println)
사용자 정의 이터레이터 정의하기
컬렉션을 감싼 클래스를 임의로 순회하고 싶을 경우 next와 hasNext 함수를 모두 구현한 이터레이터를 리턴하는 연산자 함수를 정의한다.
val team =Team("warriors")team.addPlayers(Player("Curry"), Player("Thompson"),Player("Durant"), Player("Green"), Player("Cousins"))for (player in team.playes) {println(player)}
iterator라는 이름의 연산자 함수를 정의하면 이 코드를 더 간단하게 만들 수 있다.
operatorfunTeam.iterator() : Iterator<Player> = players.iterator()for (player in team) {println(player)}
사실 Team 클래스가 Iterable 인터페이스를 구현하도록 만든 이유는 Iterable 인터페이스에 추상 연산자 함수 iterator가 있기 때문이다.