Android 앱개발 공부/TIL(Today I Learned)

[Android] TIL 15일차

bunny code 2024. 6. 11. 16:46

컬렉션


 

* 컬렉션 : 리스트, , 집합 자료구조 세 가지 종류가 있음

 

* List

  • 리스트는 읽기 전용과 수정 가능한 종류로 구분 
  • 배열과 달리 크기가 정해져있지 않아 동적으로 값 추가 가능
  • 읽기 전용은 listOf 키워드를 활용
  • 수정 가능한 종류는 mutablelistOf(값1, 값2, 값3)ArrayList<자료형>(값1, 값2, 값3) 키워드를 활용

 수정 가능한 종류 중 배 형태로 차곡차곡 저장하는 ArrayList 키워드 활용을 많이함

 

* List 구조

var scores1 = listOf(값1, 값2, 값3)

var scores2 = mutableListOf(값1, 값2, 값3)
scores2.set(인덱스, 값)

// 저장할 데이터의 자료형을 < > 안에 지정해야 사용할 수 있어요
var scores3 = ArrayList<자료형>(값1, 값2, 값3)
scores3.set(인덱스, 값)

 

 

* 맵(map)

  • 맵은 키와 값의 쌍으로 이루어진 자료형
  • 읽기전용과 수정 가능한 종류로 구분
  • 읽기 전용은 mapOf 키워드를 활용, 수정 가능한 종류는 mutableMapOf를 활용

 

* 맵 예제

    // 변수명[키]로 데이터에 접근할 수 있습니다
    var scoreInfo1 = mapOf("kor" to 94, "math" to 90, "eng" to 92)
    println(scoreInfo1["kor"])

    
    // 변수명[키]로 데이터에 접근할 수 있습니다
    var scoreInfo2 = mutableMapOf("kor" to 94, "math" to 90)
    scoreInfo2["eng"] = 92
    println(scoreInfo2["eng"])

    // 맵의 키와 값을 동시에 추출해서 사용할 수 있습니다
    for((k,v) in scoreInfo2) {
        println("${k}의 값은 ${v}입니다")
    }

 

* 출력결과

94
92
kor의 값은 94입니다
math의 값은 90입니다
eng의 값은 92입니다

 

-> for 문과 k : 키(key), v : 값(value) 키워드를 통해 맵에 있는 데이터를 한꺼번에 출력 가능함

 

 

* 셋(set)

  • 셋(Set)은 순서가 존재하지 않고 중복없이 데이터를 관리하는 집합 자료형
  • 읽기전용과 수정 가능한 종류로 구분
  • 읽기 전용은 setOf, 수정 가능한 종류는 mutableSetOf + add, remove 키워드 활용
  • 리스트랑 맵은 요소를 찾는데에 집중하지만, Set은 요소가 존재하는지에 집중

 

* set 예제

    var birdSet = setOf("닭", "참새", "비둘기")

//  수정가능 Set입니다.
//  var mutableBirdSet = mutableSetOf("닭", "참새", "비둘기")
//  mutableBirdSet.add("꿩")
//  mutableBirdSet.remove("꿩")
    println("집합의 크기는 ${birdSet.size} 입니다")

    var findBird = readLine()!!

    if(birdSet.contains(findBird)) {
        println("${findBird} 종류는 존재합니다.")
    } else {
        println("${findBird}는 존재하지 않습니다.")
    }

 

* 출력 결과

집합의 크기는 3 입니다
참새  //참새 readLine() 입력
참새 종류는 존재합니다.

 

* set 고급 활용 예제

package com.example.myapplication

fun main(){
    // 귀여운 새의 집합
    var birdSet = setOf("닭", "참새", "비둘기", "물오리")

    // 날수있는 새의 집합
    var flyBirdSet = setOf("참새", "비둘기", "까치")

    // 모든 새의 집합 (합집합)
    var unionBirdSet = birdSet.union(flyBirdSet)

    // 귀엽고 날수있는 새의 집합 (교집합)
    var intersectBirdSet = birdSet.intersect(flyBirdSet)

    // 귀여운 새들중에서 날수없는 새의 조합 (차집합)
    var subtractBirdSet = birdSet.subtract(flyBirdSet)

    println("=====합집합=====")
    println("모든 새의 집합 : ${unionBirdSet}")

    println("=====교집합=====")
    println("귀엽고 날수있는 새의 집합 : ${intersectBirdSet}")

    println("=====차집합=====")
    println("귀엽고 날수없는 새의 집합 : ${subtractBirdSet}")
}

 

* 출력 결과

=====합집합=====
모든 새의 집합 : [닭, 참새, 비둘기, 물오리, 까치]
=====교집합=====
귀엽고 날수있는 새의 집합 : [참새, 비둘기]
=====차집합=====
귀엽고 날수없는 새의 집합 : [닭, 물오리]

-> union : 합집합, intersect : 교집합, subtract : 차집합

 

 

* 컬렉션 고급 활용 예제

package com.example.myapplication

fun main() {
    //<Student>는 제네릭을 사용하여 Student 객체만 포함한다는 걸 의미함
    //이 코드에서 <Student>는 클래스 Student의 변수 자료형을 따르는 걸 의미함
    var students = mutableListOf<Student>()
    var averages = mutableMapOf<String, Int>()

    for(idx in 0..2) {
        println("학생의 이름을 입력하세요")
        var name = readLine()!!

        println("국어 점수를 입력하세요")
        var kor = readLine()!!.toInt()

        println("수학 점수를 입력하세요")
        var math = readLine()!!.toInt()

        println("영어 점수를 입력하세요")
        var eng = readLine()!!.toInt()

        var average = (kor + math + eng) / 3
        var tempStudent = Student(name, kor, math, eng)

        students.add(tempStudent)
        averages[name] = average
    }

    for(student in students) {
        var average = averages[student.name]
        student.displayInfo()
        println("평균점수는 ${average} 입니다")
    }
}

class Student(name:String, kor:Int, math:Int, eng:Int) {
    var name:String
    var kor:Int
    var math:Int
    var eng:Int

    init {
        this.name = name
        this.kor = kor
        this.math = math
        this.eng = eng
    }

    fun displayInfo() {
        println("이름: $name")
        println("국어: $kor")
        println("수학: $math")
        println("영어: $eng")
    }
}

 

* 출력결과

학생의 이름을 입력하세요
안녕
국어 점수를 입력하세요
90
수학 점수를 입력하세요
88
영어 점수를 입력하세요
73
학생의 이름을 입력하세요
밥
국어 점수를 입력하세요
88
수학 점수를 입력하세요
97
영어 점수를 입력하세요
99
학생의 이름을 입력하세요
마지막
국어 점수를 입력하세요
100
수학 점수를 입력하세요
99
영어 점수를 입력하세요
100
이름: 안녕
국어: 90
수학: 88
영어: 73
평균점수는 83 입니다
이름: 밥
국어: 88
수학: 97
영어: 99
평균점수는 94 입니다
이름: 마지막
국어: 100
수학: 99
영어: 100
평균점수는 99 입니다

 

* 예제의 코드 흐름 요약

1. 변수 Students는 List를 이용하여 Student 객체만 받아올 수 있게 선언

2. 변수 averages는 Map을 이용하여 문자열(String)과 Int 자료형만 받을 수 있게 선언


3. 첫번째 for문을 통해 인덱스에 0부터 2까지 값 입력(총 3가지)

-> name, kor, math, eng를 readLine을 통해 사용자가 총 3번 입력

-> 이 입력받은 값이 클래스 Student에 들어감


4. 변수 average는 국어, 수학, 영어를 3으로 나눈 평균값을 받도록 선언

5. 변수 tempStudent는 클래스 Student에 name, kor, math, eng을 받도록 선언

6. students.add를 통해 tempStudent를 리스트에 추가함

7. avarges[name] = average를 통해 평균 점수를 맵에 추가함


8. 두번째 for문은 students의 요소 중 하나인 student를 불러옴

9. 여기서 변수 average는 averages[student.naem]을 받아옴으로써 아까 맵에 추가된 평균점수를 받아옴


10. 그리고 클래스 Student에 있는 메소드 displayInfo()를 불러와서 그 안에 있는 println문을 통해 이름, 국어, 수학, 영어 값을 출력


11. 마지막으로 평균점수를 보여주는 println문을 작성하여 출력

 

 

* 이해하기 어려웠던 내용들

 

Q. mutableListOf<Student>에서 <Student>의 의미는?

A. 제네릭을 사용한 것으로 Student 유형의 객체만 받겠다는 걸 의미함. Student 클래스에 있는 name(String), kor(Int), math(Int), eng(Int) 형식으로 입력해야만 리스트에 추가된다.(형식이 잘못됐을 경우 오류 발생)

 

Q. average 어떻게 두 번 쓴 걸까?

A. 코틀린에서는 같은 이름의 변수를 서로 다른 스코프(scope)에서 선언할 수 있음, 이번 코드의 경우 지역 스코프에 해당함

 

Q. student.displayInfo() 작성 가능한 이유는?

A. 맨 위에 mutableListOf<Student>를 통해 Student 유형의 객체만 받겠다고 선언했기 때문.

 

 

 

Single-expression function


코틀린에선 람다식을 활용하여 메소드를 간결하게 표현 가능

 

* 예제

//예제1 : 중괄호 없이 표현
fun add(num1:Int, num2:Int, num3:Int) = (num1+num2+num3)/3


//예제2 : 메소드 없이 변수 선언하듯이 작성
var add = {num1: Int, num2: Int, num3: Int -> (num1+num2+num3) / 3}
println("평균값은 ${add(10,20,30)}입니다")

 

 

싱글턴


companion object, object 키워드로 싱글턴을 구현

 

* object를 이용하여 객체를 생성하지 않고 클래스에 접근(생성자 x) 

fun main() {
    Bird.fly("참새")
}

object Bird {
    fun fly(name:String) {
        println("${name}가 날아요~")
    }
}

 

* companion object를 이용하여 객체를 생성하지 않고 클래스에 접근(생성자 o)

fun main() {
    // trash와 같이 생성자에 매개변수 전달 가능
    var singletonObject1 = MySingletonClass.getInstance(trash = 1)
    singletonObject1.setNum(5)
    println("num값은: ${singletonObject1.getNum()}")

    // singletonObject2에서 num을 10으로 대입
    var singletonObject2 = MySingletonClass.getInstance(trash = 1)
    singletonObject2.setNum(10)

    // singletonObject1의 num이 10으로 출력됨
    // singletonObject1과 singletonObject2는 같은 객체를 공유하기 때문
    println("num값은: ${singletonObject1.getNum()}")

}

class MySingletonClass private constructor() {
    private var num:Int = 0

    companion object {
        @Volatile private var instance: MySingletonClass? = null
        private var trash = 0

        fun getInstance(trash: Int): MySingletonClass {
            this.trash = trash
            // 외부에서 요청왔을때 instance가 null인지 검증
            if(instance == null) {
		            // synchronized로 외부 쓰레드의 접근을 막음
								// 쓰레드는 다음챕터에서 소개합니다!
		            // 쓰레드간의 객체상태 혼돈을 막기위해 사용한다고 이해해주세요
                synchronized(this) {
                    instance = MySingletonClass()
                }
            }
            return instance!!
            
//            엘비스연산자와 뒷장에서배울 scope function을 이용하면
//            아래와같이 더욱 직관적인 코드 작성이 가능합니다
//            return instance ?: synchronized(this) {
//                // also는 호출한 객체를 it으로 넘김
//                // instance가 null이라면 새로 생성하고 아니면 무시함
//                instance ?: MySigletonClass().also {
//                    instance = it
//                }
//            }
        }
    }
    fun setNum(num: Int) {
        this.num = num
    }

    fun getNum(): Int{
        return this.num
    }
}

 

 

참고 자료 및 유용한 내용


 

스코프란? 변수가 유효한 범위, 즉 변수를 사용할 수 있는 코드의 영역

 

주요 스코프 종류

  1. 전역 스코프 (Global Scope)
    • 프로그램 전체에서 접근 가능한 범위
    • 전역 변수는 프로그램의 모든 부분에서 접근 가능
  2. 지역 스코프 (Local Scope)
    • 특정 블록(예: 함수, 루프, 조건문 등) 내에서만 유효한 범위
    • 지역 변수는 해당 블록 내에서만 접근 가능
  3. 블록 스코프 (Block Scope)
    • {}로 감싸진 코드 블록 내에서 유효한 범위
    • 함수나 루프, 조건문 등에서 사용되는 블록 스코프는 해당 블록이 종료되면 소멸

 

* 제네릭의 개념

제네릭(Generic)은 클래스나 함수에서 사용할 타입을 미리 지정하지 않고, 나중에 지정할 수 있도록 하는 방법이다.

이를 통해 코드의 재사용성을 높이고 타입 안전성을 확보 가능

 

 

https://velog.io/@haero_kim/혹시-싱글톤이세요-저는-벙글톤이에요-ㅋㅋㅋ

 

혹시 싱글톤이세요? 저는 벙글톤이에요 ㅋㅋㅋ

벙글..아니 싱글톤 패턴 개념 단 번에 이해하기

velog.io

 

 

 

배우면서 느낀 점


컬렉션 함수 활용이 많아지면 많이 어려워질 것 같다는 생각이 든다.. 컬렉션 고급 활용 예제 문제 이해하는 데만 거의 1시간 가까이 걸려서 복습을 꼭 하고 가야할 것 같다.

'Android 앱개발 공부 > TIL(Today I Learned)' 카테고리의 다른 글

[Android] TIL 17일차  (2) 2024.06.13
[Android] TIL 16일차  (2) 2024.06.12
[Android] TIL 14일차  (2) 2024.06.10
[Android] TIL 13일차  (0) 2024.06.07
[Android] TIL 12일차  (0) 2024.06.05