본문 바로가기

Kotlin

Kotlin 도큐먼트: 기본 문법 살펴보기

더보기

Kotlin 소스 파일의 기본 구성은 Java 소스 파일과 크게 다르지 않습니다.

애플리케이션 시작을 위한 main() 메소드에서는 프로그램 Argument를 받을 수 있으며 소스 파일에서는 패키지 경로를 정의하거나 다른 패키지를 import합니다.

Kotlin의 기본 애플리케이션의 시작점(entry point)main()입니다.

fun main() {
	// this is entry point function
}

애플리케이션의 실행 Argument를 구하려면 Array<String> 인자를 사용합니다.

fun main(args: Array<String>) {
	// this is entry point function
}

패키지 경로는 소스 파일의 맨 위에 작성합니다.

package my.demo

 다른 소스 파일을 사용하려면 import를 사용합니다.

package my.demo

import my.hello.*

fun main(args: Array<String>) {
    helloWorld()
}

패키지에 대한 자세한 내용은 Packages kotlinlang.org: Packages and imports를 참고합니다.

표준 출력(Standard output)을 위한 Print

print는 표준 출력에 Argument를 출력합니다.

print("Hello ")
print("World!")
더보기

Kotlin은 소스 코드행의 마지막을 알리는 세미콜론(;)을 입력하지 않습니다

println은 표준 출력에 Argument를 출력하고 개행(Line break)합니다.

println("Hello World!")

함수(Functions)

함수는 함수 이름 인자 리턴 타입 함수 블록으로 구성됩니다. 함수의 시작을 알리는 키워드는 fun입니다.

fun sum(a: Int, b: Int): Int {
    return a+b
}
코드 비고
Line 1 fun 함수의 시작을 알리는 키워드입니다.
sum 함수의 이름입니다.
(a: Int, b: Int) 함수의 인자입니다.
예시에서는 두 개의 인자 a b를 받으며 각 인자의 타입은 Int Int입니다.
: Int 함수의 리턴 타입입니다.
예시에서는 Int 타입을 리턴합니다.
Line 1:3 { } 함수의 블록중괄호({ })로 구성됩니다.
함수가 실행하는 코드를 입력합니다.

함수 블록중괄호({})로 감싸지 않고 단일 표현식으로 작성 할 수도 있습니다. 리턴 타입은 자동으로 추론됩니다.

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

의미있는 리턴 타입이 존재하지 않으면 Unit을 리턴 타입으로 지정합니다.

fun printSum(a: Int, b: Int): Unit {
    println("sum of $a and $b is ${a+b}")
}
코드 비고
Line 2 $a $b ${a+b} 문자열 표현식에서 변수를 참조하는 경우 $ 키워드를 사용합니다.
참조 변수가 연산식을 갖는 경우 ${연산식}처럼 사용합니다.
더보기

: Unit 키워드는 생략 할 수 있습니다.

변수(Variables)

Kotlin의 변수 선언 키워드는 두 가지입니다.

읽기 전용의 변수를 선언하려면 val을 사용합니다. 이 키워드는 Java의 final과 같으며 값이 한 번 할당된 이후 변경되지 않습니다.

val a: Int = 1
val b = 2
val c: Int
c = 4
코드 비고
Line 1 val a: Int = 1 Int 타입의 읽기 전용 변수를 선언하고 1로 초기화합니다.
Line 2 val b = 2 읽기 전용 변수를 선언하고 2로 초기화합니다.
데이터 타입은 Int 타입으로 추론됩니다.
Line 3:4 val c: Int c = 4 이 문법은 컴파일 오류를 발생시킵니다.
읽기 전용 변수는 선언과 동시에 초기화해야 하며 도중에 값을 변경 할 수 없습니다.

일반적인 변수 선언은 var입니다. 이 키워드로 선언된 변수는 읽고 쓸 수 있습니다.

마찬가지로 별도의 데이터 타입을 지정하지 않으면 자동으로 추론합니다.

var x = 123
x = 456

클래스(Class)

클래스 정의는 class 키워드로 시작합니다.

class Shape

클래스의 프로퍼티는 클래스 선언문 또는 본문에 포함합니다.

class Rectangle(val height: Double, val length: Double) {
    val perimeter = (height + length) * 2
}
코드 비고
Line 1 class 클래스를 정의하는 키워드입니다.
val height: Double val length: Double 두 개의 프로퍼티를 클래스 선언문에서 지정합니다.
Line 2 val permiter 프로퍼티를 클래스 본문에서 지정합니다.
프로퍼티 타입을 지정하지 않았기 때문에 추론됩니다.

별도의 생성자를 명시하지 않더라도 프로퍼티를 포함하는 클래스 선언문을 생성자 처럼 사용합니다.

val rectangle = Rectangle(5.0, 2.0)
println("The perimeter is ${rectangle.perimeter}")

다른 언어처럼 클래스는 다른 클래스를 상속 할 수 있습니다. 클래스 상속을 위한 키워드는 콜론(:)입니다.

open class Shape { }

class Rectangle(val height: Double, val length: Double): Shape() {
    val perimeter = (height + length) * 2
}
코드 비고
Line 1 open class Shape { } 클래스는 기본적으로 final로 선언됩니다.
다른 클래스에서 상속 할 수 있게하려면 클래스 선언문에서 open 키워드를 사용합니다.
Line 3 : Shape() Shape 클래스를 상속합니다.

주석(Comments)

예시와 같이 단일 주석(single-line, end-of-line)을 사용합니다.

// This is an end-of-line comment

여러 행을 주석으로 작성 할 수 있습니다.

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

주석은 중첩 될 수 있습니다.

/*
 This is a block comment
 on multiple lines
    /*
        This comment nested in other comment
    */
 */

문자열 템플릿(String template)

문자열에서 변수를 참조하려면 $ 키워드를 사용합니다. 문자열 내 참조되는 변수가 연산되는 경우 중괄호({ })를 사용합니다.

var a = 1
val s1 = "a is $a"

a = 2
val s2 = "${s1.replace("is", "was")}, but now is $a"
코드 비고
Line 2 Line 5 $a 문자열 내에서 변수 a를 참조합니다.
Line 5 ${s1.replace("is", "was")} 문자열 내에서 변수 s1을 참조하고 연산합니다.

조건문(Conditional expressions)

기본적인 조건문 사용법은 Java와 동일합니다.

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

Kotlin은 삼항 연산자를 지원합니다. 일반적인 표현식 ? : 대신 else를 사용합니다.

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

반복문

Kotlin의 반복문은 for in 키워드를 사용합니다.

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

인덱스로 반복문을 수행하려면 indices을 사용합니다.

val items = listOf("apple", "banana", "kiwifruit")
for (index in items.indices) {
	println(items[index])
}

for 대신 while을 사용 할 수 있습니다.

val items = listOf("apple", "banana", "kiwifruit")
var index = 0
while (index < items.size) {
	println(items[index])
	index++
}

when 표현식

Kotlin의 when은 Java의 switch와 유사한 구문입니다.

when에 전달된 객체를 case에 따라서 처리합니다.

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

범위 선택자

Kotlin 문법에서는 ..으로 어떤 범위의 데이터를 표현 할 수 있습니다.

val x = 10
val y = 9

if (x in 1..y+1) {
	println("fits int range")
}
코드 비고
Line 4 if (x in <range>) xrange에 속하는지 검사합니다
1 .. y+1 범위는 .. 으로 표현됩니다.
예시의 범위는 1부터 시작하여 10=y+1, y=9까지입니다.

in 표현식은 논리 연산자를 붙여 !in 처럼 사용 할 수 있습니다.

val list = listOf("a", "b", "c")

if (-1 !in 0 .. list.lastIndex) {
	println("-1 is out of rnage")
}

if (list.size !in list.indices) {
	println("list size is out of valid list indices range, too")
}
코드 비고
Line 3 Line 7 !in 값이 범위에 속하지 않는지 검사합니다
Line 3 0 .. list.lastIndex 리스트 list의 마지막 인덱스는 2입니다.
지정된 범위는 0, 1, 2입니다.
Line 7 list.indices 리스트 list의 인덱스를 범위로 표현합니다.
지정된 범위는 0, 1, 2까지입니다.

범위는 Iterating 될 수 있으며 방향과 단위를 선택 할 수 있습니다.

// 1 2 3 4 5 6 7 8 9 10
for (x in 1 .. 10) { }
    
// 1 3 5 7 9
for (x in 1 .. 10 step 2) { }
    
// 9 6 3 0 
for (x in 9 downTo 0 step 3) { }
코드 비고
Line 2 1 .. 10 지정된 범위는 1부터 10까지입니다.
Line 5 1 .. 10 step 2 지정된 범위는 1부터 10까지입니다.
step 2는 Iterating에서 2씩 건너뜁니다.
Line 8 9 downTo 0 step 3 downTo로 방향을 결정합니다.
지정된 범위는 9부터 0까지이며 Iterating에서 3씩 건너뜁니다.

Collections

Kotlin의 Collections으로 반복문 when 표현식 람다 표현식을 사용 할 수 있습니다.

val items: Collection<String> = listOf("banana", "avocado", "apple", "kiwifruit")

for (item in items) {

}

when {
	"orange" in items   -> "found orange"
	"apple" in items    -> "found apple"
}

items
	.filter { it.startsWith("a") }
	.sortedBy { it }
	.map { it.uppercase() }
	.forEach { println(it) }
코드 비고
Line 1 Collection<T> Collection은 Generic입니다.
Line 3 for Collection의 원소를 반복문으로 실행합니다.
Line 7 when Collection의 원소를 when 표현식으로 검사합니다.
Line 13 filter 람다 표현식으로 Collection을 필터링합니다.
sortedBy 람다 표현식으로 Collection을 정렬합니다.
map 람다 표현식으로 Collection의 각 원소를 매핑합니다.
forEach 람다 표현식으로 Collection을 Iterating합니다.

Nullable 변수와 Null 검사

Kotlin 문법에서의 주요한 특징은 변수를 선언 할 때 Nullable 변수를 명시 할 수 있다는 점입니다.

Nullable을 명시할 때는 변수의 타입 뒤에 ? 키워드를 사용합니다.

fun abc(str: String): Int? {
    
}
코드 비고
Line 1 : Int? 함수의 반환 타입은 Int이며 Nullable입니다.

Null 검사는 통상적인 조건문과 등호 연산자 사용합니다.

if (null == x) { }
if (null != x) { }

타입 검사와 Kotlin의 자동 캐스팅

is 연산자는 수식이 특정 타입의 객체인지 검사합니다.

불변 로컬 변수(Immutable local variables) 또는 프로퍼티의 타입을 검사할 때는 명시적으로 캐스팅 할 필요는 없습니다.

fun getStringLength(obj: Any): Int? {
    if (obj is String) {
        return obj.length
    }
    
    return null
}
코드 비고
Line 2 obj is String objString 타입인지 검사합니다.
Line 3 return obj.length 조건문이 true일 때 코드 블록 { }에서 objString 타입으로 자동 캐스팅됩니다.

정리 및 복습

  • 표준 출력을 위한 함수 print()println()이 있습니다.
  • 함수의 시작을 알리는 키워드는 fun입니다. 함수는 함수 이름 인자 리턴 타입 함수 블록으로 구성됩니다.
fun sum(a: Int, b: Int): Int {
    return a+b
}
  • 변수의 시작을 알리는 키워드는 var입니다. 또 다른 키워드 val은 Java의 final처럼 불변 변수를 선언 할 때 사용합니다.
  • 클래스 정의는 class 키워드로 시작합니다. 클래스의 프로퍼티는 클래스 선언문 또는 본문에 포함합니다.
class Rectangle(val height: Double, val length: Double) {
    val perimeter = (height + length) * 2
}
  • 주석은 단일 주석 // 주석 내용과 블록 주석 /* 주석 내용 */을 사용합니다.
  • 문자열에서 변수를 참조하려면 $ 키워드를 사용합니다. 문자열 내 참조되는 변수가 연산되는 경우 중괄호({ })를 사용합니다.
var a = 1
val s1 = "a is $a"

a = 2
val s2 = "${s1.replace("is", "was")}, but now is $a"
  • 조건문은 if else를 사용합니다. 삼항 연산자는 <조건식> <참> else <거짓>을 사용합니다.
fun inlineMaxOf(a: Int, b: Int): Int = if (a > b) a else b
  • 반복문은 for in을 사용하며 while문도 지원합니다.
  • Kotlin의 when은 Java의 switch와 유사한 구문입니다. when에 전달된 객체를 case에 따라서 처리합니다.
fun describe(obj: Any): String {
    when (obj) {
        1           -> return "One"
        "Hello"     -> return "Greeting"
        is Long     -> return "Long"
        !is String  -> return "Not a string"
        else        -> return "Unknown"
    }
}
  • 범위 선택자 ..는 어떤 범위의 데이터를 표현합니다. 예를 들어 1 .. 5는 1부터 5까지의 범위를 의미합니다.
  • Collections으로 반복문 when 표현식 람다 표현식을 사용 할 수 있습니다.
  • Nullable 변수를 명시하려면 변수의 타입 뒤에 ? 키워드를 사용합니다.
fun abc(str: String): Int? {
    
}
  • 타입을 검사할 때는 is 키워드를 사용합니다. 불변 로컬 변수(Immutable local variables) 또는 프로퍼티의 타입을 검사할 때는 명시적으로 캐스팅 할 필요는 없습니다.
  • is 키워드로 검사된 조건문의 true 블록에서는 변수의 타입이 자동으로 캐스팅됩니다.