본문 바로가기
Backend & Language/Kotlin

코틀린(Kotlin)

by hyunji00pj 2025. 2. 3.

코틀린(Kotlin)

 

JetBrain 사에서 2011년에 공개한 오픈소스 프로그래밍 언어

Java와 유사한 특징이 있지만 비교적 더 간결하고 다양한 기능이 추가됨

자바와 상호 운용이 가능함

가장 최신 버전은 1.8 버전으며, 2017년에 구글이 안드로이드 공식 언어로 코틀린을 추가함

 

특징

 

자바에 비해 비교적 간결한 문법을 제공

 

Null 안정성을 제공

 - 기본적으로 Null을 허용하지 않으며, 명시적으로 Null을 처리해야 사용할 수 있음

 

모든 함수가 리턴값을 가짐

예외처리를 강제하지 않음

자바 8에 호환

멀티 플랫폼을 지원

 

JDK 17 버전 설치

https://www.azul.com/downloads/

 

인텔리제이 설치

https://www.jetbrains.com/ko-kr/idea/download/#section=windows

 

변수의 선언

코틀린에서 변수의 선언은 val과 var를 사용한다

 

val

변수를 선언할 때 지정한 값에서 더이상 변경하지 않아야 하는 경우 사용

 

var

변수의 값을 바꿀 수 있어야 하는 경우 사용

변수를 선언하는 경우 아래와 같은 포맷으로 진행

val variableName: String = "변수 선언 방법"
  • val
    • 변수 선언 키워드
  • variableName: 
    • 변수 이름
  • String
    • 데이터 타입
  • "변수 선언 방법"

변수를 선언할 때 데이터 타입은 생략 가능하며, 값을 가지고 자료형을 자동으로 지정할 수 있습니다.

이것을 '자료형 추론' 이라고 합니다\

 

변수의 출력

 

변수는 아래와 같이 출력할 수 있습니다.

println("print value : $value")

 

데이터 타입(Data Type)

코틀린은 Reference Data Type을 사용합니다.

Reference Data Type은 객체(메모리)를 생성하고 데이터를 할당하는 방식을 의미합니다.

다만, 참조형으로 생성된 객체는 컴파일 과정에서 기본형으로 대체되어 문제 없이 사용할 수 있습니다.

데이터 타입의 최상위 클래스로는 Any가 있습니다.

숫자형 데이터 타입

숫자형 데이터 타입은 아래와 같습니다.

 

정수형 데이터 타입

Long (64 bits), Int (32), Short (16), Byte (8)

기본적으로  Int로 추론되며, 숫자 뒤에 L을 붙여주면 Long 타입으로 추론합니다.

작은 숫자 또한 Int로 추론되기 때문에 Short, Byte를 사용하기 위해서는 명시적으로 적어줘야 합니다.

 

실수형 데이터 타입

Double (64 bits), Float(32)

실수형은 기본적으로 Double 타입으로 추론됩니다.

 

숫자형 데이터 타입은 자리수를 구분하기 위해 언더바(_)를 사용할 수 있으며, 값에 영향을 주지 않습니다.

 

논리형 데이터 타입

논리형 데이터 타입은 아래와 같습니다.

논리형 데이터 타입

Boolean : true, false

문자, 문자열 데이터 타입

문자, 문자열 데이터 타입은 아래와 같습니다.

문자 데이터 타입

Char(16 bits)

한 단어만 입력할 수 있으며, 선언할 때는 무조건 문자 값을 사용해야 합니다.

 

문자열 데이터 타입

String

문자열을 저장할 때 사용하는 타입입니다.

 

 

 

산술 연산자

산술 연산자는 덧셈, 뺄셈, 곱셈, 나눗셈 등의 계산을 수행하는 연산자입니다.

+ - * / %

 

대입/복합 대입 연산자

대입 연산자는 변수에 값을 할당하기 위해 사용하는 연산자(=)입니다.

복합 대입 연산자는 대입 연산자에 산술 연산자가 결합된 형태 입니다.

ex) a+=1 은 a = a+1과 같습니다

 

=

+=

-=

*=

/=

%=

 

증감 연산자

증감 연산자는 변수의 값을 증가시키거나 감소시키기 위해 사용하는 연산자입니다.

a++ : a의 값을 1증가

a-- : a의 값을 1 감소

++a : a의 값을 1증가

--a : a의 값을 1 감소

 

비교 연산자

비교 연산자는 2개의 항을 비교하기 위해 사용합니다. 결과값은 항상 true 또는 false입니다.

 

a > b : a가 b보다 큰지 비교

a >= b : a가 b보다 크거나 같은지 비교

a < b : a가 b보다 작은지 비교

a <= b : a가 b보다 작거나 같은지 비교

a == b : a와 b의 값이 같은지 비교

a != b : a와 b의 값이 다른지 비교

a === b : a의 참조 주소와 b의 참조 주소가 같은지 비교

a !== b : a의 참조 주소와 b의 참조 주소가 다른지 비교

논리 연산자

논리 연산자는 주어진 논리식(true 또는 false로 결과가 도출되는 식)에 대한 연산을 수행합니다.

논리 연산자는 논리곱(&&), 논리합(||),부정(!) 연산자가 있습니다.

 

expr1 && expr2 : expr1과 expr2가 모두 true일 경우 true
expr1 || expr2 : expr1과 expr2 중 하나라도 true일 경우 true
!expr1 : expr1이 true일 경우 false

 

when 문

조건에 범위를 설정해야 할 경우 in 연산자를 사용할 수 있습니다.

when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}

for 문

특정 코드 범위를 반복해서 수행해야 할 경우 for문을 사용합니다.
간단하게 사용한다면 아래와 같은 문법을 사용할 수 있습니다.

for (item in collection) print(item)

여러 코드 줄을 반복해야 한다면 {}를 사용하여 지정할 수 있습니다.
그리고 범위를 지정하는 다양한 응용 방법이 존재합니다.

for (item: Int in ints) {
    // ...
}

while 문

while문은 for문과 동일하게 코드를 반복하기 위해 사용됩니다.
반복하는 방식에 따라 편한 키워드가 있으며, 이를 고려하여 선택하여 사용하면 됩니다.
반복문을 수행 후 코드를 실행할지, 코드를 실행하고 반복문을 수행할지에 따라 do-while을 선택할 수 있습니다.

while (x > 0) {
    x--
}

do {
    val y = retrieveData()
} while (y != null) // y is visible here!

 

함수 (Function)

함수는 input 값을 받아 일련의 기능을 수행하는 코드 구성을 의미합니다.
함수는 결과물을 돌려주거나 돌려주지 않을 수 있습니다.

[Input]  --->  [Function]  --->  [Output]
                  ↓
              do something

함수의 선언

함수의 선언은 아래와 같은 형식으로 작성할 수 있습니다.

fun 함수명(인자: 타입, 인자: 타입) : return 타입 {
    return 리턴값
}

example

fun sum1(a: Int, b: Int): Int {
    return a + b
}

// return을 생략한 표현식 가능
fun sum2(a: Int, b: Int) = a + b

만약 리턴할 값이 없다면 return 타입을 Unit으로 정의할 수 있으며 생략 가능합니다.

fun noReturnFunction(a: String) {
    println("called!")
}

전달 받는 파라미터는 기본 값을 사용할 수 있습니다.

fun defaultParameter(a: String = "default value") {
    println(a)
}

넘겨야 하는 값이 많을 경우 매개변수의 이름을 직접 명시하여 가독성을 높일 수 있습니다.

fun main() {
    namedArgument(a = "around", c = "studio", b = "hub")
}

fun namedArgument(a: String, b: String, c: String) {
    println("$a $b $c")
}

클래스

코틀린의 클래스는 아래와 같은 키워드를 사용하여 선언됨

class Person { /* ... */ }



클래스의 선언은 클래스 이름을 포함하여 매개변수, 생성자, 그리고 중괄호로 묶인 본문으로 구성됨.

class Person {
    var name: String = "Jedi"
    var age: Int = 15
    var country: String = "South Korea"
    var height: Int = 150
    var weight: Int = 30

    fun sayHello() {
        println("Hi!")
    }

    fun introduce() {
        println("I'm $name and my age is $age.")
    }
}

생성자

코틀린의 생성자는 아래와 같은 형식으로 구성할 수 있음.

class PersonWithConstructor constructor(private val name: String, private val age: Int) { // 주 생성자

    constructor(name: String) : this(name, 15) // 부 생성자

    constructor(name: String, age: Int, etc: String) : this(name, age) { // 추가 생성자
        println("additional constructor is called: $etc")
    }

    fun sayHello() {
        println("Hi!")
    }

    fun introduce() {
        println("I'm $name and my age is $age.")
    }
}

코틀린의 상속

코틀린에서는 모든 클래스가 Any를 상속받고 있는 구조입니다.
Any에는 equals(), hashCode(), toString()이 구현되어 있습니다.

public open class Any {
    public open operator fun equals(other: Any?): Boolean
    public open fun hashCode(): Int
    public open fun toString(): String
}

부모 클래스는 open 키워드를 사용하여 상속을 허용할 수 있습니다.

open class Car(val name: String, val price: Double, val brand: String) {
    fun introduce() {
        println("this car is $name. this is made by $brand.")
    }

    fun howMuch() {
        println("this car is $price dollars")
    }
}

 

메서드 또한 오버라이드할 수 있게 open 키워드를 사용할 수 있습니다.

open class Car(val name: String, val price: Double, val brand: String) {
    open fun myPurchaseDate() {
        println("you don't buy yet")
    }
}

상속을 받는 자식 클래스는 아래와 같은 형식으로 상속을 받습니다.

class MyCar(name: String, price: Double, brand: String, val purchaseDate: LocalDate) 
    : Car(name, price, brand) {
}

메서드 오버라이드는 아래와 같이 구현합니다.

class MyCar(name: String, price: Double, brand: String, val purchaseDate: LocalDate) 
    : Car(name, price, brand) {

    override fun myPurchaseDate() {
        println("you made a purchase on $purchaseDate")
    }
}

데이터 클래스

 

일반적으로 레이어 간 데이터를 전달하기 위해 DTO라는 객체를 생성하여 사용.
코틀린에서는 이러한 역할을 수행할 수 있는 '데이터 클래스'를 제공.

데이터 클래스를 사용하면 아래와 같은 메서드를 자동으로 생성해줌:
- equals
- getter/setter
- hashCode
- toString
- copy
- componentN

코틀린에서 데이터 클래스는 아래와 같은 형식으로 정의할 수 있음.

data class DataClassSample(val name: String, val age: Int)

클래스 앞에 'data' 키워드를 붙여 정의.

 

 

열거형(Enumeration) 클래스

우리는 Enum 클래스를 사용하여 일정 범주 안에 들어갈 수 있는 상수들을 묶어 관리할 수 있음.

Enum 클래스를 사용하는 이유:
- 코드가 단순해지고, 가독성이 좋아짐.
- 인스턴스의 생성과 상속 등을 방지하고 타입 안정성을 보장함.

Enum 클래스 구현

enum class Color(val label: String, val code: String) {
    RED("red", "#FE2E2E"),
    YELLOW("yellow", "#F7FE2E"),
    GREEN("green", "#40FF00"),
    BLUE("blue", "#0000FF");
}

Enum 클래스 활용

val red = Color.RED
println(red)         // 출력: RED
println(red.label)   // 출력: red
println(red.code)    // 출력: #FE2E2E

그 외에도 각 타입마다 함수를 구현하여 기능을 동작하게 할 수 있음.