TIL 20231212

2023. 12. 12. 16:52코틀린

배열

 

변수에 순서를 매겨 활용 할 수 있다.

일반적으로 변수를 선언하면 코틀린은 메모리에 간격있게 랜덤으로 생성되고 변수의 위치 정보가 연속적이지 않기때문에 순서가 없는데 배열을 사용하면 할 수 있다.

 

kotlin의 배열 사용법

배열을 통해 변수에 순서를 매겨 연속적으로 활용할 수 있다.

코틀린은 배열을 사용하기 위해 arrayOf 메소드(키워드)를 제공한다.

 

// arrayOf메소드를 호출하면 배열을 리턴해준다
// 1,2,3,4,5 각각을 저장한 변수 5개를 배열형태로 arr에 저장한다
var arr = arrayOf(1,2,3,4,5)

// 배열요소를 모두 출력한다.
println(Arrays.toString(arr))

// 배열의 첫번째 요소에 저장된 값을 출력한다.
// var num1 = 1의 num1과 arr[0]은 동일하다.
// arr[0]은 하나의 변수로 취급할 수 있다.
// arr은 0~4번방(인덱스)까지 접근할 수 있다.
println(arr[0])

 

이런식으로 배열을 사용하면 된다.

fun main() {
    var kors = arrayOf(90, 94, 96)
    for((idx, kor) in kors.withIndex()) {
        println("${idx}번째 국어 점수는 ${kor}입니다")
    }
}


컬렉션

 

개발에 유용한 자료구조를 제공한다.

코틀린에서는 리스트, 맵, 집합 자료구조를 지원한다.

1)List

리스트는 읽기 전용과 수정가능한 종류로 구분 할 수 있고 배열과 달리 크기가 정해져 있지 않아 동적으로 값을 추가할 수 있다.

 

// 읽기전용 리스트다.
// 0번, 1번, 2번 인덱스에 접근해서 값을 변경할 수 없다.
var scores1 = listOf(값1, 값2, 값3)

// 수정가능 리스트다.
// 0번, 1번, 2번 인덱스에 접근해서 값을 변경할 수 있다.
var scores2 = mutableListOf(값1, 값2, 값3)
scores2.set(인덱스, 값)

// 수정가능 리스트다.
// 0번, 1번, 2번 인덱스에 접근해서 값을 변경할 수 있다.
// array로 데이터들을 저장하는 ArrayList도 mutableListOf와 동일하게 사용할 수 있다.
// 저장할 데이터의 자료형을 < > 안에 지정해야 사용할 수 있다.
var scores3 = ArrayList<자료형>(값1, 값2, 값3)
scores3.set(인덱스, 값)

 

 

2)Map

맵은 키와 값의 쌍으로 이루어진 자료형으로, 읽기전용과 수정가능한 종류로 구분 할 수 있다.

 

// 읽기전용 맵이다/
    // 변수명[키]로 데이터에 접근할 수 있다.
    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}입니다")
    }

 

3)Set
셋은 순서가 존재하지 않고 중복없이 데이터를 관리하는 집합 자료형으로 읽기전용과 수정가능한 종류로 구분 할 수 있다.

다른 컬렉션들은 요소를 찾는 데에 집중하는 데에 비해 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}는 존재하지 않습니다.")
    }

 

교집합, 차집합, 합집합으로 간편하게 요소들을 추출 할 수도 있다.

 

// 귀여운 새의 집합
    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}")

 

+제네릭(Generic) 
코드를 작성하다보면 다양한 타입에 동일한 로직을 적용할 때가 많은데, 매번 Any타입으로 받는것은 타입의 안정성을 저하시킬 수 있다. 클래스 내부에서 사용할 자료형을 인스턴스를 생성할 때 고정해야 하며 컴파일 시간에 자료형을 검색 하여 적당한 자료형을 선택할 수 있도록 해야 한다. 그러면 객체 자료형의 안정성을 높이고, 형 변환의 번거로움이 줄게 된다.

 

fun <T> test(arr: Array<T>, data: T): Int {
    for(i in arr.indices) {
        if(arr[i] == data) return i
    }
    return -1
}

fun main() {
    val obj1: Array<String> = arrayOf("c", "java", "kotlin")

    val index = test<String>(obj1, "kotlin")
    println(index)
}

 


 

 Single-expression function

 

람다식을 이용해서 메소드를 간결하게 정의할 수 있다.

 

자바8과 동일하게 코틀린도 람다식을 지원하고 이는 하나의 메소드를 간결하게 표현할 수 있는 방법이다.

 

kotlin 람다식 구조

{매개변수1, 매개변수2... -> 
코드
}

 

세 개의 숫자의 평균을 리턴해주는 함수를 람다식으로 정의한다.

fun add(num1:Int, num2:Int, num3:Int) = (num1+num2+num3)/3

 

메소드를 선언하지 않고 로직을 저장할 수 있다.

var add = {num1: Int, num2: Int, num3: Int -> (num1+num2+num3) / 3}
println("평균값은 ${add(10,20,30)}입니다")

 

 

싱글턴

메모리 전역에서 유일한 객체임을 보장할 수 있다. 보통 객체는 자원이 가능한 만큼 생성할 수 있고
각각의 객체는 상이한 위치정보를 가지고 있어서 저장하는 값도 객체마다 고유하다.


싱글턴을 활용하면 해당 객체는 메모리 전역에서 유일함을 보장하고 위치정보를 고정 할 수 있다. 프로그램이 실행되는 시점에 메모리에 바로 로드해서 위치를 잡는다.

 

Kotlin의 싱글턴 구현방법

코틀린은 companion,object 키워드로 싱글턴을 구현할 수 있다.

 

싱글턴 객체는 전역적으로 활용할 수 있어서 다른 클래스들에서 쉽게 접근할 수 있다. 전역에서 공통적으로 사용하는 정보라면 메모리를 더욱 효율적으로 활용할 수 있고 객체 자원간의 충돌을 방지할 수 있다.

 

객체를 생성하지 않고도 클래스 정보에 접근할 수 있다. (생성자 호출X)

 

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

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

 

 

객체를 생성하지 않고도 클래스 정보에 접근할 수 있다. (생성자 호출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
    }
}

'코틀린' 카테고리의 다른 글

TIL 20231214  (2) 2023.12.14
TIL 20231213  (0) 2023.12.13
TIL 20231211  (0) 2023.12.11
WIL 20231209  (0) 2023.12.09
TIL 20231208  (1) 2023.12.08