본문 바로가기
프로그래밍언어/Kotlin

Kotlin 기본 문법

by 가판이 2025. 2. 4.

코틀린 이미지

 

코틀린 기본 문법에 대해 정리한 글입니다. 코틀린의 기본 문법들의 개요 정도로 정리되어 있으며 자세한 내용은 별도로 더 알아봐야합니다.

패키지 정의와 불러오기

package my.demo

import kotlin.text.*

// ...

 

소스 파일은 패키지 디렉토리와 일치할 필요는 없습니다. 프로젝트 내부에 임의에 곳에 있으면 됩니다.

프로그램 시작점

fun main() {
    println("Hello world!")
}

어플리케이션의 시작점은 main 함수 입니다.

어플리케이션 시작 시 인자를 전달하고 싶다면 다음과 같이 작성할 수 있습니다:

fun main(args: Array<String>) {
    println(args.contentToString())
}

표준 출력으로 인쇄하기

`print` 는 표준 출력으로 인자값을 인쇄합니다:

fun main() {
    print("Hello ")
    print("world!")
}
--------------------------
Hello world!

`println` 은 인자값 뒤에 개행 문자를 더하여 인쇄합니다.

fun main() {
    println("Hello world!")
    println(42)
}

--------------------------------
Hello world!
42

표준 입력으로부터 읽기

`readIn()` 함수는 표준 입력으로부터 읽습니다. 이 함수는 사용자가 엔터를 친 모든 줄을 읽습니다.

// Prints a message to request input
println("Enter any word: ")

// Reads and stores the user input. For example: Happiness
val yourWord = readln()

// Prints a message with the input
print("You entered the word: ")
print(yourWord)
// You entered the word: Happiness

함수

두개의 Int 인자를 받고 Int 형을 응답하는 함수:

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

fun main() {
    print("sum of 3 and 5 is ")
    println(sum(3, 5))
}
----------------------------------
sum of 3 and 5 is 8

함수 내용을 표현식으로 사용할 수 있습니다. 이 때 응답 형식은 추론됩니다:

fun sum(a: Int, b: Int) = a + b

fun main() {
    println("sum of 19 and 23 is ${sum(19, 23)}")
}
----------------------------------------------------
sum of 19 and 23 is 42

이 함수는 의미없는 값을 응답합니다:

fun printSum(a: Int, b: Int): Unit {
    println("sum of $a and $b is ${a + b}")
}

fun main() {
    printSum(-1, 8)
}
--------------------------------------------
sum of -1 and 8 is 7

Unit 응답 형식은 생략될 수 있습니다:

fun printSum(a: Int, b: Int) {
    println("sum of $a and $b is ${a + b}")
}

fun main() {
    printSum(-1, 8)
}
---------------------------------------------
sum of -1 and 8 is 7

변수

코틀린에서 변수 이름 앞에 `val` 또는 `var` 을 선언합니다.

 

`val` 은 선언하면 값에 단 한번만 값을 할당할 수 있고, 더 이상 변조되지 않습니다. 초기화 후에 다른 값으로 재할당할 수 없는 읽기 전용 지역 변수입니다:

fun main() {
    // Declares the variable x and initializes it with the value of 5
    val x: Int = 5
    // 5
    println(x)
}
-----------------------------------------
5

 

`var` 은 재할당 가능한 변수를 선언합니다. 변조가 가능하고 초기화 후에 다른 값으로 변경할 수 있어요:

fun main() {
    // Declares the variable x and initializes it with the value of 5
    var x: Int = 5
    // Reassigns a new value of 6 to the variable x
    x += 1
    // 6
    println(x)
}
-----------------------------------
6

 

Kotlin 은 type 추론을 지원하고 선언된 변수의 자료형을 자동으로 식별합니다. 변수를 선언할 때 변수 이름 뒤에 자료형을 생략할 수 있어요:

fun main() {
    // Declares the variable x with the value of 5;`Int` type is inferred
    val x = 5
    // 5
    println(x)
}
--------------------------------
5

 

변수는 초기화한 후에만 사용이 가능합니다. 선언할 때 초기화하거나 변수만 선언하고 나중에 초기화할 수 있습니다. 후자의 경우엔 변수 이름 뒤에 자료형을 반드시 지정해야합니다:

fun main() {
    // Initializes the variable x at the moment of declaration; type is not required
    val x = 5
    // Declares the variable c without initialization; type is required
    val c: Int
    // Initializes the variable c after declaration 
    c = 3
    // 5 
    // 3
    println(x)
    println(c)
}
--------------------------------------
5
3

그리고 최상위 level (메인 함수 밖) 에서도 변수를 선언할 수 있어요:

val PI = 3.14
var x = 0

fun incrementX() {
    x += 1
}
// x = 0; PI = 3.14
// incrementX()
// x = 1; PI = 3.14

fun main() {
    println("x = $x; PI = $PI")
    incrementX()
    println("incrementX()")
    println("x = $x; PI = $PI")
}
----------------------------------
x = 0; PI = 3.14
incrementX()
x = 1; PI = 3.14

Class 와 Instance 만들기

class 정의해보죠:

class Shape

 

클래스 속성들은 클래스 선언부나 본문에 나열할 수 있어요:

class Rectangle(val height: Double, val length: Double) {
    val perimeter = (height + length) * 2
}

 

기본 생성자는 인자들과 클래스 정의에서 자동으로 만들어집니다. 별도로 작성할 필요가 없습니다.

class Rectangle(val height: Double, val length: Double) {
    val perimeter = (height + length) * 2 
}
fun main() {
    val rectangle = Rectangle(5.0, 2.0)
    println("The perimeter is ${rectangle.perimeter}")
}

----------------------------------------------------------
The perimeter is 14.0

 

클래스간에 상속은 `:` 으로 선언할 수 있습니다. 클래스는 기본적으로 `final` 입니다. 상속되는 대상은 `open` 으로 선언해줘야합니다.

open class Shape

class Rectangle(val height: Double, val length: Double): Shape() {
    val perimeter = (height + length) * 2
}

 

주석

대부분의 최인 언어들처럼 코틀린은 한줄 또는 여러줄 주석을 지원합니다

// This is an end-of-line comment

/* This is a block comment
   on multiple lines. */

 

코틀린 주석 덩어리는 중첩 될 수 있습니다

/* The comment starts here
/* contains a nested comment */
and ends here. */

 

문자열 템플릿

fun main() {
    var a = 1
    // simple name in template:
    val s1 = "a is $a" 

    a = 2
    // arbitrary expression in template:
    val s2 = "${s1.replace("is", "was")}, but now is $a"
    println(s2)
}
---------------------------------------------------------
a was 1, but now is 2

 

문자열 내에서 수식을 평가할 수 있습니다. 평가를 위해선 `${}` 중괄호를 사용해야합니다. 또 단순 문자열 치환은 중괄호가 필요없습니다.

 

조건부 표현식

fun maxOf(a: Int, b: Int): Int {
    if (a > b) {
        return a
    } else {
        return b
    }
}

fun main() {
    println("max of 0 and 42 is ${maxOf(0, 42)}")
}
--------------------------------------------------
max of 0 and 42 is 42

 

코틀린에서, `if` 는 표현식 처럼 사용할 수 있습니다

fun maxOf(a: Int, b: Int) = if (a > b) a else b

fun main() {
    println("max of 0 and 42 is ${maxOf(0, 42)}")
}
-----------------------------------------------------
max of 0 and 42 is 42

 

for 반복문

fun main() {
    val items = listOf("apple", "banana", "kiwifruit")
    for (item in items) {
        println(item)
    }
}
--------------------------------------------------------
apple
banana
kiwifruit

 

또는

fun main() {
    val items = listOf("apple", "banana", "kiwifruit")
    for (index in items.indices) {
        println("item at $index is ${items[index]}")
    }
}
----------------------------------------------------
item at 0 is apple
item at 1 is banana
item at 2 is kiwifruit

 

while 반복문

fun main() {
    val items = listOf("apple", "banana", "kiwifruit")
    var index = 0
    while (index < items.size) {
        println("item at $index is ${items[index]}")
        index++
    }
}
-----------------------------------------------------------
item at 0 is apple
item at 1 is banana
item at 2 is kiwifruit

 

when 표현식

fun describe(obj: Any): String =
    when (obj) {
        1          -> "One"
        "Hello"    -> "Greeting"
        is Long    -> "Long"
        !is String -> "Not a string"
        else       -> "Unknown"
    }

fun main() {
    println(describe(1))
    println(describe("Hello"))
    println(describe(1000L))
    println(describe(2))
    println(describe("other"))
}
--------------------------------------------
One
Greeting
Long
Not a string
Unknown

 

Ranges

range 내에 숫자들이 있다면 `if` 를 통해서 확인할 수 있습니다

fun main() {
    val x = 10
    val y = 9
    if (x in 1..y+1) {
        println("fits in range")
    }
}
----------------------------------
fits in range

 

range 를 벗어난 숫자를 확인한다면

fun main() {
    val list = listOf("a", "b", "c")

    if (-1 !in 0..list.lastIndex) {
        println("-1 is out of range")
    }
    if (list.size !in list.indices) {
        println("list size is out of valid list indices range, too")
    }
}
---------------------------------------------------------------------
-1 is out of range
list size is out of valid list indices range, too

 

range 에 속한 숫자 순차적으로 접근합니다.

fun main() {
    for (x in 1..5) {
        print(x)
    }
}
-----------------------
12345

 

또는 진행식

fun main() {
    for (x in 1..10 step 2) {
        print(x)
    }
    println()
    for (x in 9 downTo 0 step 3) {
        print(x)
    }
}
--------------------------------------
13579
9630

 

Collections

collection 반복 시키기:

fun main() {
    val items = listOf("apple", "banana", "kiwifruit")
    for (item in items) {
        println(item)
    }
}
------------------------------------------------------
apple
banana
kiwifruit

 

`in` 연산자를 사용해서 collection 에 포함된 객체 확인하는 법:

fun main() {
    val items = setOf("apple", "banana", "kiwifruit")
    when {
        "orange" in items -> println("juicy")
        "apple" in items -> println("apple is fine too")
    }
}
------------------------------------------------------------
apple is fine too

 

lambda 표현식으로 collection 을 filter 하고 map 하기

fun main() {
    val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
    fruits
        .filter { it.startsWith("a") }
        .sortedBy { it }
        .map { it.uppercase() }
        .forEach { println(it) }
}
--------------------------------------------------------------------
APPLE
AVOCADO

 

Nullable 값과 null 확인하기

`null` 값이 허용 될 때 참조할 때 반드시 명시적으로 nullable 이라고 표시해야합니다. Nullable 형식의 이름은 끝에 `?` 가 붙습니다.

 

만일 `str` 변수가 정수를 소유하고 있지 않다면 `null` 을 응답 합니다:

fun parseInt(str: String): Int? {
    // ...
}

 

함수가 nullable 값을 반환하도록 해봅시다

fun parseInt(str: String): Int? {
    return str.toIntOrNull()
}

fun printProduct(arg1: String, arg2: String) {
    val x = parseInt(arg1)
    val y = parseInt(arg2)

    // Using `x * y` yields error because they may hold nulls.
    if (x != null && y != null) {
        // x and y are automatically cast to non-nullable after null check
        println(x * y)
    }
    else {
        println("'$arg1' or '$arg2' is not a number")
    }    
}

fun main() {
    printProduct("6", "7")
    printProduct("a", "7")
    printProduct("a", "b")
}
--------------------------------------------------------------------------------
42
'a' or '7' is not a number
'a' or 'b' is not a number

 

또는

fun parseInt(str: String): Int? {
    return str.toIntOrNull()
}

fun printProduct(arg1: String, arg2: String) {
    val x = parseInt(arg1)
    val y = parseInt(arg2)
    
    // ...
    if (x == null) {
        println("Wrong number format in arg1: '$arg1'")
        return
    }
    if (y == null) {
        println("Wrong number format in arg2: '$arg2'")
        return
    }

    // x and y are automatically cast to non-nullable after null check
    println(x * y)
}

fun main() {
    printProduct("6", "7")
    printProduct("a", "7")
    printProduct("99", "b")
}
------------------------------------------------------------------------
42
Wrong number format in arg1: 'a'
Wrong number format in arg2: 'b'

 

자료형 확인과 자동 형변환

`is` 는 자료형의 인스턴스인지 확인합니다. 만일 불변의 지역 변수 또는 속성일 경우 특정 자료형인지 확인 할 수 있으며, 명시적으로 형변환을 할 필요가 없습니다.

fun getStringLength(obj: Any): Int? {
    if (obj is String) {
        // `obj` 는 이 분기내에서 자동으로 `String` 으로 변환됩니다.
        return obj.length
    }

    // `obj` 는 자료형 확인 분기에서 벗어났으므로 여전히 `Any` 형입니다.
    return null
}

fun main() {
    fun printLength(obj: Any) {
        println("Getting the length of '$obj'. Result: ${getStringLength(obj) ?: "Error: The object is not a string"} ")
    }
    printLength("Incomprehensibilities")
    printLength(1000)
    printLength(listOf(Any()))
}
-----------------------------------------------------------------------------------
Getting the length of 'Incomprehensibilities'. Result: 21 
Getting the length of '1000'. Result: Error: The object is not a string 
Getting the length of '[java.lang.Object@7e6cbb7a]'. Result: Error: The object is not a string

 

또는:

fun getStringLength(obj: Any): Int? {
    if (obj !is String) return null

    // 이 분기에서는 `obj` 가 자동으로 `String` 으로 형변환 됩니다.
    return obj.length
}

fun main() {
    fun printLength(obj: Any) {
        println("Getting the length of '$obj'. Result: ${getStringLength(obj) ?: "Error: The object is not a string"} ")
    }
    printLength("Incomprehensibilities")
    printLength(1000)
    printLength(listOf(Any()))
}
------------------------------------------------------------------
Getting the length of 'Incomprehensibilities'. Result: 21 
Getting the length of '1000'. Result: Error: The object is not a string 
Getting the length of '[java.lang.Object@7e6cbb7a]'. Result: Error: The object is not a string

 

또는:

fun getStringLength(obj: Any): Int? {
    // `obj` 는 `&&` 의 우측에서 자동으로 `String` 으로 변환됩니다.
    if (obj is String && obj.length > 0) {
        return obj.length
    }

    return null
}

fun main() {
    fun printLength(obj: Any) {
        println("Getting the length of '$obj'. Result: ${getStringLength(obj) ?: "Error: The object is not a string"} ")
    }
    printLength("Incomprehensibilities")
    printLength("")
    printLength(1000)
}
반응형

'프로그래밍언어 > Kotlin' 카테고리의 다른 글

[kotlin] 자주 사용되는 구문  (2) 2025.02.09