TECHIT 앱 스쿨 2기: Android 20일차 (23.05.23)
자료 출처 : 안드로이드 앱스쿨 2기 윤재성 강사님 수업 내용
오늘 오전에는 어제 내주신 간단한 과제에 대하여 설명 및 중첩클래스와 데이터 클래스를 이용하여 작성하면서 개념을 설명해주셨습니다.
오후에는 배열과 문자열, 컬렉션에 대해서 설명해주셨습니다.
코틀린에서 배열은 개발자가 편한대로 작성할 수 있도록 배열관련 문법들을 지원합니다.
배운 내용과 더불어 알고 있는 내용을 조금 추가하여 작성하였으며, 이해하기 쉽도록 IntArray 을 사용하였으며 IntArray 대신 Array를 작성하여도 되며 Array로 작성할 경 코드에서는 c2에 들어가는 람다식에서 자료형을 추가하면 됩니다.
그리고 새로운 배열이 생성되는 것을 확인하기 위하여 변수를 변경하지 않고 진행하였습니다.
fun main(){
// 기본 배열
val a1 = arrayOf(10,20)
val a11 = arrayOf(10,"문자",11.11)
// a2 ~ a4 는 해당 자료형만 저장하는 배열
// String은 일반 배열
val a2 = intArrayOf(100,200)
val a3 = doubleArrayOf(11.11)
val a4 = booleanArrayOf(true, false)
val a5 = charArrayOf('a','b','c')
val a6 = arrayOf("문자열")
println("배열 내용 출력 방법 .contentToString()")
println("a1.contentToString() : ${a1.contentToString()}")
println("---------------------------")
// 크기가 정해져 있는 배열 생성
// { } 안에 숫자를 적어도 되고, 규칙성 있는 배열을 만들고 싶다면
// 람다식을 전달하여 작성할 수 있다.
val b1 = Array(5){0}
// it 은 인덱스 번호가 들어온다 0,1,2,3,4
val b2 = Array(5){ (it+1)*5 }
println("b1 : ${b1.contentToString()}")
println("b2 : ${b2.contentToString()}")
println("---------------------------")
// 크기가 정해져 있는 배열에서 특정 자료형만을 저장 하는 배열
// String 제외
val c1 = IntArray(5){it * 5}
println("c1 : ${c1.contentToString()}")
// 배열의 형식이 정해져 있기 때문에 자료형을 생략한 람다식 전달 가능
var c2 = IntArray(5){ i -> i * 10}
println("c2 : ${c2.contentToString()}")
println("---------------------------")
// 자바에서는 배열에 값(객체)를 추가하는 것이 안되었지만
// 코틀린에서는 문법 표시상으로는 추가하는 것처럼 보이게 할 수 있다.
// 하지만 실제로는 새로운 배열을 만들어 ID를 전달한다.
// 하기 코드는 c2에 500을 더한 배열을 생성하여 c2변수에 생성한 배열(객체)의 ID를 전달한 것이다.
println("기존 c2 : ${c2.contentToString()}")
println("기존 c2에 저장된 객체의 ID : $c2")
c2 += 500
println("c2 += 500 : ${c2.contentToString()}")
println("c2 += 500 하고 난 후 c2에 저장된 객체의 ID: $c2")
println("---------------------------")
// 배열의 값(객체) 변경
println("기존 c2 : ${c2.contentToString()}")
c2[0] = 100
println("c2[0] = 100 변경 : ${c2.contentToString()}")
println("---------------------------")
// 배열의 일부를 가져와 새로운 배열로 만들기
println("기존 c2 : ${c2.contentToString()}")
println("기존 c2에 저장된 객체의 ID : $c2")
c2 = c2.sliceArray(1 .. 3)
println("c2 : ${c2.contentToString()}")
println("c2 = c2.sliceArray(1 .. 3) 이후 c2에 저장된 객체의 ID: $c2")
println("---------------------------")
// 배열이 지원하는 다양한 메서드들
println("기존 c2 : ${c2.contentToString()}")
println("첫 번째 값 : ${c2.first()}")
println("마지막 값 : ${c2.last()}")
println("30의 위치 : ${c2.indexOf(30)}")
println("평균 : ${c2.average()}")
println("합 : ${c2.sum()}")
println("개수 : ${c2.count()}")
println("개수 : ${c2.size}")
println("30을 포함하는 가 : ${c2.contains(30)}")
println("1000 을 포함하는 가 : ${c2.contains(1000)}")
println("30을 포함하는 가 : ${30 in c2}")
println("1000을 포함하는 가 : ${1000 in c2}")
println("최대 : ${c2.max()}")
println("최소 : ${c2.min()}")
println("---------------------------")
// 배열 내 저장된 값을 정렬하여 새로운 배열을 생성한다.
var c3 = intArrayOf(100,300,200,600,500)
println("기존 c3 : ${c3.contentToString()}")
println("기존 c3에 저장된 객체의 ID : $c3")
c3 = c3.sortedArray()
println("c3.sortedArray() 결과 ${c3.contentToString()}")
println("c3.sortedArray() 이후 객체의 ID : $c3")
c3 = c3.sortedArrayDescending()
println("c3.sortedArrayDescending() 결과 ${c3.contentToString()}")
println("c3.sortedArrayDescending() 이후 객체의 ID : $c3")
println("---------------------------")
// 다 차원 배열 만들기
val c4 = arrayOf(
arrayOf(10,20,30),
arrayOf(40,50,60),
arrayOf(70,60,90)
)
println("array9 : $c4")
println("array9 : ${c4.contentToString()}")
println("array9 : ${c4.contentDeepToString()}")
for(item in c4){
for(item2 in item){
println("item2 : $item2")
}
}
}
출력결과
배열 내용 출력 방법 .contentToString()
a1.contentToString() : [10, 20]
---------------------------
b1 : [0, 0, 0, 0, 0]
b2 : [5, 10, 15, 20, 25]
---------------------------
c1 : [0, 5, 10, 15, 20]
c2 : [0, 10, 20, 30, 40]
---------------------------
기존 c2 : [0, 10, 20, 30, 40]
기존 c2에 저장된 객체의 ID : [I@1d81eb93
c2 += 500 : [0, 10, 20, 30, 40, 500]
c2 += 500 하고 난 후 c2에 저장된 객체의 ID: [I@506e1b77
---------------------------
기존 c2 : [0, 10, 20, 30, 40, 500]
c2[0] = 100 변경 : [100, 10, 20, 30, 40, 500]
---------------------------
기존 c2 : [100, 10, 20, 30, 40, 500]
기존 c2에 저장된 객체의 ID : [I@506e1b77
c2 : [10, 20, 30]
c2 = c2.sliceArray(1 .. 3) 이후 c2에 저장된 객체의 ID: [I@6e2c634b
---------------------------
기존 c2 : [10, 20, 30]
첫 번째 값 : 10
마지막 값 : 30
30의 위치 : 2
평균 : 20.0
합 : 60
개수 : 3
개수 : 3
30을 포함하는 가 : true
1000 을 포함하는 가 : false
30을 포함하는 가 : true
1000을 포함하는 가 : false
최대 : 30
최소 : 10
---------------------------
기존 c3 : [100, 300, 200, 600, 500]
기존 c3에 저장된 객체의 ID : [I@31cefde0
c3.sortedArray() 결과 [100, 200, 300, 500, 600]
c3.sortedArray() 이후 객체의 ID : [I@1d56ce6a
c3.sortedArrayDescending() 결과 [600, 500, 300, 200, 100]
c3.sortedArrayDescending() 이후 객체의 ID : [I@5197848c
---------------------------
array9 : [[Ljava.lang.Integer;@2e0fa5d3
array9 : [[Ljava.lang.Integer;@5010be6, [Ljava.lang.Integer;@685f4c2e, [Ljava.lang.Integer;@7daf6ecc]
array9 : [[10, 20, 30], [40, 50, 60], [70, 60, 90]]
item2 : 10
item2 : 20
item2 : 30
item2 : 40
item2 : 50
item2 : 60
item2 : 70
item2 : 60
item2 : 90
배열 다음으로는 문자열에 대하여 학습하였습니다.
fun main(){
val str = "가나다라마바사"
// 원하는 번째에 해당하는 글자를 가져온다.
println("str[0] : ${str[0]}")
println("str[5] : ${str[5]}")
// 원하는 번째에 해당하는 글자를 변경하는 것은 불가능 하다.
// str[6] = "가"
// str[6] = '가'
// 하지만 특정 문구를 바꾸고 싶다면 replace() 를 사용하여
// 새로운 문자열을 생성할 수 있다.
val str2 = str.replace("사", "가")
println("str.replace(\"사\", \"가\") : $str2")
println("---------------------------------")
// 특정 범위의 글자들을 추출하여 새로운 문자열로 받아온다.
val str3 = str.substring(2,5)
println("str.substring(2,5) : $str3")
println("---------------------------------")
// 문자열 비교
val str4 = "Hello World"
val str5 = "hello world"
val str6 = "Hello World"
// 코틀린에서 == 가지고 비교를 하면 문자열 값 자체를 비교하는 작업을 수행한다.
if(str4 == str5){
println("str3과 str4는 같습니다.")
}
if(str4 == str6){
println("str3과 str5는 같습니다.")
}
// compareTo : 같으면 0. 다르면 0 이 아닌 값이 나온다.
// compareTo 는 문자영을 구성하는 각 글자의 코드 값을 합산한 결과를 뺀 값을 전달한다.
println(str4.compareTo(str5))
println(str4.compareTo(str6))
// 두 번째 매개 변수에 true를 넣어주면
// 모두 소문자로 변환한 다음 코드값을 빼는 작업을 수행한다.
// 대소문자를 구분하고 같은가를 확인한다.
println(str4.compareTo(str5, true))
// 대소문자를 무시하고 같은지를 비교한다.
if(str4.equals(str5, true)){
println("대소문자 무시하고 같습니다.")
}
println("------------------------------------")
// 문자열 병합
val str7 = "abc"
// 두 문자열을 합친 새로운 문자열을 만들어 준다.
val str8 = str7 + "def"
// 문자열이 아닌 값을 새로운 문자열로 만든 다음
// 두 문자열을 합친 새로운 문자열을 만들어준다.
val str9 = str8 + 10
println("str7 : $str7")
println("str8 : $str8")
println("str9 : $str9")
// String은 문자열 합치는 작업을 수행할 때 마다 새로운 문자열 객체가
// 계속 생성된다(String은 관리하는 문자열 수정이 불가능하기 때문에...)
// 이럴 때는 StringBuffer를 사용한다.
val buffer1 = StringBuffer()
buffer1.append("abc")
buffer1.append(100)
buffer1.append(11.11)
println("buffer1 : $buffer1")
println("------------------------------------")
// 구분자를 기준으로 문자열을 나눈다. -> 나누어 list 형태로 반환한다.
val str10 = "가 나 다 라 마 바 사 아"
// 공백을 기준으로 나누었다.
val r1 = str10.split(" ")
println("r1 : $r1")
}
출력결과
str[0] : 가
str[5] : 바
str.replace("사", "가") : 가나다라마바가
---------------------------------
str.substring(2,5) : 다라마
---------------------------------
str3과 str5는 같습니다.
-32
0
0
대소문자 무시하고 같습니다.
------------------------------------
str7 : abc
str8 : abcdef
str9 : abcdef10
buffer1 : abc10011.11
------------------------------------
r1 : [가, 나, 다, 라, 마, 바, 사, 아]
다음은 컬렉션 입니다.
list,map,set 등 모두 깊게 들어가면 hashMap 등등 나오지만 기본 개념 위주로 학습하였습니다.
List
fun main(){
// 리스트 생성
// 불변형 리스트
// 리스트 생성 이후 값의 추가, 수정, 삽입, 삭제가 불가능하다.
val list1 = listOf(10, 20 ,30, 40, 50)
println("list1 : $list1")
val list2 = listOf("문자열1", "문자열2", "문자열3")
println("list2 : $list2")
val list3 = listOf(100, 11.11, "문자열", true)
println("list3 : $list3")
// 수정 가능 한 리스트
// ArrayList로 생성된다.
val list4 = mutableListOf<Int>()
val list5 = mutableListOf("문자열1", "문자열2", "문자열3")
println("list4 : $list4")
println("list5 : $list5")
// 비어있는 수정 불가능한 리스트
val list6 = emptyList<Int>()
println("list6 : $list6")
// null값을 제외하고 생성한다.
val list7 = listOf(10, 20, null, 40, null, 60, 70)
val list8 = listOfNotNull(10, 20, null, 40, null, 60, 70)
println("list7 : $list7")
println("list8 : $list8")
println("---------------------------------------")
// for 문 사용
for(item in list1){
println("item : $item")
}
// 개수
println("list1.size : ${list1.size}")
// 관리할 객체들(값들)이 있고 나중에 추가, 삭제 등을 하지 않을 경우 : arrayOf
// 관리할 객체들(값들)이 없으며, 나중에 추가, 삭제 등을 하는 경우 : ArrayList, mutableListOf
// 관리할 객체들(값들)이 있고 나중에 추가, 삭제 등을 하는 경우 : mutableListOf
// 관리할 객체들(값들)이 있고 나중에 추가, 삭제 등을 하지 않고 관리하는 값을 변경하지 못하게 강제하고 할 때 : listOf
println("---------------------------------------")
// 관리하는 객체(값)에 접근
// [ ] 연산자를 통해 순서값(0부터 1씩 증가)를 지정하여 접근한다.
println("list1 0 : ${list1[0]}")
println("list1 1 : ${list1[1]}")
println("---------------------------------------")
// 일부를 발췌하여 새로운 리스트로 생성한다.
val list9 = listOf(10, 20, 30, 10, 20, 30)
// 지정된 값이 앞에서 부터 몇 번째에 있는가
val index1 = list9.indexOf(20)
println("index1 : $index1")
// 지정된 값이 뒤에서 부터 찾아서 앞에서 부터 몇 번째에 있는가
val index2 = list9.lastIndexOf(20)
println("index2 : $index2")
// 일부를 발췌해 새로운 리스트로 만들어 준다.
// 순서 값 1 ~ 3 -1 까지
val list10 = list9.subList(1, 3)
println("list10 : $list10")
println("---------------------------------------")
val list20 = listOf(10, 20, 30)
val list21 = mutableListOf(10, 20, 30)
// 수정 불가능한 리스트에 값 추가
// 수정 불가능한 리스트에는 추가, 삭제, 수정, 삽입 등의 메서드가 없다.
// list20.add(100)
// list20[1] = 200
// 수정이 가능한 리스트에 대한 추가, 수정, 삭제, 삽입
// 추가
list21.add(40)
list21.add(50)
list21.addAll(listOf(60, 70, 80, 90, 100))
println("list21 : $list21")
// 삽입
// 순서값 1(두 번째)에 1000을 삽입하고 그 이후의 값들은 뒤로 밀린다.
list21.add(1, 1000)
println("list21 : $list21")
// 순서값 3(네 번째)에 지정된 요소가 관리하는 값드을 모두 추가하고 그 이후의 값들은 뒤로 밀린다.
list21.addAll(3, listOf(2000, 3000, 4000, 5000))
println("list21 : $list21")
// 제거
// 지정된 값을 제거한다.
list21.remove(1000)
println("list21 : $list21")
// 제거 하고자 하는 값이 같은 것이 여러개가 있다면 제일 앞쪽에는 값 하나만 제거한다.
list21.add(1000)
list21.add(1000)
list21.add(1000)
println("list21 : $list21")
list21.remove(1000)
println("list21 : $list21")
// 없는 값을 제거
// 아무 작업도 하지 않는다.
list21.remove(10000)
println("list21 : $list21")
// 제거 하기 위해 지정한 것들을 모두 제거한다.
list21.removeAll(listOf(2000, 3000, 4000, 5000))
println("list21 : $list21")
// removeAll을 통해 같은 값이 다수 저장되어 있는 것을 제거
list21.removeAll(listOf(1000))
println("list21 : $list21")
// 위치를 지정하여 제거한다.
// 두 번재 값을 제거한다.
list21.removeAt(1)
println("list21 : $list21")
// 값을 수정한다.
// 두 번재 값을 200으로 덮어 씌운다.
list21.set(1, 200)
println("list21 : $list21")
list21[2] = 300
println("list21 : $list21")
println("---------------------------------------")
val list100 = listOf(10, 20, 30, 40, 50)
// list 안에 저장되어 있는 객체(값)을 추출하여 mutableList로 생성하여 반환한다.
val list200 = list100.toMutableList()
list200.add(60)
println("list100 : $list100")
println("list200 : $list200")
// mutableList 안에 저장되어 있는 객체(값)을 추출하여 list로 생성하여 반환한다.
val list300 = list200.toList()
// list300.add(70)
}
출력결과
list4 : []
list5 : [문자열1, 문자열2, 문자열3]
list6 : []
list7 : [10, 20, null, 40, null, 60, 70]
list8 : [10, 20, 40, 60, 70]
---------------------------------------
item : 10
item : 20
item : 30
item : 40
item : 50
list1.size : 5
---------------------------------------
list1 0 : 10
list1 1 : 20
---------------------------------------
index1 : 1
index2 : 4
list10 : [20, 30]
---------------------------------------
list21 : [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
list21 : [10, 1000, 20, 30, 40, 50, 60, 70, 80, 90, 100]
list21 : [10, 1000, 20, 2000, 3000, 4000, 5000, 30, 40, 50, 60, 70, 80, 90, 100]
list21 : [10, 20, 2000, 3000, 4000, 5000, 30, 40, 50, 60, 70, 80, 90, 100]
list21 : [10, 20, 2000, 3000, 4000, 5000, 30, 40, 50, 60, 70, 80, 90, 100, 1000, 1000, 1000]
list21 : [10, 20, 2000, 3000, 4000, 5000, 30, 40, 50, 60, 70, 80, 90, 100, 1000, 1000]
list21 : [10, 20, 2000, 3000, 4000, 5000, 30, 40, 50, 60, 70, 80, 90, 100, 1000, 1000]
list21 : [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 1000, 1000]
list21 : [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
list21 : [10, 30, 40, 50, 60, 70, 80, 90, 100]
list21 : [10, 200, 40, 50, 60, 70, 80, 90, 100]
list21 : [10, 200, 300, 50, 60, 70, 80, 90, 100]
---------------------------------------
list100 : [10, 20, 30, 40, 50]
list200 : [10, 20, 30, 40, 50, 60]
Map
fun main(){
// 수정 불가능한 map
// 이름 to 값(객체)
// 이름은 꼭 문자열이 아니어도 된다.
val map1 = mapOf("key1" to 10, "key2" to 20, "key3" to 30)
println("map1 : $map1")
val map2 = mapOf(10 to "str1", 20 to "str2", 30 to "str3")
println("map2 : $map2")
// 수정 가능한 map
val map3 = mutableMapOf("key1" to 10, "key2" to 20, "key3" to 30)
println("map3 : $map3")
// mapOf 혹은 mutableMapOf를 사용할 때 제네릭을 설정하는 것을 권장하고 있다.
// 이름과 값의 타입이 모두 같을 경우
val map4 = mapOf<String, Int>("key1" to 10, "key2" to 20, "key3" to 30)
println("map4 : $map4")
// 만약 이름이나 값의 타입이 다양하게 저장된다면 Any로 설정해준다.
val map5 = mapOf<String, Any>("key1" to 10, "key2" to 11.11)
println("map5 : $map5")
// 제네릭은 어떠한 경우라도 생략이 가능하기 때문에 그냥 생략하고 사용해도 된다.
val map6 = mapOf("key1" to 10, "key2" to 20, "key3" to 30)
val map7 = mapOf("key1" to 10, "key2" to 11.11)
println("map6 : $map6")
println("map7 : $map7")
// 비어있는 map
// 비어있는 map을 만들 때는 값이 없기 때문에 제네릭을 자동으로 설정할 수 없다.
// 따라서 제네릭을 무조건 작성해 줘야 한다.
val map8 = mapOf<String,Int>()
val map9 = mutableMapOf<String, Int>()
println("-------------------------------")
// 관리하는 객체(값)을 가지고 온다.
val map10 = mapOf("key1" to 10, "key2" to 20, "key3" to 30)
val map11 = mutableMapOf("key1" to 10, "key2" to 20, "key3" to 30)
println("map10 key1 : ${map10.get("key1")}")
println("map11 key1 : ${map11.get("key1")}")
println("map10 key1 : ${map10["key1"]}")
println("map11 key1 : ${map11["key1"]}")
println("-------------------------------")
// 관리하는 값(객체)의 개수
println("map1 size : ${map1.size}")
// 이름들을 가져온다.
println("map1 keys : ${map1.keys}")
// 값들을 가져온다.
println("map1 values : ${map1.values}")
// 이 이름의 값이 있는지 확인하기
println("map1 contains ket - key1 : ${map1.containsKey("Key1")}")
println("map1 contains ket - key100 : ${map1.containsKey("Key100")}")
// 이 값이 저장되어 있는지
println("map1 contains value - 10 : ${map1.containsValue(10)}")
println("map1 contains value - 100 : ${map1.containsValue(100)}")
println("-------------------------------")
val map12 = mutableMapOf("a1" to 10, "a2" to 20)
println("map12 : $map12")
// 추가
map12.put("a3",30)
println("map12 : $map12")
map12["a4"] = 40
println("map12 : $map12")
// 수정 : 없는 이름으로 값을 넣어주면 추가가 되고 있는 이름으로 값을 넣어주면
// 수정된다.
map12["a1"] = 100
println("map12 : $map12")
// 삭제
map12.remove("a1")
println("map12 : $map12")
println("-------------------------------")
// mapOf -> mutableMapOf
val map13 = mapOf("a1" to 10, "a2" to 20, "a3" to 30)
val map14 = map13.toMutableMap()
map14["a4"] = 40
println("map14 : $map14")
// mutableMapOf -> mapOf
val map15 = map14.toMap()
//map15["a5"] = 50
}
출력결과
map1 : {key1=10, key2=20, key3=30}
map2 : {10=str1, 20=str2, 30=str3}
map3 : {key1=10, key2=20, key3=30}
map4 : {key1=10, key2=20, key3=30}
map5 : {key1=10, key2=11.11}
map6 : {key1=10, key2=20, key3=30}
map7 : {key1=10, key2=11.11}
-------------------------------
map10 key1 : 10
map11 key1 : 10
map10 key1 : 10
map11 key1 : 10
-------------------------------
map1 size : 3
map1 keys : [key1, key2, key3]
map1 values : [10, 20, 30]
map1 contains ket - key1 : false
map1 contains ket - key100 : false
map1 contains value - 10 : true
map1 contains value - 100 : false
-------------------------------
map12 : {a1=10, a2=20}
map12 : {a1=10, a2=20, a3=30}
map12 : {a1=10, a2=20, a3=30, a4=40}
map12 : {a1=100, a2=20, a3=30, a4=40}
map12 : {a2=20, a3=30, a4=40}
-------------------------------
map14 : {a1=10, a2=20, a3=30, a4=40}
Set
fun main(){
// 수정 불가능한 set
val set1 = setOf(10, 20, 30, 10, 20, 30)
// 수정 가능한 set
val set2 = mutableSetOf(10, 20, 30, 10, 20, 30)
println("set1 : $set1")
println("set2 : $set2")
// 추가
set2.add(40)
println("set2 : $set2")
set2.add(10)
println("set2 : $set2")
// set -> list
val list1 = set2.toList()
val list2 = set2.toMutableList()
println("list1 : $list1")
println("list2 : $list2")
// list -> set
val list3 = listOf(10, 20, 30, 10, 20, 30)
val set3 = list3.toSet()
val set4 = list3.toMutableSet()
println("set3 : $set3")
println("set4 : $set4")
}
출력결과
set1 : [10, 20, 30]
set2 : [10, 20, 30]
set2 : [10, 20, 30, 40]
set2 : [10, 20, 30, 40]
list1 : [10, 20, 30, 40]
list2 : [10, 20, 30, 40]
set3 : [10, 20, 30]
set4 : [10, 20, 30]
마무리
오늘은 알고리즘을 공부하면서 혹은 독학을 하면서 자연스럽게 알게 되었던 개념등을 다시 복습하여 좋았습니다.
이제 코틀린 문법 중 남은 것은 쓰레드, 예외처리, 스트림 등이 있고 아마 그에 따른 과제를 작성하게 될텐데 지난 번 자바보다는 좀 더 어려운 문제가 나올 것으로 예상이 되어 걱정이 되지만, 복기를 하다 보면 좋은 결과가 있을 거라 생각 됩니다.
오늘의 마음가짐
모르면 공부하고, 질문하고, 이해하여 발전하는 개발자가 되자~!