자바(Java)에서 문자열을 다루는 대표적인 클래스(Class)로 String, StringBuffer, StringBuilder가 있습니다. 이 클래스들은 모두 CharSequence 인터페이스의 구현체 클래스입니다. CharSequence 인터페이스를 상속 받았다는 것은 이 클래스들 모두 내부적으로 문자열을 char[]로 다루고 있다고 보면 됩니다.
연산이 많지 않을때는 위에 나열된 어떤 클래스를 사용하더라도 문제가 발생할 가능성은 거의 없습니다. 그러나 연산횟수가 많아지거나 멀티쓰레드, Race Condition 등의 상황이 자주 발생 한다면, 각 클래스의 특징을 이해하고 상황에 맞는 적절한 클래스를 사용해야 합니다.
String
String은 불변(Immutable)의 속성을 지니고있습니다. 즉, String 타입으로 인스턴스가 한번 생성되면 변경이 안된다는 의미입니다.
위의 예제를 분석할 때 "피카츄"라는 값을 가지고 있는 String 타입 참조변수 str이 가리키는 곳에 저장된 "피카츄"에 "라이츄" 문자열을 더해 "피카츄 라이츄"로 변경한 것으로 우리는 오해할 수 있습니다. 하지만, 기존에 "피카츄" 값이 들어가있던 참조변수 str이 "피카츄 라이츄"라는 값을 가지고 있는 새로운 메모리 영역을 가리키도록 변경되고 처음 선언했던 "피카츄"로 값이 할당되어 있던 메모리 영역은 가비지(Garbage)로 남았다가 GC(Garbage Collector)에 의해 소멸되는 것 입니다. String 클래스는 불변하기 때문에 문자열을 수정하는 시점에 새로운 String 인스턴스가 생성된 것입니다.
String 인스턴스
위와 같이 String은 불변성을 지니고있기 때문에 변하지 않는 문자열을 자주 읽어들이는 경우 String을 사용하면, 좋은 성능을 기대할 수 있습니다. 그러나 문자열 추가, 수정, 삭제 등의 연산이 자주 발생되는 로직에 String 클래스를 사용하면 힙 메모리(Heap Memory)에 많은 가비지(Garbage)가 생성되어 어플리케이션 성능에 악영향을 줍니다.
StringBuffer, StringBuilder
위의 String 클래스의 문제점을 해결하기 위해 Java는 가변적(Mutable)인 속성을 지닌 StringBuffer, StringBuilder 클래스를 제공하고 있습니다. String과 달리 StringBuffer와 StringBuilder는 가변적인 속성을 가지고 있기 때문에 .append() .delete() 등의 API를 이용하여 동일 객체내에서 문자열을 변경하는 것이 가능합니다. 따라서 문자열의 추가, 수정, 삭제가 자주 발생하는 경우라면 String 클래스가 아닌 StringBuffer와 StringBuilder 클래스를 사용하면 됩니다.
// StringBuffer 클래스
StringBuffer strBf = new StringBuffer("피카츄");
strBf.append(" 라이츄");
System.out.println(strBf);
// StringBuilder 클래스
StringBuilder strBd = new StringBuilder("피카츄");
strBd.append(" 라이츄");
System.out.println(strBd);
위의 코드를 실행하면 다음과 같은 결과가 출력됩니다.
피카츄 라이츄
피카츄 라이츄
StringBuffer, StringBuilder
StringBuffer와 StringBuilder의 차이점
동일한 API를 가지고 있는 StringBuffer와 StringBuilder의 차이점은 동기화 유무입니다. StringBuffer는 동기화 키워들를 지원하여 멀티쓰레드 환경에서 안전합니다(thread-safe). 참고로 String도 불변성을 가지기 때문에 마찬가지로 멀티쓰레드 환경에서 안전합니다.
반대로 StringBuilder는 동기화를 지원하지 않기때문에 멀티쓰레드 환경에서 사용하는 것은 적합하지 않지만 동기화를 고려하지 않는 만큼 단일 쓰레드에서의 성능은 StringBuffer 보다 뛰어납니다.
Kotlin string은 참조만 되지 변경하기가 어렵다. Python도 그랬던것 같다. 아마 가볍게 만들려고 그런것 같다.
공부하던중 Kotlin에도 자료구조에 사용하기 좋은 stringBuilder라는 구조를 찾았다.
StringBuilder 클래스는 String처럼 문자열을 다루는 클래스로, String에 문자열을 넣고 인스턴스 생성 후에 값을 변경하지 못했던 점을 개선한 클래스라 할 수 있다. 추가적으로 내부적으로 문자열을 저장하기 위한 메모리 공간을 지닌다.
이놈은 append도 되고 insert, delete도 된다. 처리후 toString으로 형변환을 시켜주면 된다.
StringBuilder stb = new StringBuilder(32); 이때 예시처럼 작성을 하면 생성자의 인자로 전달되는 숫자인 32 크기만큼 문자를 저장할 수 있는 공간을 마련한다. length를 찍어보면 아직까지는 0이다 메모리공간만 마련하는듯
-append(값) : 문자열 추가한다. 재미있는건 어떤 타입도 다 문자열로 바꾼다. -delete(시작, 끝) : 시작 인덱스부터 끝 인덱스까지의 내용을 삭제한다. -insert(위치, 값) : 특정 원하는 위치에 문자열을 추가한다. -replace(시작, 끝, 값) : 시작 인덱스부터 끝 인덱스 이전까지의 내용을 추가하고자 하는 '값'으로 문자열을 대체한다. -reverse() : 저장해놨던 문자열의 내용을 뒤집는다. -substring(시작, 끝) : 저장된 문자열 중에서 시작부터 끝 이전까지의 내용만 담은 String 인스턴스의 값을 반환한다. -deleteCharAt(위치) : 특정 위치의 값만 삭제한다.
fun main(args : Array<String>) {
/*
기존 참조하던 "abc" 뒤에 "def"를 추가하는 것이 아니라
추가된 문자열 "abcdef"를 새로 생성하고 참조하는 것이다.
그러면 쓰레기 "abc"가 남게되며 이러한 과정이 많아지면 비효율적
var s1 = "ab"
s1 += "cd"
*/
val str = StringBuilder() // 빈 생성자
println("1. 문자열 : $str")
/* 추가 */
str.append(5) // Int 타입
str.append("man") // String 타입
str.append(' ') // Char 타입
str.append(true) // Boolean 타입
str.append(5431)
str.append(" is ")
str.append("women")
println("2. 문자열 : $str")
println("index=0 : ${str[0]}, index=5 : ${str[5]}")
/* 삭제 */
str.deleteCharAt(0) // index
str.delete(8, 12) // [start, end)
println("after delete 0, 8..12 : $str")
println("=========================================")
val temp: String = "ABCD"
val str2 = StringBuilder(temp) // String을 받는 생성자
println("1. 문자열 : $str2")
println("길이 = ${str2.length}")
println("뒤집기 = ${str2.reverse()}")
str2.insert(0, "front+") // index=0 위치에 추가
println("2. insert front : $str2")
val li = listOf("abc", "def", "ghi")
str2.append(li.joinToString(""))
println("3. append abcdefghi : $str2")
println("4-1. 부분 문자열 : ${str2.substring(6)}") // [6, length)
println("4-2. 부분 문자열 : ${str2.substring(6, 9)}") // [6, 8)
println("4-3. 부분 문자열 : ${str2.substring(6..9)}") // [6, 9]
println("=========================================")
val str3 = str.toString() // String Type으로 저장
if(str3 is String) println("String Type")
}
Kotlin 에서는 Collection 을 정렬하기 위한 여러가지 유틸리티들을 제공합니다.
1.1. Sort, Sorted
가장 쉬운 방법은sort메소드를 호출하는 겁니다.
기본적으로 오름차순으로 정렬합니다.
val list = mutableListOf(1, 2, 7, 6, 5, 6)
list.sort()
println(list) // [1, 2, 5, 6, 6, 7]
sort메소드는 해당 Collection 의 원소 위치가 변경됩니다.
기존 Collection 은 그대로 둔 채 새로운 Collection 으로 받길 원한다면sorted메소드를 사용해야 합니다.
sorted메소드를 사용하면 기존 Collection 은 변하지 않습니다.
val list = mutableListOf(1, 2, 7, 6, 5, 6) //뮤터블 리스트 초기화 생성
val sorted = list.sorted() //소팅해서 새로운 리슽 생성
println(sorted) // [1, 2, 5, 6, 6, 7] /소팅되었음
println(list) // [1, 2, 7, 6, 5, 6] (sorted 를 사용했기 때문에 변하지 않음)
내림차순으로 정렬하고 싶다면sortByDescending를 사용하거나reverse메소드를 사용하면 됩니다.
마찬가지로sortedByDescending를 사용하면 원래 Collection 의 변경 없이 내림차순으로 정렬된 값을 구할 수 있습니다.
// 1. sortByDescending 로 내림차순 정렬
list.sortByDescending { it }
val sorted = list.sortedByDescending { it } //내림차순 정열
// 2. reverse 사용해서 정렬 후 뒤집기
list.sort() //자신을 소팅한후
list.reverse() //순서를 바꾼다.
val sorted = list.sorted().reversed() //.연산자를 이용 한번에 붙여써도
1.2. SortBy
만약 Object 의 특정 Property 들을 기준으로 정렬하고 싶다면sortBy메소드를 사용하면 됩니다.
sortBy메소드는 Object 를 받아서 Property 를 반환하는 Lamdba 식을 파라미터로 받습니다.
val list = mutableListOf(1 to "a", 2 to "b", 7 to "c", 6 to "d", 5 to "c", 6 to "e")
list.sortBy { it.second }
println(list) // [(1, a), (2, b), (7, c), (5, c), (6, d), (6, e)]
sort와 마찬가지로 기존 Collection 의 변경 없이 정렬된 값을 받고 싶다면sortedBy를 사용하면 됩니다.
그리고 내림차순을 지원하는sortByDescending도 있습니다.
1.3. SortWith
sortWith메소드를 사용하면 여러 가지 조건을 섞어서 정렬할 수 있습니다.
sortWith메소드는Comparator를 파라미터로 받습니다.
(Kotlin 에서Comparator를 생성하는 여러가지 방법은 다음 챕터에서 다룹니다)
val list = mutableListOf(1 to "a", 2 to "b", 7 to "c", 6 to "d", 5 to "c", 6 to "e")
list.sortWith(compareBy({it.second}, {it.first}))
println(list) // [(1, a), (2, b), (5, c), (7, c), (6, d), (6, e)]
위 Collection 은it.second(문자) 로 먼저 정렬된 후에it.first(숫자) 로 정렬됩니다.
그리고 역시sortedWith메소드가 존재하며, 역순으로 정렬할때는reverse를 사용하거나Comparator를 반대로 수정하면 됩니다.
2. Comparison
Kotlin 은Comparator를 만들기 위해kotlin.comparisons라는 유용한 패키지를 제공합니다.
이 챕터에서는 아래 컨텐츠를 다룹니다.
Comparatorcreation
Handling ofnullvalues
Comparatorrules extension
2.1. Comparator Creation
Kotlin 은Comparator를 생성하는 여러 팩토리 메서드를 제공합니다.
2.1.1. naturalOrder
가장 간단한 생성 메서드는naturalOrder()입니다.
아무런 파라미터를 필요로 하지 않으며 오름차순을 기본으로 합니다.
val ascComparator = naturalOrder<Long>()
2.1.2. compareBy
여러 개의 속성을 사용하고 싶다면compareBy메소드를 사용하면 됩니다.
파라미터로는Comparable를 리턴하는 정렬 규칙을 여러 개 사용할 수 있습니다.
그럼 넘겨진 규칙들은 순차적으로 호출 되며 원소들을 정렬합니다.
만약 먼저 나온 규칙에서 원소의 우열이 가려져 정렬 처리가 되었다면 뒤의 규칙들은 확인하지 않습니다.
val complexComparator = compareBy<Pair<Int, String?>>({it.first}, {it.second})
위 코드에서it.first값을 사용해 먼저 비교를 하고 값이 같은 경우에만it.second비교까지 이루어집니다.
2.1.3. Comparator
간단하게new Comparator를 선언해서 만들 수도 있습니다.
자바와 마찬가지로 두 원소에 대한 비교 조건을 넣어줘야 합니다.
val caomparator = Comparator<Int> { a, b -> a.compareTo(b) }
2.2. Handling of null Values
정렬하려는 Collection 이null값을 갖고 있을 수도 있습니다.
nullsFirst또는nullsLast와 함께Comparator를 사용하면null값을 가장 처음 또는 가장 마지막에 위치하도록 설정할 수 있습니다.
val students = mutableListOf(21 to "Helen", 21 to "Tom", 20 to "Jim")
val ageComparator = compareBy<Pair<Int, String?>> {it.first}
val ageAndNameComparator = ageComparator.thenByDescending {it.second}
// [(20, Jim), (21, Tom), (21, Helen)]
println(students.sortedWith(ageAndNameComparator))
위 코드는 나이가 어린 순으로 먼저 정렬하고 나이가 같으면 이름을 알파벳 역순으로 정렬합니다.
val fruits = listOf("apple", "banana", "kiwi") //리스트 생성
for (item in fruits) { //리스트 반복하기
println(item)
}
// 요소의 인덱스를 통해 List에 접근하기
for (index in fruits.indices) { // 인덱스 지정
println("fruits[$index] = ${fruits[index]}") //[]연산자 이용 인덱스 접근
}
// while 루프 이용하기
var index = 0
while (index < fruits.size) {
println("fruits[$index] = ${fruits[index]}")
index++
}
emptyList() / listOfNotNull() 함수
비어 있는 리스트를 생성하려면 emptyList<>()를 사용할 수 있습니다. 이때는 반드시 형식 매개변수를 지정합니다. listOfNotNull()로 초기화하면 null을 제외한 요소만 반환해 List를 구성할 수 있습니다.
val emptyList: List<String> = emptyList<String>() // 빈리스트 생성
val nonNullsList: List<Int> = listOfNotNull(2, 45, 2, null, 5, null) //Null을 제외한 리스트
println(nonNullsList) // [2, 45, 2, 5]
List
List는 데이터가 저장하거나 삭제될 때 순서를 지키는 Collection입니다. List는 Mutable(변할 수 없는)과 Immutable(불변의)을 모두 지원합니다. 이 타입의 구현체는 ArrayList, LinkedList 두 가지가 있다
// List 인터페이스
val list: List<Double> = listOf(20.18, 1.14, 9.15, 1.14) // 불변형
val list2: List<Double> = mutableListOf(20.18, 1.14, 9.15, 1.14) // 가변형
val list3: List<Int> = LinkedList<Int>() //LinkedList와
val list4: List<Int> = ArrayList<Int>() // ArrayList 2가지가 있다.
println(list[0]) // 20.18
println(list.indexOf(1.14)) // 1
println(list.indexOf(9.31)) // -1
println(list.lastIndexOf(1.14)) // 3
println(list.subList(0, 3)) // [20.18, 1.14, 9.15]
println(list.size) // List 크기
println(list.get(0)) // 해당 인덱스의 요소 가져오기
println(list.contains(2.0)) // 포함 여부 확인하기
List 인터페이스에는 indices()(인덱스의 범위), contains(), get()/elementAt()(해당 인덱스의 요소를 읽기), last(), first(), firstOrNull, lastOrNull, count(), distinct(), joinToString()(요소들의 값을 문자열로 변환하여 결합), single(요소 하나 반환), singleOrNull, binarySearch, find 등이 있다
이외에도 MutableList 인터페이스에는 slice(), containsAll(), asReversed()(모든 요소를 역순으로 저장한 새로운 List를 생성), toList(), toMutableList(), toSet(), toMutableSet(), toHashSet() 등이 있다 LinkedList에서만 사용할 수 있는 함수들은 addFirst(), addLast(), removeFirst(), removeLast() 등이 있다 그 외에도 max(), min() 등의 함수가 존재한다
List : Immutable
listOf<타입>(아이템, )로 Immutable List를 생성 및 초기화를 할 수 있습니다. 코틀린은 아이템의 타입을 추론하기 때문에 타입을 생략해도 됩니다. Immutable이기 때문에 get만 가능합니다. List의 getter는 자바처럼 get(index)도 지원하고 배열처럼 [index]도 지원합니다. 코틀린은 간결하고 직관적인 배열같은 표현 방식을 선호합니다.
val fruits= listOf<String>("apple", "banana", "kiwi", "peach")
// val fruits= listOf("apple", "banana", "kiwi", "peach") -> 타입 생략 가능
println("fruits.size: ${fruits.size}")
println("fruits.get(2): ${fruits.get(2)}")
println("fruits[3]: ${fruits[3]}")
println("fruits.indexOf(\"peach\"): ${fruits.indexOf("peach")}")
수정가능한 List는 mutableListOf로 선언합니다. listOf와 대부분 비슷하지만, 추가 및 삭제가 가능합니다. 자바의 Collection에 익숙하시다면 remove, add, addAll, removeAt 등은 이미 알고 계실 것입니다. 또 slice(), containsAll(), asReversed()(모든 요소를 역순으로 저장한 새로운 List를 생성), toList(), toMutableList(), toSet(), toMutableSet(), toHashSet() 등이 있다 LinkedList에서만 사용할 수 있는 함수들은 addFirst(), addLast(), removeFirst(), removeLast() 등이 있다 그 외에도 max(), min() 등의 함수가 존재한다
그 외에도 replace, replaceAll, contains, forEach 등의 메소드도 지원합니다.
불변형 List를 가변형으로 변환하기
// 불변형 List를 가변형으로 변환하기
val names: List<String> = listOf("one", "two", "three") // 불변형 List
val mutableNames = names.toMutableList() // 새로운 가변형 List 가 만들어짐
mutableNames.add("four")
println(mutableNames)
// [one, two, three, four]
Set
Set은 동일한 아이템이 없는 Collection입니다. Set의 아이템들의 순서는 특별히 정해져 있지 않습니다. Set은 null 객체를 갖고 있을 수 있습니다. 동일한 객체는 추가될 수 없기 때문에 null도 1개만 갖고 있을 수 있습니다. List와 같이 Set도 Immutable과 Mutable을 별개로 지원합니다. 이 타입의 구현체는 HashSet, LinkedHashSet, TreeSet 세 가지가 있다
Set : Immutable
setOf<타입>(아이템들)로 객체를 생성할 수 있습니다. 다음과 같이 객체 아이템들을 확인할 수 있습니다.
sortedSetOf() 함수는 자바의 TreeSet 컬렉션을 정렬된 상태로 반환합니다. 이 함수를 사용하려면 java.util.* 패키지를 임포트해야 합니다. TreeSet는 저장된 데이터의 값에 따라 정렬되는데, 일종의 개선된 이진 탐색 트리(Binary-search Tree)인 레드 블랙 트리(RB tree: Red-Black tree) 알고리즘을 사용해 자료구조를 구성합니다. HashSet보다 성능이 좀 떨어지고 데이터를 추가하거나 삭제하는 데 시간이 걸리지만 검색과 정렬이 뛰어나다는 장점이 있습니다.
linkedSetOf()는 자바의 LinkedHashSet 자료형을 반환하는 헬퍼 함수입니다. 링크드 리스트를 사용해 구현된 해시 테이블에 요소를 저장합니다. HashSet, TreeSet보다 느리지만 데이터를 가리키는 포인터 연결을 통해 메모리 저장 공간을 좀 더 효율적으로 사용할 수 있습니다.
import java.util.*
// 자바의 java.util.TreeSet 선언
val intsSortedSet: TreeSet<Int> = sortedSetOf(4, 1, 7, 2)
intsSortedSet.add(6)
intsSortedSet.remove(1)
println("intsSortedSet = ${intsSortedSet}")
intsSortedSet.clear() // 모든 요소 삭제
println("intsSortedSet = ${intsSortedSet}")
// Linked List를 이용한 HashSet
val intsLinkedHashSet: java.util.LinkedHashSet<Int> = linkedSetOf(35, 21, 76, 26, 75)
intsLinkedHashSet.add(4)
intsLinkedHashSet.remove(21)
println("intsLinkedHashSet $intsLinkedHashSet")
intsLinkedHashSet.clear()
println(intsLinkedHashSet)
Map
Map은 key와 value를 짝지어 저장하는 Collection입니다. Map의 key는 유일하기 때문에 동일한 이름의 key는 허용되지 않습니다.에 Map 또한 Immutable과 Mutable을 별개로 지원합니다. 이 타입의 구현체는 HashMap, LinkedHashMap, TreeMap 세 가지가 있다
// Map 인터페이스
val map: Map<String, String> = mapOf("Apple" to "사과", "Banana" to "바나나") // 불변형
println(map.size) // 2
println(map.keys) // [Apple, Banana]
println(map.values) // [사과, 바나나]
println(map.entries) // [Apple=사과, Banana=바나나]
println(map.containsKey("Cocoa")) // false
println(map.containsValue("바나나")) // true
println(map["Apple"]) // 사과
println(map.getOrDefault("Cocoa", "코코아")) // 코코아
// 맵 순회하기
for ((key, value) in map) {
println("key=$key, value=$value")
}
// MutableMap 인터페이스
val map: MutableMap<String, String> = mutableMapOf() // 가변형
println(map) // {}
println(map.put("Hi", "안녕1")) // null
println(map) // {Hi=안녕1}
map["Hi"] = "안녕2"
println(map) // {Hi=안녕2}
map.putAll(mapOf("How is it going?" to "잘 지내?", "Bye!" to "잘 가!"))
println(map) // {Hi=안녕2, How is it going?=잘 지내?, Bye!=잘 가!}
println(map.remove("Hi")) // 안녕2
println(map) // {How is it going?=잘 지내?, Bye!=잘 가!}
println(map.remove("Bye!", "잘 가!")) // true
println(map) // {How is it going?=잘 지내?}
map.clear()
println(map) {}
이외에도 getOrPut(k, v), toList(), toMutableMap(), toMap(), toSortedMap(), putAll() 등이 있다
Map의 기타 자료구조
앞에서 Set의 선언된 형태와 비슷하게 Map에서도 자바의 HashMap, SortedMap, LinkedHashMap을 사용할 수 있습니다
import java.util.*
// java.util.HashMap의 사용
val hashMap: HashMap<Int, String> = hashMapOf(1 to "Hello", 2 to "World")
println("hashMap = $hashMap")
// java.util.SortedMap 사용
val sortedMap: SortedMap<Int, String> = sortedMapOf(1 to "Apple", 2 to "Banana")
println("sortedMap = $sortedMap")
// java.util.LinkedHashMap의 사용
val linkedHash: LinkedHashMap<Int, String> = linkedMapOf(1 to "Computer", 2 to "Mouse")
println("linkedHash = $linkedHash")
Map : Immutable
Map은 mapOf<key type, value type>(아이템)로 생성할 수 있습니다. 아이템은 Pair객체로 표현하며, Pair에 key와 value를 넣을 수 있습니다. Pair(A, B)는 A to B로 간단히 표현이 가능합니다. 이런 문법이 가능한 것은 to가 Infix이기 때문입니다.
val numbersMap = mapOf<String, String>(
"1" to "one", "2" to "two", "3" to "three")
println("numbersMap: $numbersMap")
val numbersMap2 = mapOf(Pair("1", "one"), Pair("2", "two"), Pair("3", "three"))
println("numbersMap2: $numbersMap2")
// 실행해보면 모두 동일한 값을 갖고 있습니다.
// numbersMap: {1=one, 2=two, 3=three}
// numbersMap2: {1=one, 2=two, 3=three}
Map의 데이터를 읽는 것도 다른 Collection과 유사합니다. getter는 get(index)와 [index]를 모두 지원합니다. 코틀린은 배열 방식을 선호합니다. keys와 values는 key와 value만으로 구성된 Set을 리턴해줍니다.
val numbersMap = mapOf<String, String>(
"1" to "one", "2" to "two", "3" to "three")
println("numbersMap.get(\"1\"): ${numbersMap.get("1")}")
println("numbersMap[\"1\"]: ${numbersMap["1"]}")
println("numbersMap[\"1\"]: ${numbersMap.values}")
println("numbersMap keys:${numbersMap.keys}")
println("numbersMap values:${numbersMap.values}")
for (value in numbersMap.values) {
println(value)
}
실행 결과입니다.
numbersMap.get("1"): one
numbersMap["1"]: one
numbersMap["1"]: [one, two, three]
numbersMap keys:[1, 2, 3]
numbersMap values:[one, two, three]
one
two
three
Map : Mutable
Mutable은 mutableMapOf<key type, value type>(아이템)로 생성합니다. 객체 추가는 put 메소드이며, Pair를 사용하지 말고 인자로 key와 value를 넣어주면 됩니다. put도 배열 방식을 지원합니다. 그 외에 자바의 Map과 유사합니다.
val numbersMap = mutableMapOf<String, String>(
"1" to "one", "2" to "two", "3" to "three")
println("numbersMap: $numbersMap")
numbersMap.put("4", "four")
numbersMap["5"] = "five"
println("numbersMap: $numbersMap")
numbersMap.remove("1")
println("numbersMap: $numbersMap")
numbersMap.clear()
println("numbersMap: $numbersMap")
List와 Set은 Collection을 상속합니다. 이 클래스들은 Collection에 대입할 수 있기 때문에 아래와 같이 사용할 수 있습니다.
fun printAll(strings: Collection<String>) {
for(s in strings) print("$s ")
println()
}
val stringList = listOf("one", "two", "one")
printAll(stringList)
val stringSet = setOf("one", "two", "three")
printAll(stringSet)
실행 결과 입니다.
one two one
one two three
컬렉션 선택하기
List 인터페이스의 ArrayList와 LinkedList는 기본적으로는 무작위나 순차적인 처리 속도가 더 빠른 ArrayList를 선택하는 것이 좋다. 그러나 List의 중간에서 추가나 삭제를 자주 한다면 LinkedList를 사용하는 것이 좋다. 물론, 정해진 수의 요소들을 처리할 때는 배열을 사용하는 게 좋다 Set 인터페이스에는 LinkedHashSet, HashSet, TreeSet이 있다. 기본적으로는 코클린에서 생성 시 제공되는 LinkedHashSet을 사용하는 것이 좋으며, 무작위 검색의 성능이 매우 중요하다면 HashSet을, 그리고 요소의 일정한 순서 유지와 처리가 중요하다면 TreeSet을 사용하는 것이 좋다 Map 인터페이스는 LinkedHashMap, HashMap, TreeMap이 있다. 코틀린은 기본적으로 LinkedHashMap을 사용한다. HashMap은 무작위 검색 시에만 조금 더 유리하며, 정렬된 상태로 요소를 유지할 필요가 있을 때만 TreeMap을 사용하는 게 좋다. 그리고 Map은 크기가 성능을 좌우하므로 할당된 크기에 너무 많은 요소가 저장되지 않도록 하는 것이 중요하다
정렬
정렬에는 sorted(), sortedBy(), sortedDescending(), sortedDescendingBy()가 있다
정리
코틀린의 Collection인 Map, Set, List에 대해서 알아보았습니다. 자바와 다른 것은 Mutable과 Immutable을 구분하여 지원한다는 점입니다. 그 외의 지원하는 메소드는 자바와 거의 유사합니다.