반응형
Main 함수
fun main(args: Array<String>) {
println("Hello World")
}
변수의 선언
val a: Int = 10 // 변경 불가능한 변수
var b: Int = 5 // 변경 가능한 변수
var c: Int? = null // null을 가질 수 있는 변수
var d = "Hello World"
var e = """
Hello
World
""".trimIndent()
형 변환
var a: Int = 54321
var b: Long = a.toLong()
배열
var a = arrayOf(1, 2, 3, 4, 5)
var b = arrayOfNulls<Int>(5)
println(a[1])
println(b[1])
타입 추론
var a: Int = 54321 // 일반적인 사용
var b = 12345 // 타입 추론
함수
fun add(a: Int, b: Int): Int {
return a + b
}
fun add(a: Int, b: Int) = a + b
var result = add(1, 2)
when
fun doWhen(a: Any) {
when (a) {
1 -> println("1")
"Hello", "Hello World" -> println("Hello")
is Long -> println("is long type")
!is String -> println("is not string type")
else -> println("else")
}
}
fun doWhen(a: Any) {
var result = when (a) {
1 -> "1"
"Hello", "Hello World" -> "Hello"
is Long -> "is long type"
!is String -> "is not string type"
else -> "else"
}
println(result)
}
fun doWhen(a: Any) {
val result = when {
a == 1 -> "1"
a in arrayOf("Hello", "Hello World") -> "Hello"
a is Long -> "is long type"
a !is String -> "is not string type"
else -> "else"
}
println(result)
}
fun main() {
doWhen(1) // 1
doWhen("Hello") // Hello
doWhen(12L) // is long type
doWhen(3.14159) // is not string type
doWhen("Kotlin") // else
}
if
val number = 5
val status = if (number % 2 == 0) "EVEN" else "ODD"
val number = 5
if (number in 1..10) {
println("1부터 10 사이의 숫자")
}
val value = 5
if (value is Int) {
println("value는 숫자")
}
val value: String? = "ABCDE"
value?.takeIf { it.length >= 5 }?.let { println(it) } // 길이가 5보다 크므로 let 구문 실행
value?.takeUnless { it.length >= 10 }?.let { println(it) } // 길이가 10보다 크지 않으므로 let 구문 실행
for
// 0부터 9까지 1씩 증가
for (i in 0..9) {
println(i)
}
// 0부터 9까지 3씩 증가
for (i in 0..9 step 3) {
println(i)
}
// 9부터 0까지 1씩 감소
for (i in 9 downTo 0) {
println(i)
}
// a부터 e까지 증가
for (i in 'a'..'e') {
println(i)
}
흐름 제어
loop@for (i in 1..10) {
for (j in 1..10) {
// 조건에 해당 되면 loop라는 라벨의 루프를 종료(continue도 동일하게 사용 가능)
if (i == 1 && j == 2) {
break@loop
}
println("i : $i, j : $j")
}
}
클래스 기본 구조
class Person(var name: String, val birthYear: Int)
fun main() {
var a = Person("John", 1990)
println("${a.name} : ${a.birthYear}")
}
class Person(var name: String, val birthYear: Int) {
fun introduce() {
println("${name} : ${birthYear}")
}
}
fun main() {
var a = Person("John", 1990)
a.introduce()
}
class Person1 {
var name: String? = null
}
class Person2 {
var name: String? = null
private set
fun changeName() {
name = "john"
}
}
fun main() {
val person1 = Person1()
person1.name = "john"
println(person1.name)
val person2 = Person2()
// person2.name = "john" // 불가능
person2.changeName()
println(person2.name)
}
클래스의 생성자
class Person(var name: String, val birthYear: Int) {
init {
// 기본 생성자 실행시 호출되는 부분
println("${this.name} : ${this.birthYear}")
}
constructor(name: String) : this(name, 1997)
}
fun main() {
var a = Person("John", 1990)
var b = Person("Tom")
}
클래스의 상속
// 상속 받게 할 수 있도록 class 앞에 open 키워드 필요
open class Animal(var name: String, var age: Int, var type: String) {
fun introduce() {
println("${this.name}, ${this.age}, ${this.type}")
}
}
class Dog(name: String, age: Int) : Animal(name, age, "개")
fun main() {
var a = Animal("happy", 5, "개")
var b = Dog("happy", 5)
a.introduce()
b.introduce()
}
오버라이딩
open class Animal {
open fun eat() {
println("음식을 먹습니다")
}
}
class Tiger : Animal() {
override fun eat() {
println("고기를 먹습니다")
}
}
fun main() {
var a = Tiger()
a.eat()
}
추상클래스
abstract class Animal {
abstract fun eat()
}
class Rabbit : Animal() {
override fun eat() {
println("당근을 먹습니다")
}
}
fun main() {
var a = Rabbit()
a.eat()
}
인터페이스
interface Runner {
fun run()
}
interface Eater {
fun eat() {
println("음식을 먹습니다")
}
}
class Dog : Runner, Eater {
override fun run() {
println("달리는중")
}
override fun eat() {
println("먹는중")
}
}
fun main() {
var a = Dog()
a.run()
a.eat()
}
고차함수
fun a(str: String) {
println(str)
}
// Unit 리턴 타입 없음
fun b(function: (String) -> Unit) {
function("Hello")
}
// ::는 고차함수를 지칭하는 키워드
fun main() {
b(::a)
}
람다
fun b(function: (String) -> Unit) {
function("Hello")
}
fun main() {
val a: (String) -> Unit = { str -> println(str) }
// val a = { str: String -> println(str) }
b(a)
b { str -> println(str) }
}
fun calc(a: Int, b: Int, calculator: (Int, Int) -> Int): Int {
return calculator(a, b)
}
fun main() {
println(calc(1, 2) { a, b -> a + b })
println(calc(1, 2) { a, b -> a * b })
}
스코프 함수(Scope Function)
- 인스턴스의 속성이나 함수를 스코프 함수 내에서 쉽게 접근해서 사용 가능
Extension Scope Function 예제
class Book(var name: String, var price: Int) {
fun discount() {
price -= 2000
}
}
fun main() {
// 컨텍스트 객체 참조 : this
// 리턴 : 컨텍스트 객체
val book1 = Book("Kotlin", 10000).apply {
name = "[초특가] $name"
discount()
}
// 컨텍스트 객체 참조 : it
// 리턴 : 컨텍스트 객체
val book2 = Book("Kotlin", 10000).also {
it.name = "[초특가] ${it.name}"
it.discount()
}
// 컨텍스트 객체 참조 : this
// 리턴 : 람다식의 실행 결과
val bookInfo1 = Book("Kotlin", 10000).run {
"${name} : ${price}"
}
// 컨텍스트 객체 참조 : it
// 리턴 : 람다식의 실행 결과
val bookInfo2 = Book("Kotlin", 10000).let {
"${it.name} : ${it.price}"
}
println("${book1.name} : ${book1.price}") // [초특가] Kotlin : 8000
println("${book2.name} : ${book2.price}") // [초특가] Kotlin : 8000
println(bookInfo1) // Kotlin : 10000
println(bookInfo2) // Kotlin : 10000
}
Non-Extension Scope Function 예제
class Book(var name: String, var price: Int) {
fun discount() {
price -= 2000
}
}
fun main() {
val book = Book("Kotlin", 10000)
// 컨텍스트 객체 참조 : this
// 리턴 : 람다식의 실행 결과
val bookInfo1 = with(book) {
"${name} : ${price}"
}
// 컨텍스트 객체 참조 : 없음
// 리턴 : 람다식의 실행 결과
// 연산 과정을 한 블락으로 관리할 때 사용
val bookInfo2 = run {
"Kotlin : 10000"
}
println(bookInfo1) // Kotlin : 10000
println(bookInfo2) // Kotlin : 10000
}
오브젝트
object Counter1 {
const val NAME = "Counter1"
var count = 0
fun countUp() {
count++
}
}
class Counter2 {
companion object {
const val NAME = "Counter2"
var count = 0
fun countUp() {
count++
}
}
}
fun main() {
Counter1.countUp()
Counter1.countUp()
println("${Counter1.NAME}, ${Counter1.count}")
Counter2.countUp()
Counter2.countUp()
println("${Counter2.NAME}, ${Counter2.count}")
}
클래스의 다형성
open class Drink {
var name = "음료"
open fun drink() {
println("${name}를 마십니다")
}
}
class Cola: Drink() {
var type = "콜라"
override fun drink() {
println("${name}중에 ${type}를 마십니다")
}
fun washDishes() {
println("${type}을 설거치를 합니다")
}
}
fun main() {
var a = Drink()
var b: Drink = Cola()
a.drink()
b.drink()
if (b is Cola) {
b.washDishes()
}
var c = b as Cola
c.washDishes()
b.washDishes()
}
제네릭
open class Animal {
open fun shout() {
println("Animal이 소리칩니다")
}
}
class Dog : Animal() {
override fun shout() {
println("Dog가 소리칩니다")
}
}
class UsingGeneric<T: Animal>(var t: T) {
fun doShouting() {
t.shout()
}
}
fun <T: Animal> doShouting(t: T) {
t.shout()
}
fun main() {
var a = UsingGeneric(Animal())
var b = UsingGeneric(Dog())
a.doShouting() // Animal이 소리칩니다
b.doShouting() // Dog가 소리칩니다
doShouting(Dog()) // Dog가 소리칩니다
}
문자열
fun main() {
val test1 = "Test.Kotlin.String"
println(test1.length) // 18
println(test1.toLowerCase()) // test.kotlin.string
println(test1.toUpperCase()) // TEST.KOTLIN.STRING
println(test1.substring(5..10)) // Kotlin
val test2 = test1.split(".")
println(test2.joinToString()) // Test, Kotlin, String
println(test2.joinToString("-")) // Test-Kotlin-String
}
fun main() {
val nullString: String? = null
val emptyString = ""
val blankString = " "
val normalString = "A"
println(nullString.isNullOrEmpty()) // true
println(emptyString.isNullOrEmpty()) // true
println(blankString.isNullOrEmpty()) // false
println(normalString.isNullOrEmpty()) // false
println(nullString.isNullOrBlank()) // true
println(emptyString.isNullOrBlank()) // true
println(blankString.isNullOrBlank()) // true
println(normalString.isNullOrBlank()) // false
}
null operator
fun main() {
var a: String? = null
// null safe operator
// 객체가 null이면 뒷 구문을 실행하지 않음
println(a?.toUpperCase())
// 아래 내용 실행되지 않음
a?.run {
println(toUpperCase())
}
// elvis operator
// 객체가 null이면 : 다음 객체를 사용
println(a?:"default".toUpperCase())
// non-null assertion operator
// null일 경우 NPE 발생하도록 의도적으로 방치
println(a!!.toUpperCase())
}
fun printName(name: String?) {
name ?: return
println(name)
}
fun main() {
printName(null) // do nothing
printName("john") // "john"
}
내용 동일성, 객체 동일성 체크
class Product(val name: String, val price: Int) {
override fun equals(other: Any?): Boolean {
return other is Product && this.name == other.name && this.price == other.price
}
}
fun main() {
var a = Product("콜라", 1000)
var b = Product("콜라", 1000)
var c = a
var d = Product("사이다", 1000)
println(a == b) // true : equals() 실행 결과가 같은지 확인
println(a === b) // false : 객체가 같은지 확인
println(a == c) // true
println(a === c) // true
println(a == d) // false
println(a === d) // false
}
default arguments
fun exam(name: String = "john", age: Int = 20) {
println("${name}, ${age}")
}
fun main() {
exam("tom")
exam("tom", 30)
exam(age = 30)
}
variable arguments
fun sum(vararg numbers: Int): Int {
var sum = 0
for (num in numbers) {
sum += num
}
return sum
}
fun main() {
println(sum(1, 2, 3))
}
infix function
infix fun Int.multiple(x: Int): Int = this * x
fun main() {
println(6 multiple 4)
println(6.multiple(4))
}
중첩 클래스
- 외부 클래스의 내용을 중첩 클래스 안에서 공유할 수 없음
- 외부 클래스의 생성 없이 사용 가능
class Outer {
class Nested {
fun introduce() {
println("Nested Class")
}
}
}
fun main() {
Outer.Nested().introduce()
}
내부 클래스
- 외부 클래스의 내용을 내부 클래스 안에서 공유할 수 있음
- 외부 클래스 생성 후 사용 가능
class Outer {
var text = "Outer Class"
inner class Inner {
var text = "Inner Class"
fun introduce() {
println("${this@Outer.text}, ${text}")
}
}
}
fun main() {
Outer().Inner().introduce()
}
Data Class
- 데이터를 다루는데 최적화된 클래스
- equals(), hashCode(), toString(), copy(), componentN() 함수를 자동으로 생성
class General(val name: String, val id: Int)
data class Data(val name: String, val id: Int)
fun main() {
val a = General("john", 100)
println(a == General("john", 100)) // false
println(a) // General@6fadae5d
val b = Data("tom", 200)
println(b == Data("tom", 200)) // true
println(b) // Data(name=tom, id=200)
println(b.copy()) // Data(name=tom, id=200)
println(b.copy(name = "jane")) // Data(name=jane, id=200)
println(b.copy(id = 300)) // Data(name=tom, id=300)
}
분리 선언(Destructuring Declarations)
- componentN() 함수를 활용하여 값을 분리하여 선언하는 방식
class Book(val name: String, val price: Int) {
operator fun component1(): String {
return name
}
operator fun component2(): Int {
return price
}
}
data class Person(val name: String, val age: Int)
fun main() {
/*
분리 선언시 다음 코드로 컴파일된다
val a1 = person.component1()
val b1 = person.component2()
*/
val person = Person("john", 25)
val (a1, b1) = person
println("name : ${a1}, age : ${b1}") // name : john, age : 25
val book = Book("Kotlin", 10000)
val (a2, b2) = book
println("name : ${a2}, price : ${b2}") // name : Kotlin, price : 10000
}
fun main() {
/*
Map.Entry는 기본적으로 아래처럼 componentN() 함수가 구현되어 있다.
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator()
operator fun <K, V> Map.Entry<K, V>.component1() = getKey()
operator fun <K, V> Map.Entry<K, V>.component2() = getValue()
*/
val map = mapOf(
"john" to 25
)
for ((key, value) in map) {
println("name : ${key}, age : ${value}") // name : john, age : 25
}
for ((_, value) in map) {
println("age : ${value}") // age : 25
}
println(map.mapValues { entry -> entry.value + 10 }) // {john=35}
println(map.mapValues { (key, value) -> value + 10 }) // {john=35}
println(map.mapValues { (_, value) -> value + 10 }) // {john=35}
}
Private Setter
class Person1(_name: String) {
var name = _name
private set
fun changeName() {
name = "tom"
}
}
class Person2(private var _name: String) {
var name
get() = _name
private set(value) {
_name = value
}
fun changeName() {
name = "tom"
}
}
data class Person3(private var _name: String) {
var name = _name
private set
fun changeName() {
name = "tom"
}
}
data class Person4(private var _name: String) {
var name
get() = _name
private set(value) {
_name = value
}
fun changeName() {
name = "tom"
}
}
fun main() {
val person1 = Person1("john")
// person1.name = "tom" // 불가능
person1.changeName()
println(person1.name)
val person2 = Person2("john")
// person2.name = "tom" // 불가능
person2.changeName()
println(person2.name)
val person3 = Person3("john")
// person3.name = "tom" // 불가능
person3.changeName()
println(person3.name)
val person4 = Person4("john")
// person4.name = "tom" // 불가능
person4.changeName()
println(person4.name)
}
Enum Class
enum class State(val message: String) {
EAT("먹다"),
SLEEP("자다");
fun isSleeping() = this == State.SLEEP
}
fun main() {
println(State.EAT) // EAT
println(State.SLEEP.isSleeping()) // true
}
List
fun main() {
val a = listOf("사과", "딸기", "배")
println(a[1])
for (fruit in a) {
println(fruit)
}
val b = mutableListOf(6, 3, 1)
b.add(4) // 4 추가
b.add(2, 8) // 2번 인덱스에 8값으로 교체
b.removeAt(0) // 0번 인덱스 요소 제거
b.shuffle() // 무작위로 섞기
b.sort() // 정렬
}
Set
fun main() {
val a = mutableSetOf("귤", "바나나")
for (item in a) {
println(item)
}
a.add("자몽")
println(a) // [귤, 바나나, 자몽]
a.remove("바나나")
println(a) // [귤, 자몽]
println(a.contains("귤")) // true
}
Map
fun main() {
val a = mutableMapOf(
"john" to 100,
"tom" to 200
)
for (entry in a) {
println("${entry.key} : ${entry.value}")
}
// 추가
// a.put("jane", 300)
a["jane"] = 300
println(a) // {john=100, tom=200, jane=300}
// 삭제
a.remove("jane")
println(a) // {john=100, tom=200}
// 사용
// println(a.get("john"))
println(a["john"]) // 100
}
컬렉션 함수 - 1
fun main() {
val nameList = listOf("john", "tom", "jane")
nameList.forEach { print("${it} ") }
println() //john tom jane
println(nameList.filter { it.startsWith("j") }) // [john, jane]
println(nameList.map { "이름 : ${it}" }) // [이름 : john, 이름 : tom, 이름 : jane]
println(nameList.any { it == "john" }) // true
println(nameList.all { it.length >= 3 }) // true
println(nameList.none { it.startsWith("a") }) // true
println(nameList.first { it.startsWith("j") }) // john, 찾지 못할 경우 Exception
println(nameList.firstOrNull { it.startsWith("j") }) // john
println(nameList.last { it.startsWith("j") }) // jane, 찾지 못할 경우 Exception
println(nameList.lastOrNull { it.startsWith("j") }) // jane
println(nameList.count()) // 3
println(nameList.count { it.startsWith("j") }) // 2
}
컬렉션 함수 - 2
data class Person(val name: String, val birthYear: Int)
fun main() {
val list = listOf(
Person("john", 1992),
Person("tom", 1996),
Person("jane", 1999),
Person("john", 2003)
)
// {1992=Person(name=john, birthYear=1992), 1996=Person(name=tom, birthYear=1996), 1999=Person(name=jane, birthYear=1999), 2003=Person(name=john, birthYear=2003)}
println(list.associateBy { it.birthYear })
// {john=[Person(name=john, birthYear=1992), Person(name=john, birthYear=2003)], tom=[Person(name=tom, birthYear=1996)], jane=[Person(name=jane, birthYear=1999)]}
println(list.groupBy { it.name })
val (over98, under98) = list.partition { it.birthYear > 1998 }
println(over98) // [Person(name=jane, birthYear=1999), Person(name=john, birthYear=2003)]
println(under98) // [Person(name=john, birthYear=1992), Person(name=tom, birthYear=1996)]
}
컬렉션 함수 - 3
fun main() {
val numbers = listOf(-3, 7, 2, -10, 1)
println(numbers.flatMap { listOf(it * 10, it + 10) }) // [-30, 7, 70, 17, 20, 12, -100, 0, 10, 11]
println(numbers.getOrElse(1) { 50 }) // 7
println(numbers.getOrElse(10) { 50 }) // 50
val names = listOf("A", "B", "C", "D")
// 두 컬렉션 중 작은 컬렉션 기준으로 합치기
println(names zip numbers) // [(A, -3), (B, 7), (C, 2), (D, -10)]
}
lateinit var
class LateInitSample {
lateinit var text: String
fun getLateInitText(): String {
return if (::text.isInitialized) {
text
} else {
"Default"
}
}
}
fun main() {
val a = LateInitSample()
println(a.getLateInitText()) // Default
a.text = "AAA"
println(a.getLateInitText()) // AAA
}
lazy var
fun main() {
val number: Int by lazy {
println("init")
7
}
println("start")
println(number)
println(number)
}
start
init
7
7
반응형
'Development > Kotlin' 카테고리의 다른 글
[Kotlin] Coroutine (0) | 2024.02.17 |
---|---|
[Kotlin] Kotlin 소스 파일 컴파일하여 Class 객체로 로딩하기 (0) | 2023.05.27 |