프로젝트 중 코틀린을 사용해보자는 말에 생소한 코틀린에 대해서 살펴보았다.
Kotlin Programming Language
kotlinlang.org
코틀린에 대해서 알고있는 것은 이름만 들어봤지 알고 있는게 없다. 한번 읽어보자.
Kotlin 을 왜 사용하지?
- 코틀린은 기존 Java 기반 기술 스택과 완전한 호환을 하면서 간결하고 표현력 있는 코드를 작성할 수 있다고 한다.
- Null에 대한 고민이 많이 줄어든다.
- 타입추론으로 코드의 양이 감소한다.
- var 와 val 의 구분으로 개발 실수를 줄여준다.
Variables
변수(Variable)는 var, 상수(value)는 val 를 쓴다.
상수는 한번 값을 할당하면 변경이 불가한 변수이다.
타입은 변수명 : 뒤에 붙는다.
타입은 초기값이 있으면 초기값에 기반에 타입을 지정해주므로 생략이 가능하다.
val a: Int = 1 // 'Int' 타입의 상수 a 의 값은 1
val b = 2 // 상수 b에 값이 숫자 2 이므로 'Int' 타입으로 지정된다.
val c: Int
c = 3 // 초기값이 Int 타입의 상수 c 를 선언한 후에 3을 대입한다.
var x = 5 // 초기값이 5 인 변수 x 는 'Int' 타입으로 지정된다.
x = 1 // 변수 x 의 값을 1로 변경.
String
var a = 1
val s1 = "a is $a" // a is 1
a= 2
val s2 = "${s1.replace("is", "was")}, but now is $a"
// a is 1 , but now is 2
Functions
두 개의 Int 타입 매개변수를 가지고, Int 타입을 반환 하는 함수.
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}")
}
Class & Instance
//클래스 정의 - 상속 받을 수 없다.
class BasicSyntax
//클래스의 속성
class Rectangle(var height: Double, var length: Double) {
var perimeter = (height + length) * 2
}
//클래스를 상속하게 하려면 open 을 앞에 붙혀준다.
open class Shape
class Rectangle(var height: Double, var length: Double): Shape() {
var perimeter = (height + length) * 2
}
Conditional expressions
fun maxOf(a: Int, b: Int): Int {
//일반 적인 If else
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)
}
or
//for loop 인덱스 포함
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 expression
fun describe(obj: Any): String =
when(obj){
1 -> "One" //1일때
"1" -> "String One" //Sting type의 1일때
"Kotlin" -> "Greeting" //문자 Kotlin일때
is Long -> "Long" //Long type일때
!is String -> "Not a string" //문자가 아닐때
else -> "Unknown" //그외
}
Ranges
//x 가 1 ~ 10 에 포함하면 출력.
val x = 10
val y = 9
if (x in 1..y+1) {
println("fits in range")
}
////숫자가 범위를 벗어났는지 확인
val list = listOf("a", "b", "c")
// -1 가 0 ~ 2 에 포함되지 않으면
if (-1 !in 0..list.lastIndex) {
println("-1 is out of range")
}
// list의 size 3이 list.indices(0~2) 에 포함되지 않으면
if (list.size !in list.indices) {
println("list size is out of valid list indices range, too")
}
for (x in 1..5) {
print(x)
}
// 범위 반복 2씩 증가
for (x in 1..10 step 2) {
print(x)
}
println()
//9 ~ 0 역순 3씩 감소
for (x in 9 downTo 0 step 3) {
print(x)
}
Collections
for (item in items) {
println(item)
}
//컬렉션에 in 연산자를 사용하여 개체가 포함되어 있는지 확인(Check if a collection contains an object using in operator.)
fun checkObjectInCollection(item: String): Boolean{
val items = setOf("apple", "banana", "kiwifruit")
return when (item) {
in items -> true
else -> false
}
}
//람다식을 사용하여 컬렉션 필터링과 매핑(Using lambda expressions to filter and map collections:)
fun getCollectionFilterMapping(keyWord: String): List<String>{
val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
return fruits
.filter{it.startsWith(keyWord)} //a로 시작하는 키워드만 필터링
.sortedBy{it} //내림차순 정렬
.map{it.toUpperCase()} //대문자 변환
}
//람다식을 사용하여 컬렉션 필터링과 매핑(Using lambda expressions to filter and map collections:)
fun printCollectionFilterMapping(keyWord: String){
val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
fruits
.filter{it.contains(keyWord)} //a를 포함하는 키워드 필터링
.sortedByDescending{it} //오름차순 정렬
.map{it.toUpperCase()} //대문자 변환
.forEach{it -> println(it)} //출력
}
Nullable values and null checks
null 값이 가능한 참조에는 nullable 을 명시적으로 표시.
nullable 타입은 뒤에 ?을 붙혀준다.