[Kotlin] 코틀린 이해하기

gyeol·2025년 4월 23일
post-thumbnail

코틀린

JetBrains에서 오픈소스 그룹을 만들어 개발한 프로그래밍 언어이다.
JVM에 기반을 둔 언어로 코틀린 컴파일러가 .kt 파일을 컴파일하면 자바 바이트 코드를 생성해준다.

장점

  • 최신 언어 기법 이용시 훨씬 간결한 구문으로 프로그램 작성 가능
  • 널 안전성 보장
  • 자바와의 호환성
  • 코루틴 기법을 이용해 비동기 프로그램 간소화 가능

변수 선언

  • val : value의 줄임말로 초깃값이 할당되면 바꿀 수 없는 변수
  • var : variable의 줄임말로 초깃값이 할당되면 할당된 후에도 값을 바꿀 수 있는 변수

최상위에 선언한 변수나 클래스의 멤버 변수는 선언과 동시에 초깃값을 할당해야하지만 함수 내부에 선언한 변수는 선언과 동시에 초깃값을 할당하지 않아도 된다.

val data1 : Int  //error
val data2 = 10

    fun ma(){
        val data3: Int
    }

by lazy

by lazy { } 형식을 선언해 소스에서 변수가 최초로 이용되는 순간 중괄호로 묶은 부분이 자동 실행되어 그 결괏값이 변수 초깃값으로 할당된다.
해당 함수의 마지막 줄의 실행 결과가 변수의 초깃값이 된다.

val data4: Int by lazy{
       println("in lazy...")
       10
}

데이터타입

  • 문자열 템플릿 : String 타입의 데이터 변숫값이나 연산식의 결괏값을 포함해야 할 때 $ 기호 사용
  • Any : 모든 타입 가능
  • Unit : 반환 타입 없는 함수
  • Nothing : null이나 예외를 반환하는 함수로 타입 뒤에 ?를 붙이면 널 허용, 붙이지 않으면 널 불허용으로 선언

함수

함수 선언 시 fun이라는 키워드를 사용하면 반환 타입을 선언할 수 있으며 기본적으로 Unit 타입이 적용된다. 함수의 매개변수에는 val 키워드가 자동으로 적용되며 함수 내에서 매개변수 값을 변경할 수 없다.

컬렉션 타입

  • Array
val data1: Array<Int> = Array(3, {0})
val data1: IntArray = IntArray(3, {0})
val data1 = intArrayOf(1, 2, 3)
val data1 = arrayOf<Int>(1, 2, 3)

다음과 같은 형식으로 선언이 가능하다.

  • List, Map, Set
    기본적으로 불변의 특징을 가지며 가변적인 특성을 지니려면 각 타입 앞에 mutable을 적어주면 된다
val list = listOf<Int>(1, 2, 3)
val set = setOf<Int>(1, 2, 3)
val map = mapOf<String, String>(Pair("one", "world"), "one" to "hello")

map의 경우 위의 코드와 같이 선언할 수 있다.

반복문

  • for(i in 1 .. 10) : 1부터 10까지 1씩 증가
  • for(i in 1 until 10) : 1부터 9까지 1씩 증가
  • for(i in 1 .. 10 step 2) : 1부터 10까지 2씩 증가
  • for(i in 10 downTo 1) : 10부터 1씩 1 감소
  • 인덱스를 불러오기 위해 indices 사용
  • 인덱스와 실제 데이터까지 불러오기 위해 withIndex( ) 함수 사용
    fun main(){
        var data = arrayOf<Int>(1, 2, 3)
        for(i in data.indices){
            print(data[i])
        }

        for((index, value) in data.withIndex()){
            print(value)
        }
    }

클래스 선언

class main (name: String, count: Int){
    init{
        println("init")
    }
    fun some(){
        println("name: $name, count: $count") //error
    }
}

위의 같은 코드는 에러가 난다. 주생성자의 매개변수는 일반 함수에서 접근할 수 없다. 이때 주 생성자 매개변수를 var, val로 선언해주면 일반 함수에서도 접근 가능해진다.

class main (name: String, count: Int){
    constructor(name: String, count: Int, address: String): this(name, count){
        println("hello")
    }
    constructor(name: String, count: Int, address: String, age: Int): this(name, count, address){
        println("hello2")
    }
 }

이런식으로 보조 생성자에서 this()를 사용해 주 생성자 및 다른 보조 생성자를 호출할 수 있다.

상속

어떤 클래스를 상속받으려면 선언부에 콜론과 함께 상속받을 클래스 이름을 입력해준다. 다른 클래스에서 상속할 수 있게 선언하려면 부모 클래스에서 open 키워드를 사용하면 된다. 이때 자식 클래스에서 재선언한다면 override 키워드를 사용해주면 된다.

open class Super{
    open var some = 10
    open fun some() {
        println("parent")
    }
}

class Sub: Super(){
    override var some = 20
    override fun some(){
        println("child $some")
    }
}

데이터클래스

데이터 클래스는 VO 클래스를 편리하게 이용할 수 있는 방법을 제공하며 data 키워드를 이용해 선언한다.

data class Dataclass(val name: String, val email: String, val: Int)
  • equals() : true, false의 결과 반환한다. 이때 비교는 주생성자에 선언된 매개변수만을 비교한다.
  • toString() : 데이터 클래스를 사용하면서 객체가 가지는 값을 확인해야할 때 주로 사용한다.

오브젝트 클래스

선언과 동시에 객체를 생성한다.

open class Super{
	open var data = 10
    open fun some() {
    	println("i am super")
    }
}
val obj = object: Super(){
	override var data = 20
    override fun some(){
    	println("iam object")
    }
}

fun main(){
	obj.data = 30
    obj.some()
}

컴패니언 클래스

멤버 변수나 함수를 클래스 이름 단위로 접근하고자 할 때 사용한다.

class MyClass{
	companion object{
    	var data = 10
    }
}

fun main(){
	MyClass.data = 20
}

람다 함수

익명 함수 정의 기법으로 함수이지만 fun 키워드를 사용하지 않는다. 따로 return 문을 사용하지 않으며 함수의 반환값은 함수 본무늬 마지막 표현식이다.
이때 매개변수가 1개이면 매개변수를 선언하지 않아도 it 키워드로 매개변수를 이용할 수 있으며, 해당 매개변수의 타입을 식별할 수 있을 때만 사용 가능하다.

val some: (Int) -> Unit = {println(it)}

val some = {no1: Int, no2: Int ->
		println("lambda")
        no1+no2  //some의 값이 됨
}

이때 typealias를 사용해서 타입을 지정해줄 수 있다.

typealias MyFunType = (Int, Int) -> Boolean

fun main(){
	var data1: MyFunType = {no1: Int, no2: Int ->
    		println("myfuntype")
            true
    }

널 안전성

객체가 null인 상황에서 널 포인터 예외가 발생하지 않도록 연산자를 비롯해 여러 기법을 제공한다. 이때 널 포인트 예외가 발생하지 않도록 하기 위해 널 안전성 연산자를 사용한다.

  • ? : 변수 타입을 널 허용과 널 불허용으로 구분하고자 할 때 사용
  • ?.: 널 허용을 한 변수는 다음과 같은 연산자로 접근해야 함
  • ?: : 널 일때 대입해야 하는 값이나 실행해야 하는 구문이 있는 경우
  • !! : 객체가 null일 때 예외를 발생시키는 연산자
profile
공부 기록 공간 '◡'

0개의 댓글