개요


어차피 요즘 나오는 언어들이 추구하는 방향이 비슷한 것 같다. JS의 최신 문법들을 확인하다보면, 코틀린도 별반 다를 것 없다는 생각이 든다. 화살표 함수, 리터럴, 맵, 리듀스 등등 편의성을 향상시켜 놓은 것이 전부이다. 그렇기 때문에 빠르게 Cheating Sheet를 정리하겠다.

 

기본


1. Hello World 프로그램 구성

fun main(args: Array<String>){

pringln("Hello, World")

}

//  fun  : 함수 예약어 / main  : 함수명 / args  : 입력파라미터명 / Array<String> : 입력파라미터 타입

 

2. 함수 선언

fun sum(a:Int, b:Int): Int {

return a + b

}

// fun : 함수 예약어 / a,b : 입력파라미터명 / ':Int' : 입력, 출력 파라미터 타입

 

3. Single-Expression 함수 

fun sum(a:Int, b:Int) = a + b

// '함수 선언부' = : one 라인 로직을 통해 return을 표현 가능

 

4. 변수 선언 with Nullable Types

var <propertyName>[: <PropertyType>] [= <property_initializer>][<getter>][<setter>] // [] 부분은 생략 가능(자동으로 추론됨), getter, setter 는 기본적으로 만들어지지만, 재정의할 수 있음.

val length: Int

// val : Read-only를 의미

// var : mutable을 의미

// val로 선언한 변수의 초기값을 변경할 수는 없지만, 일반적인 상수변수와 다름 → 단지 setter 가 없는, 바꿀 수 없는 것

// const라는 예약어를 이용해 상수 변수 선언, 최상위 레벨에서 선언할 때만 const 예약어 사용 가능 

var name: String? = null

// ? : null을 의미 / name은 nullable(null값이 올 수 있음을 미리 정의)

// 기본적으로 null 대입이 허용되지 않지만 ? 을 이용하면 허용

// return text?.get(0) // text가 null이면 get 메서드는 호출되지 않으며, get의 리턴 값도 null이 된다.

// return editText?.getText()?.toString() // 둘 중 하나라도 null 이면 null 리턴

// 간혹 변수가 null 값이 아님이 확실한데도 Nullable로 선언된 경우(특히 Java로 정의된 메서드에 접근할 때)  변수의 이름 뒤에 !!를 붙여 Non-Null 타입으로 강제 캐스팅

// """ 으로 멀티라인 스트링 대입 가능

// as 연산자(캐스팅 연산자)

// as? 연산자는 ClassCastException이 발생해야 하는 상황에 에러 발생 없이 Null 리턴

// val x: String? = y as? String // 캐스팅에 실패할 경우 Exception이 발생하지 않고 x에 null값이 대입된다. 

length = name?.length ?: 0

// name.length / name? : name은 ?(null)일 가능성이 있음 / '?: 기본값' : ?이 null을 의미, null일 경우 0 

length = name?.length ?: return

// name.length / name이 null일 경우 return

length = name?.length ?: throw Error()

// name.length / name이 null일 경우 throw Error()

 

- 코틀린의 숫자 타입의  클래스들은 모두 Number 타입의 서브 클래스

- 문자(Characters)는 Number Type이 아니다.

Number Type에 대한 자동 형 변형(implicit conversions for number)을 제공하지 않는다. : ToXXX() 변환 함수 사용

- 숫자 타입에 대입되는 데이터에 언더바(Underscore) 추가 가능(가독성 Up!)

 ex) val oneMillion: Int = 1_000_000 

- 코틀린 클래스의 최상위 클래스는 Any (Java의 Object 느낌)

- Unit : 기본 리턴 (java 의 void 느낌), 생략 가능

- Nothing : 의미 있는 데이터가 없다는 것을 명시적으로 선언하기 위해 사용하는 타입

제어 구조


1. If문 as an expression

fun bigger(a: Int, b: Int) = if (a > b) a else b

// return을 붙이지 않아도, 끝 statement를 return으로 취급한다.

 

2, For 반복문

val list = listOf("A", "B", "C")

for(element in list){

Pringle(element)

}

// in : for문 keyword

 

Iterator “ hasNext() 함수와 next() 함수를 이용해 순차적 이용

 

val list1= listOf<String>("hello","list")
val iterator1=list1.iterator()
while (iterator1.hasNext()){
    println(iterator1.next())
}

 

3. When Expression

fun numberTypeName(x:Number) = when(x) {

0 -> "Zero".                    //동일여부 체크

in 1..4 -> "Four or less"   //범위 체크

5,6,7 -> "Five To Seven" //멀티 벨류 체크

is Byte -> "Byte"             //값 타입 체크

else    -> "Other Value"  //이외

}

// 편의성 있게, 유형 분류 가능 / Single Expression, 화살표 함수를 활용 / switch 상위호환

 

4. When Expression with Predicates

fun signAsSTring(x: Int) = when {

x < 0 -> "Negative"

x == 0 -> "Zero"

else -> "Positive

}

// 편의성 있게, 크기에 따른 분류 가능 / if 상위호환

 

클래스


1. 주 생성자

class Person(val name: String, var age: Int)

// name은 read-only 속성, age는 mutable 속성, 클래스 생성되고 나면, 이름은 변경불가

 

2. 상속

open class Person(val name: String){

open fun hello() = "Hello, I am $name" //오버로딩?

// JS의 템플릿 리터럴처럼 "" 안에 $변수로 표현

class PolishPErsion(name: String) : Person(name) {

override fun hello() = "Hi, I am $name"

}

 

3. 속성 with assessors(악세서리 형식)

class Person(var name: String ,var surname: String){

var fullName: String                   //변수지만, 함수와 같이 get, set의 로직을 정의

get() = "$name $surname"  //비구조적 할당

set(value) {

val (first, rest) = value.split(" ", limit = 2)

name = first

surname = rest

}

}

// JS의 비구조적 할당처럼 val(first, rest) = 로 표현

 

4. Data 클래스

data class Person(val name: String, var age: Int)

val mike = Persion("Mike",23)

//data modifier를 추가해줄 경우

//toString, equals, hashCode, 비구조화 할당, copy 함수가 추가로 제공된다.

mike.toString()                                                         // 모든 주생성자 값을 출력

mike == Persion("Mike", 23)                                     // 모든 주생성자를 비교해서, 완전히 같을 경우 True

mike.hashCode() == Person("Mike",23).hashCode() // 모든 주생성자를 참고해서 HashCode생성

val(name, age) = mike                                              //주생성자를 비구조화하여, 개별 변수로 입력해줄 수 있음

val Jake = mike.copy(name = "Jake")                       //나머지는 다 동일한 상태에서, 클래스 객체 복사 가능

 

콜렉션 리터럴


1. List(링크드..? 리스트) 선언

listOf(1,2,3,4)                // List<Int>

mutableListOf(1,2,3,4) // MutableList <Int>

List(4) {it * 2}               // it는 iterator를 의미하며, 리스트의 개별 요소를 의미, it는 4에서 시작

// 선언에 이런식올 표현할 경우, 8,16,32,64... 식으로 무제한 증가

// 아니면 8,10,12,14일수도.. it값이 만약 4에서 시작해서 1씩증가한다면 가정한다면

// 콜렉션의 개별값이 이전값에서 *2씩 곱하는 값을 취한다는 의미이다.

 

 

2. Set(집합) 선언

setOf("A", "B" , "C")       //Set<String>

mutableSetOf("A", "B", "C") //MutableSEt<String>

 

3. Array(배열) 선언

arrayOf('a', 'b'. 'c') //Array<Char> , 작은 따옴표는 Char형을 의미

 

4. Map(Key Value 맵) 선언

mapOf(1 to "A", 2 to "B") //Map<Int, String>

mutableMapOf(1 to "A", 2 to "B") //MutableMap<Int, String>

 

5. Sequence 선언

sequenceOf(4,3,2,1) // Sequence<Int>

generateSequence(4){it + 1} // Sequence<Int>

//it는 4에서 시작하여, 4,5,6,7,8 형태의 무한배열을 취한다.

//콜렉션의 개별값이 이전값에서 +1 씩 더하는 값을 취한다는 의미이다.

 

6 Pair 선언

1 to "A" //Pair<Int, String>

 

# 콜렉션 처리

students

.filter { it.passing && it.averageGrade > 4.0 } 

// filter : 조건에 맞는 것만 남김 / it은 iterator의 줄임말로, 탐색 당시 해당 객체를 의미

       .sortedByDescending {it.averageGrade}

       // sortedByDescending : 각 객체의 averageGrade값 기준으로 정렬

       .take(10) 

       //상위 10개만 취함

       .sortedWith(compareBy({it.surname}, {it.name}))

       //각 객체의 surname 기준으로 먼저 정렬한 후에, name 기준으로 정렬

 

 

generateSequence(0) { it + 1}

.filter {it % 2 == 0 } 

//filter : 해당 조건을 만족하는 것만 남김

.map { it *3 }

//map : 모든 값에 일괄 매핑(적용)

.take(100) 

//take : 상위 100개만 취함

.average()

//average. : 평균 계산

 

 

val list = listOf(1,2,3,4)

1. filter : 콜렉션 상에서, 조건에 해당하는 값만 남김

list.filter {it % 2 == 0 }

 

2. map : 콜렉션 상에 존재하는 모든 객체에 일괄 작업 적용

list.map {it * 2}

 

3. flatmap. : 콜렉션 상에 존재하는 모든 객체에 일괄 작업을 적용하되, N개의 객체가 존재하는 컬렉션을 N*m개의 객체가 존재하는 컬렉션으로 변경 가능

list.flatmap {listOf(it, it+10)} //[1,11,2,12,3,13,4,14]

 

4. fold/reduce : 콜렉션 상에 존재하는 모든 객체를 축적하여, 특정 값을 계산

list.fold(0.0){ acc, i -> acc + I

//acc값은 0.0부터 시작하되, i는 개별 iterator(it)를 의미함, acc값에 개별 it값들을 더해가는 방식으로 최종 acc 값을 반환

list.reduce{acc, I -> acc * I

//acc값은 1부터 시작하되, i는 개별 iterator(it)를 의미함, acc값에 개별 it값들을 곱해가는 방식으로 최종 acc 값을 반환

 

5. forEach/onEach

list.forEach{ print(it) } //1234 출력 / 출력값 : Unit(기존 리스트에 변경값 적용)

list.onEach{ print(it) }  //1234 출력 / 출력값 : [1,2,3,4] 리스트(변환된 새로운 리스트)

 

6. partition : 조건에 맞는 것이랑 맞지 않는 콜렉션을 두 파트로 나누어 줌

val (evenlist, oddlist) = list.partition { it % 2 == 0}  //true, false에 따라

 

7. min/max/minBy/maxBy : 해당 콜렉션의 최솟값, 최댓값, 특정 조건을 일괄 적용했을 때, 최솟값

list.min()             //1

list.minBy { -it } //4

//일괄 개별 객체에 -1 연산을 했을 때의 기준으로, 최소값

list.max()           //4

list.maxBy-it } //1

 

8. first/firstBy : 해당 콜렉션의 가장 첫번쨰 값, 특정 조건을 만족하는 값중에서 첫번째값

list.first()                     //1

list.first { it% 2 == 0} //2

//해당 조건을 만족하는 값의 첫번째, 내부적으로 임시적 Filter 연산

 

9.count : 특정 조건에 맞는 값을 카운팅

list.count { it % 2 == 0} //2

 

10. sorted/sortedBy : 조건에 따라 정렬된 콜렉션 반환

list.sorted() //[1,2,3,4]

list.sortedBy {it % 2} //[2,4,1,3]

//개별 객체에 일괄 %2한 값을 기준으로 정렬(보통은 속성값이 들어감)

 

11. groupBy : 콜렉션상에 존재하는 모든 객체에 대해 일괄 연산 후, 계산된 연산결과값을 key값(특정 속성값이 될 수 있음)으로 하고, value는 해당하는 객체의 리스트 값으로 하여,  맵 콜렉션 형식으로 반환

list.groupBy {it % 2} // Map : {1=[1,3], 0=[3,4]}

 

12. distinct/distinctBy

list.distinct() //유일한 값을 가지는 요소만 남긴 콜렉션 반환

 

# Mutable vs Immutable 콜렉션 처리 함수 비교

val list = mutableListOf(3,4,2,1)

val sortedResult = list.sorted() //정렬된 새로운 콜렛션 반환

//기존 list 순서에는 영향을 안줌, 새로운 배열 반환

println(sortedResult)                //[1,2,3,4]

println(list)                               //[3,4,2,1]

 

val sortResult = list.sort()         //기존 Mutable List를 정렬

println(sortResult)                    //kotlin.Unit

println(list)                               //[1,2,3,4]

 

# 어떠한 Object(클래스)이든지, 확장(사용)가능한 Functions

this : apply / run,with

it     : also       / let

 

val dialog = Dialog().apply {

title = "Dialog Title"

onClick { print("Clicked")}

}

 

함수


1. 함수 타입

() -> Unit : 입력 파라미터도 없고, 출력 파라미터도 없을 경우, Unit 객체를 반환하는 함수

(Int, Int) -> Int : 두개의 정수 입력 파라미터와 한개의 정수 출력 파라미터로 구성된 함수

(()->Unit)-> Int : 함수를 입력 파라미터로 받고, 정수 출력 파라미터를 반환하는 함수

(Int) -> () -> Unit : 정수 입력 파라미터를 받고, 출력 파라미터로 함수 반환하는 함수[입력 파라미터는 전체를 항상 소괄호로 표현할 것]

 

# 함수 리터럴

val add:(Int, Int) -> Int = {I,k -> I + j}

// 간단한 Lambda Expression(함수형 표현식)

// (int, Int) -> Int : 특정유형의 함수라는 타입을 의미

// (I, k) : 함수의 입력 파라미터

// (I + j) : 함수 처리 및 출력값을 의미

// 화살표 함수로 실제 함수 구현부 표현

val printAndDouble: (Int) -> Int = {

println(it)

// 람다 표현식 내에서, 하나의 입력 파라미터만 받을 경우, it으로 받을 수 있다.

it * 2

// 람다 표현식 내에서, 마지막 표현식은 함수의 출력값이 된다.

}

 

val I = printAndDouble(10) //10

print(i) //20

 

# 확장 함수 : 특정 클래스 또는 기존 타입 클래스에 임의로 사용자 정의 함수를 정의하여, 확장 및 추가할 수 있다.

fun Int.isEven() = this % 2 == 0

// Int라는 기존 클래스에 isEven()이라는 함수 추가

print(2.isEven()) //true

 

fun List<Int>.average() = 1.0 * sum() /size

print(listOf(1,2,3,4).average()) //2.5

 

# Delegates(대표)

1. Lazy : 미리 계산하지 않고, 처음으로 해당 변수가 사용될 때, 계산한다(성능용도)

val I by lazy {print("init"); 10}

print(i) //init 10 출력

print(i) //10 출력

//

• lateinit은 var 타입만 가능하고 lazy는 val 타입만 가능

• lateinit은 primitive type은 불가능하나 lazy는 가능

 • lateinit은 Non-null 타입만 가능하나 lazy는 둘 다 가능

 • lateinit은 로컬 변수에서는 불가능 하나 lazy는 가능

2. notNull : 마지막으로 할당된 값을 반환, 어떠한 값도 설정된 적이 없었으면 에러반환(null값이면 안됨)

 

3. observable/vetoable : 값이 변할 경우에 콜백함수를 호출해줌, vetoable 함수는 새로운 값이 설정되었을 경우 호출됨

var name by observable("Unset"){pooled,new -> println("${p.name} 이 $old 에서 $new로 변경되었습니다.")}

name = "Marcin"

//name이 Unset에서 Marcin으로 변경되었습니다.

 

4. Map/MutableMap : 속성 이름에 의해 맵에 대한 값을 찾는다.

val map = mapOf("a" to 10)

val a by map //속성 이름만으로, 값 할당

print(a) // 10

 

접근 제어자


public(default) : 프로젝트 내 어디서나

private : 같은 클래스내에서만 Visible

protected : 같은 클래스와 상속받은 클래스 내에서만 Visible

Internal : 클래스가 접근가능하면 같은 모듈내에서만 Visible

 

# Variance Modifier

Number > Int

class Box<T> : Box<Number> 와 Box<Int>는 Invariance한 관계이다.

class Box<out T> : Box<Number> 와 Box<Int>는 covariance한 관계이다.

class Box<in T> : Box<Number> 와 Box<Int>는 contravariance한 관계이다.

 

 

 

출처


https://blog.kotlin-academy.com/kotlin-cheat-sheet-1137588c75a

https://one-delay.tistory.com/20?category=793470

 

 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기