본문 바로가기
혼공노트

코틀린에 대한 작은 정리 (1)

by 김비거 2024. 4. 3.

안드로이드 앱을 제작과정에 있는데

코틀린 언어에 대해 따로 작게라도 재정리를 해야 할 것 같아서 이 글을 씁니다.

자세히는 말고 개념만 잡자는 느낌으로 썼습니다.

 

* 이 글은 인프런 강의 <[입문편] 안드로이드를 위한 코틀린(Kotlin) 문법>을 보고 정리한 글입니다.

 


엘비스 연산자 (Elvis Operator)

 

fun main() {
    println(findStringLength(null)) // 인자로 null 값    
}

fun findStringLength(str : String?) : Int? { // 인자 값이 null일 수 있고, 반환 값이 null일 수 있음   
    return str?.length // 인자 값 str이 null일 수 있음
}

// 결과값은 null

 

'?' =  null 일 수도 있다.

 

fun main() {
    println(findStringLength(null)) // null 값의 길이는?
}

fun findStringLength(str : String?) : Int {
    return str?.length ?: 0 // str이 null일 수 있는데, null이면 0으로 반환
}

 

'?:' =  null 일 경우 값을 이렇게 하자.

 

 

Any /  is / as

 

fun main() {
    var str : Any = "abc" // Any = 어떤 자료형이든 포함
    println(str) // 문자열(String) 출력
    str = 123 
    println(str) // 숫자(Int) 출력
}

 

Any = 어떤 자료형이든 포함.

 

fun main() {    
    var str1 : Any = 123 
    if(str1 is String) { 
        println("this is string") // 자료형이 String이면 출력
    } else {
        println("this is not string") // 그렇지 않으면 출력
    }
    
    
    var str2 : Any = 123L // Long형 타입
    
    when(str2) {
        is Int -> {println("this is int")}
        is String -> {println("this is string")}
        else -> {
            println("this is else") // Int, String이 아니므로 출력
        }
    }

 

is = 이 자료형입니까?

 

fun main() {
    var str1 : String? = 1 as? String // String으로 변환 안되므로 null
    println(str1) // null 출력
    
    var str2 : String? = 1 as? String ?: "none" // null로 된다면 "none"으로
    println(str2) // "none" 출력
}

 

as = 자료형 변환

as? = 자료형이 변환 안 되면 null로

 

 

List 가공

 

fun main() {    
    val testList = mutableListOf<Int>()
    testList.add(1)
    testList.add(2)
    testList.add(3)
    testList.add(4)
    testList.add(10)
    testList.add(10)
    testList.add(11)
    testList.add(11) // [1, 2, 3, 4, 10, 10, 11, 11]
    
    println(testList.distinct()) // 중복제거 -> [1, 2, 3, 4, 10, 11]
    println(testList.maxOrNull()) // 제일 큰 값 -> 11
    println(testList.minOrNull()) // 제일 작은 값 -> 1
    println(testList.average()) // 평균값 -> 6.5
}

 

.distinct() = 중복제거

.maxOrNull() = 제일 큰 값

.minOrNull() = 제일 작은 값

.average() = 평균값

 

fun main() {    
    val testList2 = listOf("john", "jay", "minsu", "minji", "viger")
    val result1 = testList2.filter {
        it.startsWith("m") // "m"으로 시작하는 값 필터
    }
    println(result1) // [minsu, minji]
    
    
    val testList3 = listOf(1, 2, 3, 4, 5, 6)
    
    val result2 = testList3.filter {
        it % 2 == 0 // 2의 배수 필터
    }
    
    println(result2) // [2, 4, 6]
    
    
    val testList4 = listOf("a", "aa", "aaa", "aaaa")
    val result3 = testList4.groupBy {
        it.length > 2 // 글자수가 2보다 큰 값은 true, 아니면 false 그룹
    }
    println(result3) // {false = [a, aa], true = [aaa, aaaa]}
    println(result3[true]) // [aaa. aaaa]
}

 

.filter = 리스트 필터링 하겠음.

it = 리스트 안에 있는 값들

.startswith("m") = "m"으로 시작하는 값 

.groupBy = 리스트 그룹핑 하겠음. (map 형식)

 

 

Class

 

fun main() {       
    InitialValue("kim_viger") // kim_viger와 기본값20 출력
    InitialValue("viger", 30) // viger와 30 출력
}

class InitialValue(name: String, age : Int = 20) {
    init {					// 생성되면 자동으로 실행
        println(name)
        println(age)
    }
}

 

클래스 = 설계 + 기능

init = 생성되면 자동으로 실행됨.

 

 

오버로딩

 

fun main() {
    
    val c  = Calculator()
    c.sumNumber(1, 2) // 3
    c.sumNumber(1, 2, 3) // 6
    c.sumNumber("viger", "Happy") // vigerHappy
}

class Calculator() {
    fun sumNumber(a : Int, b : Int) {
        println(a + b)
    }
   
    fun sumNumber(a : Int, b : Int, c : Int) {
        println(a + b + c)
    }
    
    fun sumNumber(str1 : String, str2 : String) {
        println(str1 + str2)
    }
}

 

오버로딩 = 겹겹이 쌓는다.

 

 

상속

 

fun main() {
    Job() // "일을 합니다." 와 "마케팅을 합니다." 출력
}

open class AllJobs() { 			// 상속을 해주려면 open 키워드 쓰기
    init {
        println("일을 합니다.")
    }
}

class Job() : AllJobs() { 		// ALLJobs()를 상속한다고 써주기
    init {
        println("마케팅을 합니다.")
    }
}

 

open = 상속 가능한 클래스다.

상속하려면 상속할 클래스를 자료형처럼 써주기

 

 

상속과 오버라이딩

 

fun main() {
    Child().doing()				// "자식을 돌봅니다."
    Child().disease()				// "알러지가 있습니다."
}

open class Parents() {			// 상속 가능
    fun doing() {
        println("자식을 돌봅니다.")
    }
    open fun disease() { 		// 오버라이드 가능
        println("비염이 있습니다.")
    }
}

class Child() : Parents() {		// Parents 상속
    override fun disease() { 	// 오버라이드 하겠다
        // super.disease() 		// 그대로 사용
        println("알러지가 있습니다.")
    }
}

 

오버라이드 = 부모 클래스 메서드 재정의

open = 오버라이드 가능한 메서드다. (부모 클래스)

override = 부모 클래스의 메서드를 오버라이드 하겠다. (자식 클래스)

super = 그냥 부모 클래스대로 쓸게요.

 

 

추상 클래스

 

fun main() {
    BMW().wheel()		// "BMW 굴러갑니다."
    BMW().engine()		// "BMW 시동걸립니다."
}

abstract class Car {		// 추상 클래스 선언
    abstract fun wheel()	// 추상 메서드 선언
    abstract fun engine()
}

class BMW() : Car() {		// 추상 클래스 Car 상속
    override fun wheel() {		// 추상 메서드 wheel() 오버라이드
        println("BMW 굴러갑니다.")
    }
    override fun engine() {		// 추상 메서드 engine() 오버라이드
        println("BMW 시동걸립니다.")
    }
}

 

abstract = 기존엔 비어있음. 상속/오버라이딩 때 꼭 채워야.

공통적인 기능을 구현하고 싶을 때 쓴다.

 

 

인터페이스

 

fun main() {
   BMW().autoDriving()	// "BMW 자율주행"
   BMW().autoParking()	// "BMW 자동주차"
}

abstract class Car {
    abstract fun wheel()
    abstract fun engine()
}

interface CarAutoDriving {
    fun autoDriving()
}

interface CarAutoParking {
    fun autoParking()
}

// 추상 클래스, 인터페이스 상속
class BMW() : Car(), CarAutoDriving, CarAutoParking { 	
    override fun wheel() {
        println("BMW 굴러감")
    }
    override fun engine() {
        println("BMW 엔진시동")
    }
    
    // CarAutoDriving 인터페이스 메서드 채워넣기
    override fun autoDriving() {
        println("BMW 자율주행")
    }
    
    // CarAutoParking 인터페이스 메서드 채워넣기
    override fun autoParking() {
        println("BMW 자동주차")
    }
}

 

인터페이스 = 기존에 비어있음. 상속 / 오버라이딩 되면 꼭 채워야.

추상 클래스보다 작은 단위 느낌.

 

 

데이터 클래스 (Data Class)

 

fun main() {
    val justDog = JustDog("파트라슈", 12)
    println(justDog.name)
    println(justDog.age)
    println(justDog.toString()) // JustDog@34c45dca 출력
    
    val dataDog = DataDog("콜리", 15)
    println(dataDog.name)
    println(dataDog.age)
    println(dataDog.toString()) // DataDog(name=콜리, age=15) 출력
    
    val dataDog2 = dataDog.copy(name = "쉽독") // dataDog 복사. 이름만 변경
    println(dataDog2.toString()) // DataDog(name=쉽독, age=15) 출력
}

class JustDog(var name: String, var age : Int)
data class DataDog(var name: String, var age : Int) // 데이터 클래스

 

데이터 클래스 = 데이터 받은 것을 서버에 넣어 놓을 때 사용

 

 

중첩 클래스 (Nested class), 내부 클래스 (Inner class)

 

fun main() {
    val test1 = Test1.TestNestedClass()
    test1.testFun1()
    
    val test2 = Test2().Test2InnerClass()
    test2.testFun2()
}

class Test1 {
    val tempText1 = "tempText1"
    
    class TestNestedClass {
        fun testFun1() {
            println("TestFun1")
            println(tempText1) // 에러
        }
    }
}

class Test2 {
    
    val tempText2 = "tempText2"
    
    inner class Test2InnerClass {
        fun testFun2() {
            println("TestFun2")
            println(tempText2) // 출력됨
        }
    }
}

 

중첩 클래스 = 클래스 안에 클래스 중첩. (클래스 바깥 변수 사용 X)

내부 클래스 = 클래스 안에 속 클래스. (클래스 바깥 변수 사용 O)

중첩 클래스 -> 객체지향 / 캡슐화

내부 클래스 -> RecyclerView

 

 

 

 

댓글