// data를 붙이면 toString(), equals(), hashCode(), copy() Method 생성 // 기본적으로 모든 변수는 null을 허용하지 않기 때문에, C#처럼 "Nullable" type이 존재. // C#처럼 default value를 지정할 수 있음. // val은 Scala처럼 Immutable, var는 Mutable. // Custom Accessor는 C#처럼 작성. 아래는 getter의 예시. data class Person(val name: String, val age: Int? = null, val job: String = "Salesman") { val isDeveloper: Boolean get() = job == "Developer" } // 함수 내용이 한 줄인 경우 "="를 이용하여 식(Expression) 표현이 가능하다. // it은 Scala나 Clojure의 "_"와 같은 의미. 즉, 함수 안에서 자기 자신을 가리키며 "x -> x.age"에서 x를 it으로 축약 표현. //"?:"은 Elvis Operator라고 하며, 뒤의 값은 null인 경우 0으로 처리하겠다는 의미. fun getOldest(persons: List<Person>) = persons.maxBy { it.age ?: 0} // main 함수를 작성하는데 class가 필요하지 않다. fun main(args: Array<String>) { val person1 = Person("john", 11) // Nullable로 선언했기에 age는 생략 가능 val person2 = Person("doe") // 이름을 붙인 argument // 단, Java로 작성된 Code는 사용할 수 없음. 즉, Android에서 API 호출시 사용할 수 없음. val person3 = Person(age = 22, name = "Jake") //list 생성. 모든 Collection은 ...Of로 생성 가능. val persons = listOf(person1, person2, person3) val oldest = getOldest(persons) // 문자열 Template 지원. 식(Expression)이 아닌 경우 {} 생략 가능. println("oldest : ${oldest}") println(persons.filter { it.isDeveloper }) }
oldest : Person(name=Jake, age=22)
[Person(name=Jake, age=22, job=Developer)]
https://kotlinlang.org/docs/reference/lambdas.html
아래 예제처럼 Kotlin은 함수를 first-class로 취급하므로 Functional Programming의 기본 특성을 만족한다. (함수를 인자로 받고, 함수를 반환할 수 있는 특성)
// Type만을 지정하기 위한 빈 Interface 생성. 상속은 ":" 사용. interface Event data class KeyEvent(val value: String): Event fun onKeyDown(f: (Event) -> Unit) = f(KeyEvent("keydown event")) fun main(args: Array<String>) { // onKeyDown { event -> println(event) } 와 동치. onKeyDown { println(it) } }
KeyEvent(value=Hello, World)
https://kotlinlang.org/docs/reference/control-flow.html
if, while/do while은 동일하므로 생략.
interface Event data class KeyEvent(val value: String): Event data class MouseEvent(val value: String): Event fun main(args: Array<String>) { val eventControlFlow = { event: Event -> when (event) { is KeyEvent -> println("Key event! ${event.value}") is MouseEvent -> println("Mouse event! ${event.value}") else -> println("Unknown") } } // 인자가 없는 형태로도 사용 가능. 이 경우 Matching 대상이 계속 Instance를 생성하는 경우 사용. /* val eventControlFlow = { event: Event -> when { event is KeyEvent -> println("Key event! ${event.value}") event is MouseEvent -> println("Mouse event! ${event.value}") else -> println("Unknown") } } */ eventControlFlow(KeyEvent("foo")) eventControlFlow(MouseEvent("bar")) }
Key event! foo
Mouse event! bar
foreach만 존재.
fun main(args: Array<String>) { // in은 infix가 붙은 함수로 중위표현식 가능. // in은 Collections 혹은 Range의 원소 검사. val test = "Banana" in "Apple".."Cherry" println(test) for (i in 1..10) { print("$i ") } println() for (i in 10 downTo 1) { print("$i ") } println() for (i in 10 downTo 1 step 2) { print("$i ") } println() val size = 10 for (i in 0 until size) { print("$i ") } }
true
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
10 8 6 4 2
0 1 2 3 4 5 6 7 8 9
data class Person(val name: String, val age: Int? = null) fun main(args: Array<String>) { val l = arrayListOf<Person>() l.add(Person("Jake", 11)) l.add(Person("Luke", 23)) l.add(Person("Nina", 21)) // Destructuring for((age, name) in l) { println("$name $age") } println() for((index, element) in l.withIndex()) { // Kotlin은 element에 대해서 Nested Destructuring 을 지원하지 않기 때문에 변수를 이용하여 Destructuring. val (name, age) = element println("$index $name $age") } }
11 Jake
23 Luke
21 Nina
0 Jake 11
1 Luke 23
2 Nina 21
이미 존재하는 Class에 함수 확장. Static Method 호출에 대한 Syntatic sugar. 이를 이용하더라도 private/protected가 선언된 Member를 호출할 수 없으므로 캡슐화가 깨지는 것은 아님.
// 다른 파일에서 사용하려면 package 선언. 임의 이름으로 선언 가능. package myextension // 기존에 존재하는 List에 filterByOdd() 함수 확장. fun List<Int>.filterByOdd() = this.filter { it % 2 != 0 }
import myextension.filterByOdd fun main(args: Array<String>) { (1..10).toList().filterByOdd().forEach { print("$it ") } }
1 3 5 7 9
그리고 Override할 수 없고, 정적으로 결정된다.
open class MouseEvent class RightButtonEvent: MouseEvent() fun MouseEvent.onKeyUp() = println("MouseEvent") fun RightButtonEvent.onKeyUp() = println("RightButtonEvent") fun main(args: Array<String>) { val test: MouseEvent = RightButtonEvent() // 정적으로 지정한 MouseEvent의 onKeyUp이 호출된다. test.onKeyUp() }
MouseEvent
기본적으로 …Of 형태로 생성 가능.
fun main(args: Array<String>) { // 중위 표현식. to라는 Method는 접미사로 infix가 붙어 가능한 표현. val map = hashMapOf(1 to "one", 2 to "two") map[3] = "three" // Destructuring for ((key, value) in map) { println("$key $value") } // Java에서 제공하지 않는 함수들은 모두 확장 함수(Extension Functions) println(map.keys.max()) }
1 one
2 two
3 three
변경자 | 클래스 멤버 | 최상위 선언 |
---|---|---|
public (default) | 모두 | 모두 접근 가능 |
internal | 같은 모듈 | 같은 모듈 |
protected | 하위 클래스 | - |
private | 같은 클래스 | 같은 파일 |
Module : https://kotlinlang.org/docs/reference/visibility-modifiers.html#modules