5.6 KiB
5.6 KiB
코틀린 컬렉션과 스트림 API vs 자바 스트림 API
코틀린은 자바와 마찬가지로 리스트(List), 세트(Set), 맵(Map) 등의 컬렉션을 제공한다. 하지만 자바와는 다르게, 컬렉션을 더욱 간결하게 다룰 수 있는 함수형 API를 기본 제공하며, 대부분의 연산을 람다식과 메서드 체이닝을 통해 쉽게 수행할 수 있다.
이번 글에서는 코틀린의 컬렉션 사용법과 자바 스트림 API와의 차이점을 비교해보겠다.
1. 코틀린 컬렉션 기본 개념
1.1. 불변(Immutable) vs 가변(Mutable) 컬렉션
코틀린의 컬렉션은 **불변형(listOf, setOf, mapOf)**과 **가변형(mutableListOf, mutableSetOf, mutableMapOf)**으로 나뉜다.
자바에서는 Collections.unmodifiableList() 등을 사용해야 하지만, 코틀린에서는 기본적으로 불변 컬렉션을 사용하도록 유도한다.
자바의 리스트 선언
List<String> immutableList = List.of("A", "B", "C"); // Java 9+
List<String> mutableList = new ArrayList<>();
mutableList.add("A");
mutableList.add("B");
코틀린의 리스트 선언
val immutableList = listOf("A", "B", "C") // 불변 리스트
val mutableList = mutableListOf("A", "B") // 가변 리스트
mutableList.add("C")
차이점 요약:
- 자바:
List.of()(불변) vsArrayList<>()(가변)- 코틀린:
listOf()(불변) vsmutableListOf()(가변)
2. 코틀린 컬렉션 사용 예제
2.1. 리스트(List)
val numbers = listOf(1, 2, 3, 4, 5)
println(numbers[0]) // 1
println(numbers.size) // 5
가변 리스트:
val mutableNumbers = mutableListOf(1, 2, 3)
mutableNumbers.add(4)
println(mutableNumbers) // [1, 2, 3, 4]
2.2. 집합(Set)
val names = setOf("Alice", "Bob", "Charlie")
println(names.contains("Alice")) // true
가변 집합:
val mutableNames = mutableSetOf("Alice", "Bob")
mutableNames.add("Charlie")
2.3. 맵(Map)
val userMap = mapOf("Alice" to 25, "Bob" to 30)
println(userMap["Alice"]) // 25
가변 맵:
val mutableUserMap = mutableMapOf("Alice" to 25)
mutableUserMap["Bob"] = 30
3. 코틀린의 스트림 API vs 자바의 스트림 API
자바에서는 컬렉션을 처리할 때 **스트림 API(Stream)**를 사용해야 하지만,
코틀린은 컬렉션 자체가 스트림 API처럼 동작한다.
3.1. 자바 스트림 예제
List<String> names = List.of("Alice", "Bob", "Charlie");
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("A"))
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(filteredNames); // [ALICE]
자바의 특징:
.stream()을 호출해야 함.collect(Collectors.toList())를 사용해야 리스트 반환
3.2. 코틀린 컬렉션 API 예제
val names = listOf("Alice", "Bob", "Charlie")
val filteredNames = names
.filter { it.startsWith("A") }
.map { it.uppercase() }
println(filteredNames) // [ALICE]
코틀린의 특징:
stream()없이 컬렉션 자체에서 메서드 체이닝 가능collect()없이 리스트 반환
3.3. 숫자 리스트 필터링 & 변환
자바 (Stream API 사용)
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);
List<Integer> evenSquares = numbers.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.collect(Collectors.toList());
System.out.println(evenSquares); // [4, 16, 36]
코틀린 (컬렉션 API 사용)
val numbers = listOf(1, 2, 3, 4, 5, 6)
val evenSquares = numbers
.filter { it % 2 == 0 }
.map { it * it }
println(evenSquares) // [4, 16, 36]
차이점 요약:
- 자바:
.stream()호출 →filter(),map()→.collect(Collectors.toList())필요- 코틀린: 바로
filter(),map()사용 가능
4. 추가적인 컬렉션 함수들
4.1. forEach
val numbers = listOf(1, 2, 3)
numbers.forEach { println(it) }
4.2. groupBy
val words = listOf("apple", "banana", "avocado", "blueberry")
val grouped = words.groupBy { it.first() }
println(grouped)
// {a=[apple, avocado], b=[banana, blueberry]}
4.3. associateBy (키 매핑)
data class Person(val name: String, val age: Int)
val people = listOf(Person("Alice", 25), Person("Bob", 30))
val personMap = people.associateBy { it.name }
println(personMap["Alice"]) // Person(name=Alice, age=25)
5. 정리: 코틀린 vs 자바 스트림 API 차이점
| 기능 | 자바 (Stream API) | 코틀린 (컬렉션 API) |
|---|---|---|
| 스트림 사용 | .stream() 필요 |
컬렉션 자체에서 사용 가능 |
| 리스트 반환 | .collect(Collectors.toList()) 필요 |
자동 반환 |
filter() 사용 |
filter(n -> 조건) |
filter { it 조건 } |
map() 사용 |
map(n -> 변환) |
map { it 변환 } |
| 그룹핑 | .collect(Collectors.groupingBy()) |
groupBy { it 기준 } |
| 가변 리스트 | new ArrayList<>() |
mutableListOf() |
코틀린은 컬렉션을 더욱 직관적이고 간결하게 다룰 수 있도록 설계되었다.
자바에서 스트림 API를 써야 하는 많은 경우를 코틀린에서는 기본 컬렉션 함수만으로 해결할 수 있다.
코틀린으로 스트림 API를 더 쉽게 다룰 수 있다는 점을 기억하자!