Android 개발에 있어 Kotlin의 장점

코드가 짧으며 가독성이 좋다

다른 사람들이 이해하기 쉽도록 코드를 작성할 때 시간이 단축됩니다.

2011년 Kotlin이 공개된 이후 언어자체와 생태계가 함께 지속적으로 개발되고있다

예를들어 안드로이드 스튜디오가 있습니다.

Android Jetpack과 다른 라이브러리들을 지원한다

coroutines, extension functions, lambdas. named parameters 등을 지원합니다

Java와 호환이 된다. 

따라서 기존 어플리케이션을 모두 Kotlin으로 바꿀 필요가 없습니다

multiplatform 개발이 가능하다.

Kotlin을 이용해서 안드로이드 뿐만아니라 IOS개발, backend, web 어플리케이션을 제작할 수 있습니다

안전한 코드

간결한 코드와 높은 가독성을 통해서 에러발생률을 낮추고, 발생한 에러에 대해서는 컴파일러가 감지합니다.

배우기 쉽다

특히 Java 개발자들은 매우 배우기 쉽습니다.

거대한 커뮤니티

코틀린은 전세계적으로 성장하고 있고, 커뮤니티에서 많은 기여를 하고 있습니다. 구글에 따르면 Top 1000앱들중 60% 이상은 Kotlin을 사용합니다.

 

기본 문법

패키지 명 선언, import

package my.demo

import kotlin.text.*

// ...

패키지 명은 소스파일의 첫줄에 와야합니다.

standard output 출력하기

print("Hello ")
print("world!")
println("Hello world!")
println(42)

print와 println으로 주어진 인자를 출력할 수 있습니다.

이때 println은 출력후 line break를 추가해 한줄을 띄웁니다.

함수

Kotlin의 기본 함수의 원형은 아래와 같습니다.

fun functionName(param1: param1Type, param2:param2Type): returnType {
	// function code
}

두개의 Int형을 인자로 받고 리턴타입으로 Int를 가지는 함수입니다.

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

함수의 코드부분은 식이 될 수 있습니다. 그리고 타입은 추론해서 적용합니다.

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

 

변수

읽기전용변수는 val이라는 키워드로 선언합니다.

val a: Int = 1  // 즉시 할당합니다
val b = 2   // `Int` 타입을 추론하여 선언합니다
val c: Int  // 초기화를 하지 않는 경우 타입을 명시해야합니다
c = 3       // c에 대해 초기화합니다

val로 선언된 변수는 단 한번만 초기화 될 수 있습니다.

반면 var로 선언된 변수는 여러번 초기화 될 수 있습니다.

var x = 5 // `Int` 타입을 추론해서 선언합니다
x += 1

변수들은 top level에서 선언될 수 있습니다.

val PI = 3.14
var x = 0

fun incrementX() { 
    x += 1 
}

 

인스턴스와 클래스 생성

클래스를 선언하기 위해서 class 키워드를 사용합니다.

class Shape

클래스의 프로퍼티는 선언하거나 클래스 body에서 등록될 수 있습니다.

class Rectangle(var height: Double, var length: Double) { // height, length 프로퍼티
    var perimeter = (height + length) * 2 // perimeter 프로퍼티
}

클래스 선언시 등록한 프로퍼티들을 이용한 생성자는 자동으로 생성됩니다.

val rectangle = Rectangle(5.0, 2.0) // constructor를 생성하지 않아도 사용이 가능
println("The perimeter is ${rectangle.perimeter}")

: 로 클래스 간 상속을 할 수 있습니다. 클래스들은 기본적으로 final이며 상속이 가능하게 하기 위해선 open이라는 키워드를 사용해서 알려줘야 합니다.

open class Shape

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

 

주석

다른 언어들처럼 single-line과 multi-line 주석을 지원합니다.

// 이건 한줄 주석입니다.

/*
이것은 여러줄
주석 입니다.
*/

/*
코틀린의 주석은
/* nested를 지원합니다 */
그래서 주석 안에 주석이 가능합니다.
*/

 

템플릿 문자열

$변수명을 이용해서 문자열에 변수를 쉽게 넣을 수 있습니다.

${표현식}을 이용해서 함수, 식의 결과를 문자열에 포함시킬 수 있습니다.

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

a = 2
val s2 = "${s1.replace("is", "was")}, but now is $a"

 

조건문

다른 언어의 조건문과 동일한 형태를 가집니다.

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

if문 또한 표현식의 일부 이므로 함수로 선언할 수 있습니다. (위의 템플릿 문자열에서도 사용이 가능합니다)

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

 

반복문

기본적으로 Java의 enhanced for loop의 형태를 가집니다.

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

list의 indices를 이용해서 인덱스를 가져올 수 있습니다.

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

whlie문은 다른 언어들과 비슷한 형태를 가집니다.

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

 

when 표현식

when은 c언어의 switch문의 발전된 형태입니다.

fun describe(obj: Any): String =
    when (obj) {
        1          -> "One"	// obj의 값이 1이라면 "One" 반환
        "Hello"    -> "Greeting"	// obj의 값이 Hello이라면 "Greeting" 반환
        is Long    -> "Long"	// obj이 Long타입이라면 "Long" 반환
        !is String -> "Not a string"	// obj이 String타입이 아니라면 "Not a string" 반환
        else       -> "Unknown"	// 위 조건에 모두 해당되지 않는다면 "Unknown" 반환
    }

 

범위 표현

in키워드를 통해서 어떠한 숫자가 범위에 포함되는지 확인할 수 있습니다.

숫자..숫자 는 앞과 뒤 숫자를 포함한 범위를 표현합니다.

(1..10 은 1,2,3,4,5,6,7,8,9,10 과 같습니다)

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

 

..표현을 이용해 for문의 반복횟수를 지정할 수 있습니다.

for (x in 1..5) {
    print(x)
}

1,2,3,4,5 총 5번 반복됩니다.

downTo 키워드를 이용해서 역순으로 범위를 지정할 수 있습니다.

step 키워드를 이용해서 일정 간격을 가지는 범위를 지정 할 수 있습니다.

for (x in 1..10 step 2) { // 1, 3, 5, 7, 9
    print(x)
}
println()
for (x in 9 downTo 0 step 3) { // 9, 6, 3, 0
    print(x)
}

 

컬렉션

 

컬렉션의 모든 아이템을 탐색합니다.

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

 

in 연산자를 이용해 컬렉션에 특정 원소가 존재하는지 확인할 수 있습니다.

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

 

람다 표현식을 이용해 필터링과 map을 할 수 있습니다.

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

 

Nullable한 변수와 Null 체크

 

null일 수 있는 값은 ?를 통해 알려줘야합니다.

인자로 주어진 string이 Int값이 아닐경우 null을 리턴하는 함수입니다.

따라서 리턴값은 null이 될 수 있으며 Int?로 표현해야합니다.

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

 

위의 parseInt를 사용하는 예시입니다.

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

    // x와 x의 값이 null 일 수 있기 때문에 사용하기 전에 null 체크를 해주어야 합니다.
    if (x != null && y != null) {
    	// null체크가 끝난 이후에는 해당 변수들의 타입은 null이 아닌 원래의 타입으로 자동으로 변경됩니다.
        println(x * y)
    }
    else {
        println("'$arg1' or '$arg2' is not a number")
    }    
}

 

타입 체크와 자동 캐스팅

 

is 연산자를 이용해서 해당 연산식이 특정 타입의 인스턴스인지 검사합니다.

immutable local variable의 경우 타입 체크 이후 자동으로 캐스팅 됩니다.

fun getStringLength(obj: Any): Int? {
    if (obj is String) {
        // `obj` is automatically cast to `String` in this branch
        return obj.length
    }

    // `obj` is still of type `Any` outside of the type-checked branch
    return null
}

 

복사했습니다!