제어문은 조건문과 반복문이 있는데, 반복문을 이해하려면 반복문에서 필수적으로 다루는 데이터 타입 배열과 컬렉션을 알아야 한다.
Int와 Double과 같은 기본 타입은 하나의 변수에 하나의 값만 저장할 수 있는데 하나의 변수에 여러 개의 값을 저장해야 할 때가 있을 것이다. 이럴 때 여러 개의 값을 하나의 변수에 저장할 수 있도록 배열(Array)과 컬렉션(Collection)이라는 데이터 타입을 배워보자.
배열은 값을 담기 전에 먼저 배열 공간의 개수를 할당하거나 초기화 시에 데이터를 저장해두면 데이터의 개수만큼 배열의 크기가 결정된다. 먼저 개수를 정해놓고 사용해야 하며, 중간에 개수를 추가하거나 제거할 수 없다. 다른 데이터 타입들과 마찬가지로 변수에 젖아해서 사용할 수 있다.
var 변수 = Array(개수) // 선언
// 배열 객체는 Int, Long, Char 등과 같은 기본 타입 뒤에 Array를 붙여서 만든다.
var students = IntArray(10)
var longArray = LongArray(10)
var charArray = CharArray(10)
var floatArray = FloatArray(10)
var doubleArray = DoubleArray(10)
위와 같이 정수형을 10개 할당하게 되면 각 공간의 위치를 뜻하는 인덱스가 [0]~[9]까지 생기게 된다. 컴퓨터는 1이 아닌 0을 첫 번째로 인식하도록 설계되어 있기 때문이다!
// 기본 타입이 아닌 String타입(문자 배열)에 빈 공간 할당
var stringArray = Array(10, {item->""})
// 값으로 배열 공간 할당하기
var dayArray = arrayOf("Mon", "TUE", "WED", "THU", "FRI", "SAT", "SUN")
// 배열에 값 입력하기
배열명[인덱스] = 값
배열명.set(인덱스, 값)
❗️배열의 범위를 벗어난 인덱스에 값을 넣을 경우❗️
10개의 공간이 할당된 배열에서 열한 번재에 해당하는 10번 인덱스에 값을 넣으려고 하면 범위를 넘어섰다는 Exception이 발생하고 프로그램이 종료된다.
var intArray = IntArray(10)
intArray[10] = 100
// Exception 발생. (intArray의 마지막 인덱스는 9)
-> ArrayIndexOutOfBoundsException 발생
// 배열에 있는 값 꺼내기
배열명[인덱스]
배열명.get(인덱스)
var seventhValue = intArray[6] //배열 intArray의 일곱 번째 값을 seventhValue 변수에 저장
var tenthValue = intArray.get(9) //배열 intArray의 열 번째 값을 get 함수를 사용해서 tenthValue 변수에 저장
여러 개의 값을 넣을 수 있는 자료형에는 배열 외에도 컬렉션이 있다. 배열과는 다르게 공간의 크기를 처음 크기로 고정하지 않고 임의의 개수를 담을 수 있기 때문에 동적 배열이라고도 한다.
컬렉션은 크게 세 가지로 리스트(List), 맵(Map), 셋(Set)이 있다.
리스트는 저장되는 데이터에 인덱스를 부여한 컬렉션이며 중복된 값을 입력할 수 있다. Kotlin에서 동적으로 리스트를 사용하기 위해서는 리스트 자료형 앞에 뮤터블(Mutable)이라는 접두어(Prefix)가 붙는다.
ex) mutableList, mutableMap, mutableSet
배열과 같이 '데이터 타입Of' 형태로 사용할 수 있다.
// 리스트 생성
var mutableList = mutableListOf("MON", "TUE", "WED") //3개의 값을 가진 크기가 3인 동적 배열 리스트 생성
// 리스트에 값 추가하기 : add
mutableList.add("THU") //값이 추가되면서 동적으로 리스트의 공간이 자동으로 증가.
// 리스트에 입력된 값 사용하기 : get
var variable = mutableList.get(1) // 두 번째 값을 변수에 저장.
// 입력할 때와는 다르게 사용할 때는 인덱스를 지정해서 몇 번째 값을 꺼낼 것인지 명시해야 함
리스트값 수정하기 : set
mutalbeList.set(1, "수정할 값") // 두 번째 값을 수정.
// 리스트에 입력된 값 제거하기 : removeAt
mutableList.removeAt(1) // 두 번째 값을 삭제
// "TUE"가 삭제되면서 3번 째 값인 "WED"의 인덱스는 2에서 1로 바뀌게 됨.
// 빈 리스트 사용하기
var 변수명 = mutableListOf<컬렉션에 입력될 값의 타입>()
var stringList = mutableListOf<String>()
//아무것도 없는 빈 리스트를 생성하면 앞으로 입력되는 값의 데이터 타입을 알 수 없어서 값의 타입을 추론할 수 없기 때문에 빈 컬렉션의 경우 데이터 타입을 직접적으로 알려주는 방법을 사용해야 한다.//
// 생성
var stringList = mutableListOf<String>()
stringList.add("월")
stringList.add("화")
// 사용
Log.d("Collection", "stringList에 입력된 두 번째 값은 ${stringList.get(1)}입니다.")
// 수정
stringList.set(1, "수정된 값"
// 삭제
stringList.removeAt(1)
// 컬렉션 개수 가져오기 : size 프로퍼티
mutableList.size //set, get처럼 () 있으면 함수, size처럼 없으면 프로퍼티!
셋은 중복을 허용하지 않는 리스트라고 할 수 있다. 리스트와 유사한 구조이지만 인덱스로 조회할 수 없고, get 함수도 지원하지 않는다.
// String 타입의 값 입력
var set = mutableSetOf<String>()
빈 셋으로 초기화하고 값 입력
set = mutableSetOf<String>()
set.add("JAN")
set.add("FEB")
set.add("MAR")
set.add("JAN") // 동일한 값은 입력되지 않음!
셋은 인덱스로 조회하는 함수가 없기 때문에 특정 위치의 값을 직접 사용할 수 없다.
// 셋에 있는 모든 값 출력해 보기
Log.d("Collection", "Set 전체 출력 = ${set}")
//삭제
set.remove("FEB") //셋은 값이 중복되지 않기 때문에 값을 직접 조회해서 삭제 가능
맵은 키와 값의 쌍으로 입력되는 컬렉션이다. 맵의 키는 마치 리스트에서의 인덱스와 비슷한데 리스트와는 다르게 키를 직접 입력해야 한다. <제네릭>으로 키와 값의 데이터 타입을 지정해서 맵을 생성한다.
// 키와 값의 타입을 모두 String으로 사용해 보기
var map = mutableMapOf<String, String>() //인덱스에 해당하는 키를 직접 지정해서 사용해야 함
// 빈 맵으로 생성하고 값 추가하기(키와 값을 추가할 때마다 리스트처럼 공간이 늘어남)
var map = mutableMapOf<String, String>()
map.put("키1", "값1")
map.put("키2", "값2")
map.put("키3", "값3")
// 출력해보기(get 함수에 키를 직접 입력해서 값 꺼낼수 있음)
Log.d("ColletionMap", "map에 입력된 키1의 값은 ${map.get("키1")}")
// 수정(키는 유지된 채로 그 값만 수정됨)
map.put("키", "수정")
// 삭제(리스트와 다르게 인덱스에 해당하는 키의 값이 변경되지 않고 그대로 유지)
map.remove("키2") // 키2 값이 삭제 돼도 키3은 그대로 유지
// ❗️없는 값을 불러오면 null 값이 출력됨❗️
Log.d("Collection", "키2의 값은 ${map.get("키2")}입니다.") --> null
코틀린은 일반 배열처럼 크기를 변경할 수 없으면서 값 또한 변경할 수 없는 이뮤터블 컬렉션을 지원한다. 이뮤터블 컬렉션은 기존 컬렉션에서 mutable이라는 접두어가 제거된 형태로 사용된다.
var list = listOf("1", "2")
불변형 컬렉션은 한 번 입력된 값을 변경할 수 없기 때문에 add나 set 함수는 지원하지 않고 최초 입력된 값을 사용만 할 수 있다.
// 생성
val IMMUTABLE_LIST = listOf("JAN", "FEB", "MAR")
// 사용
Log.d("Collection", "리스트의 두 번째 값은 ${IMMUTABLE_LIST.get(1)}입니다.")
배열과 다른 점은 크기뿐 아니라 값의 변경도 불가능하다는 것이다.
변수와 상수의 관계에서 그 사용법을 유추할 수 있는데 기준이 되는 어떤 값의 모음을 하나의 변수에 저장할 필요가 있거나 여러 개의 값을 중간에 수정하지 않고 사용할 필요가 있을 때 이뮤터블 컬렉션을 사용한다. ex) 요일 데이터
val DAY_LIST = listOf("월", "화", "수", "목", "금", "토", "일")
이뮤터블 컬렉션을 저장할 때는 상수로 선언하고 상수명을 대문자로 표시하는 게 좋고, 셋과 맵도 동일하게 사용한다.