오늘은 Kotlin
의 기본 문법을 알아보겠습니다.
Kotlin
공식 사이트를 기준으로 합니다.
package와 import 사용법은 자바와 동일합니다.
package my.demo import kotlin.text.*
코틀린 어플리케이션은 main
함수를 통해 시작됩니다.
기본 함수 구현부터 인자값 설정도 가능합니다.
fun main() { println("Hello world!") }
fun main(args: Array<String>) { println(args.contentToString()) }
출력은 자바와 동일합니다.
print("Hello ") print("world!") println("Hello world!") println(42)
함수는 다양한 방법으로 구현할 수 있습니다.
처음에는 인자값과 리턴값이 명시되어 있는 기본적인 방법입니다.
fun sum(a: Int, b: Int): Int { return a + b }
다음으로 리턴값을 생략하고 간결하게 구현 할수도 있습니다.
fun sum(a: Int, b: Int) = a + b
리턴값을 주지 않아도 되며, Unit은 생략이 가능합니다.
fun printSum(a: Int, b: Int): Unit { println("sum of $a and $b is ${a + b}") } fun printSum(a: Int, b: Int) { println("sum of $a and $b is ${a + b}") }
변수는 세 가지로 선언할 수 있고, 타입은 생략해도 자동으로 지정됩니다.
참고로 타입 생략을 남발하면 가독성을 떨어뜨릴 수 있어서 선택이 필요합니다.
val a: Int = 1 val b = 2 val c: Int c = 3
클래스는 class
키워드로 간단하게 선언할 수 있습니다.
그리고 별도의 설정없이 인스턴스로 활용이 가능합니다.
class Shape class Rectangle(var height: Double, var length: Double) { var perimeter = (height + length) * 2 } fun main() { val rectangle = Rectangle(5.0, 2.0) println("The perimeter is ${rectangle.perimeter}") }
클래스에 open
키워드를 쓰면 상속이 가능합니다.
자식 클래스에서 :
을 사용하면 상속이 됩니다.
open class parentClass() { var a = "Inheritance" } class childClass(): parentClass() { var b = parentClass().a } fun main() { var c = childClass().b println(c) //Inheritance }
주석은 자바와 동일하며 중첩 주석도 가능합니다.
// 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. */
String에서 $
표현식을 통해 템플릿을 활용할 수 있습니다.
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"
조건 표현식은 일반적인 방법과 함축하는 방법이 있습니다.
fun maxOf(a: Int, b: Int): Int { if (a > b) { return a } else { return b } }
fun maxOf(a: Int, b: Int) = if (a > b) a else b
val items = listOf("apple", "banana", "kiwifruit") for (item in items) { println(item) }
val items = listOf("apple", "banana", "kiwifruit") for (index in items.indices) { println("item at $index is ${items[index]}") }
val items = listOf("apple", "banana", "kiwifruit") var index = 0 while (index < items.size) { println("item at $index is ${items[index]}") index++ }
when
은 인자값에 따라 다양한 조건으로 사용할 수 있습니다.
fun describe(obj: Any): String = when (obj) { 1 -> "One" "Hello" -> "Greeting" is Long -> "Long" !is String -> "Not a string" else -> "Unknown" }
in
연산자는 숫자가 범위 내에 있는지 확인합니다.
val x = 10 val y = 9 if (x in 1..y+1) { println("fits in range") }
!in
연산자는 범위 밖의 숫자를 확인합니다.
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") }
for
연산의 범위를 지정할 수 있습니다.
for (x in 1..5) { print(x) //12345 }
step
으로 단계를 지정할 수 있습니다.
그리고 downTo
로 내림 처리가 가능합니다.
for (x in 1..10 step 2) { print(x) //13579 } for (x in 9 downTo 0 step 3) { print(x) //9630 }
컬렉션을 반복합니다.
for (item in items) { println(item) }
컬렉션에 개체 포함 여부를 확인합니다.
val items = setOf("apple", "banana", "kiwifruit") when { "orange" in items -> println("juicy") "apple" in items -> println("apple is fine too") }
람다식
을 사용해서 컬렉션을 필터링하고 맵핑합니다.
val fruits = listOf("banana", "avocado", "apple", "kiwifruit") fruits .filter { it.startsWith("a") } .sortedBy { it } .map { it.uppercase() } .forEach { println(it) }
코틀린은 개발자를 괴롭히는 NPE 오류에서 자유롭습니다.
함수에 ?
지시하면 Nullable
값을 반환합니다.
fun parseInt(str: String): Int? { }
또한 null check
도 간편하게 할 수 있습니다.
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") } }
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)
is
연산자를 통해 타입을 체크할 수 있습니다.
또한 자동으로 타입이 변환됩니다.
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 } fun main() { printLength(getStringLength("ABC")) //3 printLength(getStringLength(1000)) //null printLength(listOf(Any())) //null }
Or
fun getStringLength(obj: Any): Int? { if (obj !is String) return null // `obj` is automatically cast to `String` in this branch return obj.length }
Or even
fun getStringLength(obj: Any): Int? { // `obj` is automatically cast to `String` on the right-hand side of `&&` if (obj is String && obj.length > 0) { return obj.length } return null }