BackEnd/Kotlin
15강. 코틀린에서 배열과 컬렉션을 다루는 방법
hanseom
2024. 3. 21. 05:00
반응형
- 배열(Array)
- 컬렉션(Collection) - List, Set, Map
- 컬렉션의 null 가능성
- Java와 함께 사용할 때 주의할 점
배열
배열은 잘 사용하지 않습니다. Effective Java에도 '배열보다 리스트를 사용하라'라고 되어 있습니다.
다음은 배열을 사용한 Java 코드입니다.
int[] array = {100, 200};
for (int i = 0; i < array.length; i++) {
System.out.printf("%s %s", i, array[i]);
}
Kotlin으로 구현하면 다음과 같습니다.
val array = arrayOf(100, 200)
for (i in array.indices) {
println("${i} ${array[i]}")
}
for ((idx, value) in array.withIndex()) {
println("$idx $value")
}
- array.indices: 0부터 마지막 index까지의 Range입니다.
- withIndex(): index와 value를 한 번에 가져올 수 있습니다.
Collection
컬렉션을 만들어 줄 때 불변인지, 가변인지를 설정해줘야 합니다. 다음은 Kotlin의 Collection 계층 구조입니다.
- 가변 (Mutable) 컬렉션: 컬렉션에 element를 추가, 삭제할 수 있습니다.
- 불변 컬렉션: 컬렉션에 element를 추가, 삭제할 수 없습니다. 단, 불변 컬렉션이라도 Reference Type인 Element의 필드는 바꿀 수 있습니다.

List
다음은 Java의 List 코드입니다.
public static void main(String[] args) {
// List
final List<Integer> numbers = Arrays.asList(100, 200);
// get
System.out.println(numbers.get(0));
// For Each
for (int number : numbers) {
System.out.println(number);
}
// for문
for (int i = 0; i < numbers.size(); i++) {
System.out.printf("%s %s,", i, numbers.get(i));
}
}
Kotlin으로 구현하면 다음과 같습니다.
fun main() {
// List
val numbers = listOf(100, 200)
val emptyList = emptyList<Int>() // 비어있는 리스트의 경우 타입을 명시해 주어야 합니다.
// get
println(numbers.get(0))
println(numbers[0])
// For Each
for (number in numbers) {
println(number)
}
// 전통적인 for문
for ((index, number) in numbers.withIndex()) {
println("$index $number")
}
}
emptyList의 경우, 타입을 추론할 수 있다면 생략 가능합니다.
fun main() {
printNumbers(emptyList())
}
private fun printNumbers(numbers: List<Int>) {
}
가변 리스트를 만들고 싶다면, listOf() 대신 mutableList()를 사용하면 됩니다.
val mutableNumbers = mutableListOf(100, 200)
mutableNumbers.add(300)
- add, remove, addAll, removeAll 같은 Java에 존재하는 모든 라이브러리 기능들이 Kotlin에도 존재합니다.
- 기본 구현체는 ArrayList이고, 기타 사용법은 Java와 동일합니다.
Note. 우선 불변 리스트를 만들고, 반드시 필요한 경우에만 가변 리스트로 바꾸어 사용합니다.
Set
집합은 List와 다르게 순서가 없고, 같은 element는 하나만 존재할 수 있습니다. 자료구조적 의미만 제외하면 모든 기능이 List와 비슷합니다.
다음은 Kotlin 코드입니다.
// Set
val setNumbers = setOf(100, 200)
// For Each
for (number in setNumbers) {
println(number)
}
// 전통적인 for문
for ((index, number) in numbers.withIndex()) {
println("$index $number")
}
가변(Mutable) 집합을 만들고 싶다면, mutableSetOf()를 사용하시면 됩니다.
val setNumbers = mutableSetOf(100, 200)
- 기본 구현체는 LinkedHashSet 입니다.
Map
다음은 Map을 생성하는 Java 코드입니다.
// JDK 8까지
Map<Integer, String> map = new HashMap<>();
map.put(1, "MONDAY");
map.put(2, "TUESDAY");
// JDK 9부터
Map.of(1, "MONDAY", 2, "TUESDAY");
Kotlin으로 구현하면 다음과 같습니다.
val oldMap = mutableMapOf<Int, String>()
oldMap.put(1, "MONDAY")
oldMap[2] = "TUESDAY"
mapOf(1 to "MONDAY", 2 to "TUESDAY")
- 가변 Map이기 때문에 (key, value)를 넣을 수 있습니다.
- Java처럼 put을 쓸 수도 있고, map[key] = value을 쓸 수도 있습니다.
- mapOf(key to value)를 사용해 불변 map을 만들 수 있습니다.
다음은 Java에서 Map을 활용하는 코드입니다.
for (int key : map.keySet()) {
System.out.println(key);
System.out.println(map.get(key));
}
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
Kotlin으로 구현하면 다음과 같습니다.
for (key in oldMap.keys) {
println(key)
println(oldMap[key])
}
for ((key, value) in oldMap.entries) {
println(key)
println(value)
}
컬렉션의 null 가능성
- List<Int?>: List에 null이 들어갈 수 있지만, List는 절대 null이 아닙니다.
- List<Int>?: List에는 null이 들어갈 수 없지만, List는 null일 수 있습니다.
- List<Int?>?: List에 null이 들어갈 수도 있고, List가 null일 수도 있습니다.
? 위치에 따라 null 가능성 의미가 달라지므로 차이를 잘 이해해야 합니다.
Java와 함께 사용할 때 주의할 점
- Java는 읽기 전용 컬렉션과 변경 가능 컬렉션을 구분하지 않습니다.
- Java는 nullable 타입과 non-nullable 타입을 구분하지 않습니다.
- Kotlin 쪽의 컬렉션이 Java에서 호출되면 컬렉션 내용이 변할 수 있음을 감안해야 합니다.
- Kotlin 쪽에서 Collections.unmodifableXXX()를 활용하면 변경 자체를 막을 수는 있습니다.
- Kotlin에서 Java 컬렉션을 가져다 사용할 때는 플랫폼 타입을 신경써야 합니다. Java 코드를 보며 맥락을 확인하고, Java 코드를 가져오는 지점을 wrapping해서 영향 범위를 최소화하는 것이 좋습니다.
감사합니다.
반응형