1. 배열
배열은 production에서 잘 사용하지 않는다.
effective java에서도 배열보다는 List를 사용하라고 하였다.
그 이유 중 하나는 배열은 공변이기 때문이다.
자바에서 배열코드
int[] array = {100, 200};
for (int i = 0; i < array.length; i++) {
System.out.println("i = " + i);
System.out.println("array[i] = " + array[i]);
}
코틀린에서 배열코드
fun main() {
var array = arrayOf(100, 200)
for (element in array) {
println("element = ${element}")
}
for (index in array.indices) { // indices는 0부터 마지막 index까지의 Range이다.
println("i = ${index}")
println("array[i] = ${array[index]}")
}
for ((index, value) in array.withIndex()) {
println("index = ${index}")
println("value = ${value}")
}
array = array.plus(300) // 새로운 array 반환된다.
println(array.size) // 3
}
2. 코틀린에서의 Collection – List, Set, Map
List
컬렉션을 만들어줄 때 불변인지, 가변인지를 설정해야 한다
Mutable : 변하기 쉬운 ( 가변 )
Immutable : 변경되지 않는 ( 불변 )
가변 (Mutable) 컬렉션 : 컬렉션에 element를 추가, 삭제할 수 있다.
불변 컬렉션 : 컬렉션에 element를 추가, 삭제할 수 없다.
자바에서는 Collections.unmodifiableList() 를 사용하여 불변 컬렉션을 만들거나
public static void main(String[] args) {
List<String> originalList = new ArrayList<>();
originalList.add("A");
originalList.add("B");
List<String> unmodifiableList = Collections.unmodifiableList(originalList);
// 읽기 가능
System.out.println(unmodifiableList.get(0)); // 출력: A
// 수정 시도 (예외 발생)
unmodifiableList.add("C"); // UnsupportedOperationException
}
List.of 를 이용하여 불변 컬렉션을 만든다.
public class Main {
public static void main(String[] args) {
List<String> immutableList = List.of("A", "B", "C");
// 읽기 가능
System.out.println(immutableList.get(0)); // 출력: A
// 수정 시도 (예외 발생)
immutableList.add("D"); // UnsupportedOperationException
}
}
Arrays.asList()는 일부만 불변
public class Lec15Main {
public static void main(String[] args) {
/*
Arrays.asList로 생성된 리스트는 크기가 고정됩니다.
리스트의 요소는 수정할 수 있습니다
Arrays.asList로 생성된 리스트는 내부적으로 배열을 기반으로 하며, 배열과 리스트는 서로 연결되어 있습니다.
원본 배열을 변경하면 리스트도 영향을 받고, 반대로 리스트를 변경하면 배열도 영향을 받습니다.
*/
List<Integer> numbers = Arrays.asList(100, 200);
}
}
불변 컬렉션이라 하더라도 Element의 필드는 바꿀 수 있다.
[ Collection의 element의 field값은 수정가능 ]
코틀린에서 리스트 만들어보기
fun main() {
/*
입력된 값으로 타입이 추론 가능하므로 타입 생략가능하다.
생략안하면 listOf<Int>(100,200)처럼도 가능
listOf는 불변 리스트를 만든다.
*/
val numbers = listOf(100,200)
/*
emptyList는 비어있는 리스트를 만들 수 있다.
타입이 추론 가능하면 타입을 생략 가능하다.
*/
val emptyList = emptyList<Int>()
/*
printNumbers에는 Int 요소 List를 받기에
타입이 생략가능하다.
*/
printNumbers(emptyList())
}
private fun printNumbers(numbers: List<Int>) {
}
코틀린에서 리스트 출력해보기
fun main() {
val numbers = listOf(100,200) // 불변 리스트
println(numbers.get(0))
println(numbers[0])
for (number in numbers) {
println(number)
}
for ((index, value) in numbers.withIndex()) {
println("numbers[$index] = $value")
}
}
코틀린 가변 리스트 생성
fun main() {
val mutableList = mutableListOf(100, 200) // 가변 리스트
mutableList.add(300)
println(mutableList.get(0))
println(mutableList[0])
for (number in mutableList) {
println(number)
}
for ((index, value) in mutableList.withIndex()) {
println("numbers[$index] = $value")
}
}
mutableListOf()의 반환값은 ArrayList이기 때문에
list.add(요소)와 같은
자바에 존재하는 List 메서드들을 코틀린에서 그대로 사용할 수 있다.
우선 불변 리스트를 만들고, 꼭 필요한 경우 가변 리스트로 바꾸자!
Set
집합은 List와 다르게 순서가 없고, 같은 element는 하나만 존재할 수 있다.
자료구조적 의미만 제외하면 모든 기능이 List와 비슷하다.
요소가 여러개라면 요소의 삽입순서를 유지하는 LinkedHashSet을 반환한다.
요소가 하나라면 singletonSet을 만들어준다.
setOf(요소..)
들 사용하면 불변 Set을 반환한다.
기본적으로 LinkedHashSet은 가변 Set이지만 setOf()로 반환되는 LinkedHashSet은 불변으로 처리되서 반환된다.
가변(Mutable)Set 만들기
fun main() {
val numbers = mutableSetOf(100,200)
for (number in numbers) {
println(number)
}
for ((index, value) in numbers.withIndex()) {
println("numbers[$index] = $value")
}
}
이 또한 반환 Set은 LinkedHashSet이고 가변 Set이다.
Map
자바코드에서 Map 생성 및 출력
public static void main(String[] args) {
// JDK 8까지
Map<Integer, String> map = new HashMap<>(); // 가변 Map
map.put(1, "MON");
map.put(2, "TUE");
// JDK 9부터
Map<Integer, String> map2 = Map.of(1, "MON", 2, "TUE"); // 불변 Map
for (int key : map.keySet()) {
System.out.println("key = " + 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());
}
}
코틀린에서 Map 생성 및 출력
fun main() {
/*
타입을 추론 못하니까 mutableMapOf에는 타입을 넣어줬다.
*/
val oldMap = mutableMapOf<Int, String>() // 가변 map 반환
oldMap.put(1, "MON") // 옛날 스타일
oldMap[2] = "TUE" // 권장 스타일
val newMap = mapOf(1 to "MON", 2 to "TUE") // mapOf는 불변 MAP 반환
for (key in oldMap.keys) {
println(key)
// println(oldMap.get(key)) 옛날방식
println(oldMap[key])
}
for ((key, value) in oldMap.entries) {
println("key = ${key}")
println("value = ${value}")
}
}
Kotlin도 동일하게 MutableMap을 만들어 넣을 수도 있고, 정적 팩토리 메소드(mapOf)를 바로 활용할 수도 있다.
3. 컬렉션의 null 가능성, Java와 함께 사용하기
? 위치에 따라 null가능성 의미가 달라지므로 차이를 잘 이해해야한다.
주의할점 1
Java는 읽기 전용 컬렉션과 변경 가능 컬렉션을 구분하지 않는다
주의할점 2
Java는 nullable 타입과 non-nullable 타입을 구분하지 않는다.
Kotlin 쪽의 컬렉션이 Java에서 호출되면 컬렉션 내용이 변할 수 있음을 감안해야 한다
자바에서 컬렉션이 돌아왔을때 검증을 할 수 있는 방어로직을 짜던가,
코틀린 쪽에서 Collections.unmodifableXXX()를 사용해서 컬렉션을 생성하면 자바에서도 해당 컬렉션이 불변컬렉션으로 구분되서 변경 자체를 막을 수는 있다.
ex) Collections.unmodifableList()
Kotlin에서 Java 컬렉션을 가져다 사용할때 플랫폼 타입을 신경써야 한다.
Java 코드를 보며, 맥락을 확인하고 Java 코드를 가져오는 지점을 wrapping한다
자바에서 코드 가져오는 부분에 대한 함수를 만들고 그 안에서 null이 없어야하는데 들어있는지 등.. 과 같은 검증을 진행하고
받아오는 로직이 들어있는 함수를 만들어서 그 함수를 통해 컬렉션을 받아와야한다는것이다.
'인프런 > 자바 개발자를 위한 코틀린 입' 카테고리의 다른 글
10) 코틀린에서 람다를 다루는 방법 (0) | 2025.01.10 |
---|---|
9) 코틀린에서 다양한 함수를 다루는 방법 (0) | 2025.01.10 |
7) 코틀린에서 object 키워드, 중첩 클래스, 다양한 클래스를 다루는 방법 (0) | 2025.01.09 |
6) 코틀린에서 접근 제어를 다루는 방법 (0) | 2025.01.09 |
5) 코틀린에서 상속을 다루는 방법 (0) | 2025.01.08 |
댓글