Package definition and import
- 패키지는 .kt 파일의 가장 위에 표시 되어야함
package my.demo import kotlin.text.* // ...
Program entry point
- 코틀린 애플리케이션은
main
참수의 호출로 시작됨
Array<String>
을 args로 받을 수 있음
fun main(args: Array<String>) { println(args.contentToString()) }
표준 출력
kotlin.io.Console
의inline
함수print
와println
- 자바와 달리 그냥 쓸 수 있다
함수
fun sum(a: Int, b: Int): Int { return a + b } fun sum(a: Int, b: Int) = a + b 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}") }
문자열 에서
$a
로 바로 a의 값을 땡겨오는 것이 인상적이다.Unit
은 java 의 void
와 같은 역할을 하는 것 같다.함수의 리턴 타입 선언에서
Unit
은 생략 될 수 있다.Variables
val
키워드를 사용하면 Read-only local variables를 선언 할 수 있다.
val a: Int = 1 // 즉시 할당 val b = 2 // `Int` 타입 추론 val c: Int // 즉시 할당을 하지 않으면 타입을 제공 해야함 c = 3 // 연기된 할당
- 규칙을 따르지 않았을때 발생하는 컴파일 에러 메시지를 살펴보자
val b //This variable must either have a type annotation or be initialized val c = 3; c = 2 // Val cannot be reassigned
var
키워드를 사용하면 재할당이 가능한 변수를 선언 할 수 있다.
var x = 5 // `Int` type is inferred x += 1
- 변수 (val, var)는 top level에 선언할 수 있다.
val PI = 3.14 var x = 0 fun incrementX() { x += 1 }
클래스와 인스턴스 생성
class Shape // 클래스 정의 - `class` 키워드 //클래스의 프로퍼티는 선언부 (declaration) 혹은 body 에 나열될 수 있음 class Rectangle(var height: Double, var length: Double) { var perimeter = (height + length) * 2; }
선언부에 포함된 프로퍼티를 인자로 받는 기본 생성자는 자동으로 생성된다
val rectangle = Rectangle(5.0, 2.0) println("The perimeter is ${rectangle.perimeter}")
new
가 없이 생성이 가능한점과 .
으로 바로 클래스의 속성에 접근가능 한 점이 인상적이다.클래스간의 상속은 colon(
:
) 으로 표시한다.클래스는 기본적으로
final
이며 (상속 불가) 상속을 가능하게 하기 위해서는 open
으로 표시해주자.open class Shape // 클래스 정의 - `class` 키워드 class Rectangle(var height: Double, var length: Double) : Shape() { var perimeter = (height + length) * 2; }
상속하는 클래스를 표시할때 괄호를 사용하는 모습이 인상적이다.
String template
문자열에서 $로 변수를 땡겨오는 기능이 String template 인가보다.
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"
if 문
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
for loop
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]}") }
while loop
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" }
Ranges
- 숫자가 주어진 범위인지
in
operator 로 체크
val x = 10 val y = 9 if (x in 1..y+1) { println("fits in range") }
- 주어진 숫자가 범위를 벗어났는지 확인
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") }
- 범위를 iterate
for (x in 1..5) { print(x) } //12345
- 하면서 step을 뛰기
for (x in 1..10 step 2) { print(x) } //13579 println() for (x in 9 downTo 0 step 3) { print(x) } //9630
Collections
- iterate 하기
fun main() { val items = listOf("apple", "banana", "kiwifruit") for (item in items) { println(item) } }
- 객체 포함 여부 확인
fun main() { val items = setOf("apple", "banana", "kiwifruit") when { "orange" in items -> println("juicy") "apple" in items -> println("apple is fine too") } }
- 람다
fun main() { val fruits = listOf("banana", "avocado", "apple", "kiwifruit") fruits .filter { it.startsWith("a") } .sortedBy { it } .map { it.uppercase() } .forEach { println(it) } }
스트림 전환 없이 람다를 적용할 수 있는게 인상적이다.
Nullable values and null checks
null
이 될 수 있는 참조는 nullable 표시를 명시적으로 해줘야 한다. nullable type은 type name 의 끝에?
를 표시하면 된다.
//문자열이 정수값이 아니라면 null을 반환하는 paseInt 함수 fun parseInt(str: String): Int? { // ... }
Int?는 Int가 아님 null check를 해주어야 Int로 자동 변환이 됨
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 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 }
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 }