Kotlin
빠르게 배워보는 kotlin
Kotlin 사용 목적
서버를 위한 언어
서버단의 어플리케이션 개발에 좋은 언어
이미 있는 JAVA 기반 기술들과도 호환
Android가 지원하는 언어
Android 이전 버전들과 호환 및 java로 개발한 앱 만큼 성능
Javascript
Kotlin으로 작성한 코드를 JS로 변환시켜주는 기능 (Typescript처럼 가능하나, 사실 라이브러리 생태계가 그닥인듯..)
Native 지원
VM 없이 실행 가능한 Binary 파일 생성 가능 (LLVM 기반)
Variables
변수 var 상수 val (한번 값을 입력하면 변경이 안되는 변수)
타입은 변수명 : 뒤에 붙는다.
val a: Int = 1
val b = 2
val c :Int
c = 3
var x = 5
x = 1
//String
var v =1
var s1 = "a string"
var s2 = "$s1 and $v"
var s3 = """
abc
def
efg
"""
function
fun 키워드를 사용하며 파라미터에는 변수명:타입을 쓰고 리턴타입을 지정
fun sum(a: Int, b:Int): Int{
return a + b
}
fun sum(a:Int,b:Int) = a + b
아무것도 리턴하지 않으면 Unit을 리턴 타입으로 사용하거나 생략한다.
fun sum(a:Int, b:Int): Unit{
print("sum(${a},${b})=${a+b}")
}
Program entry point
main 함수를 entry point로 가진다.
fun main(){
println("Hello world")
}
조건문
fun maxOf(a:Int, b:Int) :Int{
if(a > b){
return a
}else{
return b
}
}
println(maxOf(5,2))
NULL 키워드
Null 을 가질수 있는 타입은 반드시 명시적으로 표기가 되어야됨
fun parseInt(str:String) : Int?{
return str.toIntOrNull()
}
if(parseInt("A")==null) {
println("a is not a number")
}
Type 확인 (=typeOf)
is 연산자로 타입 확인
if(obj is String)
Loop
for in
val items = listOf("a","b","c")
for(item in items){
println(item)
}
for((index, value) in array.withIndex()){
println("the element at $index is $value")
}
while
var index = 0
while(index < items.size){
println("items[$index]=${items[index]}")
index++
}
do{
val y:Int? = null
println("!")
}while( y != null)
when (=switch)
fun describe(x:Int) =
when(x){
1 -> println("x == 1")
2 -> println("x == 2")
3, 4 -> println("x == 3 or x == 4")
else -> println("x is neither 1 nor 2")
}
describe(5)
when(x){
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
Ranges
..키워드로 특정 범위의 값을 표현식에 사용
if (2 in 1..3){
println("2 is in range")
}
(= 1 <= 2 && 2 <= 3)
for(x in 1..3){
println(x)
}
for(x in 1..10 step 2){
print(x)
}
-> 1,3,5,7,9
Numbers 타입
byte, short, Int, Long, Float, Double
val one = 1 // Int
val threeBillion = 3000000000 // Long
val oneLong = 1L // Long
val oneByte: Byte = 1
val pi = 3.14 // Double
val e = 2.7182818284 // Double
val eFloat = 2.7182818284f // Float, actual value is 2.7182817
//밑줄 표현
//숫자 사이에 밑줄을 써서 표현가능
val oneMillion = 1_000_000
Representation
=== 는 참조하는 object를 비교하고 == 는 가지고 있는 value를 비교한다.(= java equals)
Java에선 null을 가질 수 없는 숫자 변수는 primitive type으로 처리
but Int?와 같이 null을 가질 수 있는 타입은 boxing 되어 처리된다. ==> 값은 같으나, 즉 주소값에 따라 다른 객체로 인식한다. (Integer 타입으로 변환) (Int와 Integer 타입의 차이)
val : a Int = 10000
val boxedInt : Int? = a
val anotherBoxedA: Int? = a
println(boxedInt === anotherBoxedA) // false
Explicit conversions
작은 데이터 타입의 변수를 더 큰 데이터 타입으로 변환할수 없다.
ex) Byte 변수의 값을 Int에 바로 대입할수 없다.
val a : Int? = 1
val b : Long? = a
print(a == b) // -- false
val b:Byte = 1
val i:Int = b.toInt()
* 모든 숫자 타입은 변환 함수가 존재
toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char
소수점 비교
변수 a,b가 Float, Double로 타입이 명확하면, Floating point에 따른 연산 불명확하면, equals()와 compareTo()함수를 사용한다.
NaN is considered equal to itself:
NaN 이 NaN 자신과 동등한 것으로써 비교가 가능하다.
NaN is considered greater than any other element including POSITIVE_INFINITY:
NaN 은 POSITIVE_INFINITY 을 포함해 다른 어떤 것보다 크다. -0.0 is considered less than 0.0: -0.0 이 0.0 보다 작은것으로 간주된다.
fun compare(a:Any, b:Any){
println(a == b)
}
fun main(){
println(Double.NaN == Double.NaN)
compare(Double.NaN == Double.NaN)
println(-0.0 == 0.0)
println(-0.0, 0.0)
}
Character
문자는 char를 사용하고, 작은 따온표로 표시 당연히 숫자값이 직접 대입해서 쓸 수 없다. (JAVA와 다름 주의!)
특수 문자는 \ 역 슬래쉬를 사용한다.
var a:Char = '1'
var b:Int = a.toInt()
Booleans
true / false
nullable reference 일 때 boxed 된다.
Arrays
생성 함수 arrayOf(), arrayOfNulls(), emptyArray()
element 접근 : get(), set()
val a = arrayOf(1,2,3)
a.set(2,5) // 1,2,5
var b = arrayOfNulls<String>(3) //(size) [ , , ] == new int [3]
if(b[0] == null){
println("b[0] is null")
}
Array 배열의 크기와 초기값 설정 함수
val a = Array<String>(3,{i -> i.toString()})
a.forEach{ print(it) } // 012
primitive type Arrays
boxing overhead 없이 primitive type의 배열을 위한 클래스
ex) ByteArray, ShortArray, IntArray
val x : IntArray = intArrayOf(1,2,3)
x[0] = x[1] + x[2]
val arr = IntArray(5) // [0,0,0,0,0]
if Expression
if else모양이지만 값이 리턴되는 표현식이 존재, if를 표현식으로 쓰려면, 모든 경우의 리턴값이 존재해야 하므로, else branch가 반드시 함께 사용되어야한다.
val max = if(a > b) a else b
val max = if(a > b){
print("Choose a)"
a
}else{
print("Choose b)"
b
}
Kotlin의 jump expressions : return, break, continue
val s = person.name ? : return
Break and Continue Label
expression은 Label로 표시될 수 있으며 식별자(=@) 뒤에 붙인다.
ex) abc@
loop@ for(i in 1..10){
for(j in 1..10){
if(...) break@loop
}
}
listOf(1,2,3,4,5).forEach{
if(it == 3) return
print(it)
}
// 1,2
listOf(1,2,3,4,5).forEach lit@{
if(it == 3) return@lit
print(it)
}
// 1,2,4,5
listOf(1,2,3,4,5).forEach{
if(it == 3) return@forEach
print(it)
}
//1,2,4,5
listOf(1,2,3,4,5).forEach(fun(value:Int){
if(value == 3) return
print(value)
})
//=> 익명함수를 사용하면 return은 자신의 함수만을 종료하게 되고 외부에는 영향을 끼치지 않는다.
//1,2,4,5
Kotlin 클래스의 프로퍼티와 필드
property는 var 또는 val로 선언

property_initializer는 property의 데이터 초기화
getter, setter는 데이터 변경, 접근을 위한 접근자
위 기능들은 생략이 가능하며, 암묵적으로 기본적인 기능이 구현된다. initalizer로 부터 property의 타입 추론이 가능한 경우 type을 생략 가능 => ex) var a = 1
Late-initalized Propeties
보통의 property는 constructor에서 null이 아닌 어떤 값으로 초기화되어야됨 바로 초기화를 하지 않고, 특정 조건이 만족한 후 초기화를 하고 싶은 경우, lateinit을 사용
클래스 body안에서 var 에서 사용할수 있고, top-level properties와 지역변수에 쓸수 있음. 변수는 null이 될수 없고, promitive type이 아니여야한다. primary constructor 안에서 사용할 수 없으며,custom 생성자를 쓰지 않는 경우에만 사용 가능
public class MyTest{
lateinit var subject:TestSubject
@Setup fun setup(){
subject = TestSubject()
}
@Test fun test(){
subject.method()
}
}
* 초기화 여부 확인
if(foo::bar.isInitialized){
println(foo.bar)
}
Interface
추상화 메소드와 구현코드를 가지고 있고, state를 저장할 수 없다. 한개의 클래스나 오브젝트는 한개 이상의 인터페이스를 가질수있음
인터페이스는 property를 가질 수 있으나, 추상화하거나 접근자를 구현해야한다. state를 지정할 수 없는 속성 때문에 property는 backing fields를 가질수 없으므로, interface 내의 접근자들 또한 property를 참조할 수 없다.
interface Named{
val name : String
}
inteface Person : Named{
val firstName: String
val lastName : String
override val name : String get() = "$firstName $lastName"
}
data class Employee{
override val firstName: String,
override val lastName: String,
val position: Position
} : Person
Visibility Modifer
private, protected, internal, public
public은 모든 곳에서 접근 가능
private 선언한 파일 내에서만 접근 가능
internal 같은 모듈 안 어디에서나 접근 가능
protected 최상위 선언이 불가능 다른 패키지로부터 최상위 선언들을 사용하려면 import를 해야한다.
Extension
kotlin의 클래스는 상속이나 디자인 패턴인 Decorator를 통한 기능확장 외의 방법인 extension을 제공 수정이 불가능한 3rd party 라이브러리 클래스에 함수 추가 가능
fun MutableList<Int>.swap(index1:Int,index2:Int){
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
val list = MutableListOf(1,2,3)
list.swap(0,2)
확장 함수가 클래스의 멤버함수를 overload 하는 것은 가능하다.
class Example{
fun printFunctionalType(){
println("Class Method")
}
}
fun Example.printFunctionalType(i:Int){
println("$i Extension function")
}
Example().printFunctionalType(1)
extionsion은 nullable receiver type으로 정의 가능 = object의 값이 null일 수도 있고 함수에서 this == null처럼 체크가 가능
fun Any?.toString():String{
if(this == null) return "null"
return toString()
}
Data class
데이터를 저장하기 위한 클래스
컴파일러가 자동으로 primary constructor의 properties로부터 아래의 멤버 생성
equals() / hashcode()
"User(name=john, age=42)" 폼의 toString()
copy()
data class가 파라미터가 없는 constructor가 필요하면 모든 프로퍼티에 대한 기본값이 설정되어야한다.
특정 property를 제외하려면 클래스 내부에 선언하면 된다.
data class Person(val name:String){
var age: Int = 0
}
//Destructuring Declarations
val jane = User("Jane", 35)
val (name, age) = jane
Last updated
Was this helpful?