SKKU SW/Mobile App Programming

[Kotlin] Kotlin(코틀린) 기본 문법 간단 정리(val/var, if/when, for/while, null safety(?. / ?.let / ?: / !! / as?), function, collections, constructor)

효딩 2024. 5. 4. 18:10

What is Kotlin?

- Cross-platform,

- statically typed(정적타입 언어),

- JVM-targeted programming language Built-in null safety support

정적 타입 언어: 컴파일 시 변수의 타입이 설정되고, 그 이후로 타입은 변화하지 않는다.
동적 타입 언어: 런타임에 변수의 타입이 결정된다.

 

kotlinlang.org

온라인 코틀린 컴파일러

 

Basic syntax

kotlin은 ; 사용하지 않음

같은 줄에 multiple statement 작성할 때만 세미콜론(;) 사용

ex)

val mynumber = 10; println(mynumber)

 

variable declaration

1. val: read-only local variables

can be assigned a value only one 초기에 값을 할당하면 나중에 값을 변경할 수 없다.

값을 변경하게 되면 컴파일 에러 발생

(java의 final과 유사)

val a: Int = 1
// val 변수명: 변수타입 = 값
// 변수타입 선언 권장
val b = 2
val c: Int
c = 3

 

2. var: variables that can be reassigned

var x = 5
x += 1

다른 타입의 값을 넣을 수 없다.

다른 타입의 값으로 재정의 한다면 타입 미스매치 Error 발생

string → “ ”

char → ‘ ‘

auto type casting 지원 (변수 타입 명시하지 않아도 됨)

 

 

If expression

fun maxOf(a: Int, b: Int): Int {
	if (a > b) {
		return a
		} else {
			return b
		}
	}
fun maxOf(a: Int, b: Int) = if (a > b) a else b

 

When expression

conditional expression with multiple branches

C의 switch statement와 유사함

when (x) {
	1 -> print("x == 1")
	2 -> print("x == 2")
	else -> {
		print("x is neither 1 nor 2")
	}
}

코틀린 컴파일러는 when이 표현식으로 사용될 때 else 부분이 존재하는지, 표현식이 가능한 모든 입력에 대해 값을 생성하는지 검증한다.

즉, when을 표현식으로 사용했는데 else가 없거나 처리할 수 없는 예외 입력 케이스가 있다면 컴파일러는 오류를 발생시킨다.

all cases가 covered 된다면 else을 사용하지 않아도 된다.

 

For loops

C#의 foreach loop와 유사하다.

val items = listOf("apple", "banana", "kiwi")
for (item in items) {
	println(item)
}
val items = listOf("apple", "banana", "kiwi")
for (index in items.indices) {
	println("item at $index is ${items[index]}"))
}

items.indices

for (x in 1..10 step 2) {
	print(x)
}

for (x in 9 downTo 0 step 3) {
	print(x)
}

// downTo로 역순 범위 지정

step

downTo

 

While loops

while: condition을 check한 뒤 조건 만족한다면 body를 실행하고 다시 condition check로 돌아간다.

do-while: body를 실행하고 condition을 check한다. 만족한다면 loop repeats.

while (x > 0) {
	x--
}

do {
	val y = retrieveData()
} while (y != null)

while → 컨디션 판단 먼저

do while → 실행 후 컨디션 판단

 

Null safety

Kotlin은 null value를 default로 hold할 수 없다.

타입 시스템이 null이 가능한 참조와 그렇지 않은 참조를 구분한다.

null이 가능한 value라면 명시적으로 nullable하다고 mark해둬야 한다

var a: String = "abc"
a = null // 컴파일 에러 발생
val b: String ?= null
println(b?.length)
// returns b.length if b is not null,
// and null otherwise

 

?. null safe call operator

val l = if (b != null) b.length else -1
bob?.department?.head?.name
// 이 중 하나라도 null이라면 returns null

 

?.let

안전한 호출 연산자 let

→ null이 아닌 값에 대해서만 특정 연산 수행

ignores null

val listWithNulls: List<String?> = listOf("Kotlin", null)
for (item in listWithNulls) {
	item?**.let** {println(it)} // prints Kotlin and ignores null

 

?: Elvis operator

null이 들어오면 다른 값/실행 코드를 반환해준다.

val l = b?.length ?: -1
// b.length가 null이 아니라면 그대로 return하고
// null이라면 -1를 return한다.
?: throw IllegalArgumentException("name expected")

 

!! not-null assertion

→ 값을 non-null type으로 변환해주고 value가 null이라면 exception(Null Point Exception) 발생

val l = b!!.length
// b.length가 null 아니라면 그대로 실행
// null 이라면 null point exception 발생

 

as? safe cast operator

어떤 값을 지정한 타입으로 캐스트

대상 타입으로 캐스트할 수 없어 failure 떴을 때 null 반환

val aInt: Int? = a as? Int

 

Functions

fun sum(a: Int, b: Int): Int {
	return a + b
}

fun printSum(a: Int, b: Int) {
	println("sum of $a and $b is ${a + b}")
	// return type 명시하지 않아도 됨

Unit: useful value를 return하지 않으면 return type은 Unit

Unit is a type with only one value

void와 비슷함

unit return type declaration 생략 가능

fun double(x: Int): Int = x * 2
fun double(x: Int) = x * 2
// explicitly declaring the return type is optional
// when this can be inferred by the compiler

 

collections overview

kotlin standard library는 basic collection type으로 sets, lists, maps를 제공한다.

read-only 불변: collection element에 접근하기 위한 기능을 제공한다.

mutable 가변: collection element를 더하거나 지우거나 변경하는 등의 기능을 제공한다.

참조자인 변수가 변경되는 것이 아니므로 꼭 var를 사용해야 하는 것은 아니다.

listOf → read-only

mutableListOf → mutable

val numbers = setOf(1, 2, 3, 4)
val numbersBackwards = setOf(4, 3, 2, 1)

println(numbers.first() == numbersBackwards.first()) // false
println(numbers.first() == numbersBackwards.last()) // true

List<T>

: 지정된 순서대로 element 저장.

0부터 시작하는 인덱스로 element 접근

길이가 같고 구조적으로 동일하면 동등한 list로 판단한다.

Set<T>

: 순서 없는 element 저장.

중복 없이 모든 element는 유일하며 null도 유일하므로 한 개만 가질 수 있다.

길이 같고 element 같으면 동등한 set으로 판단한다.

Map<K, V>

:key-value pairs 저장

key는 유일, 같은 value 가진 key 존재 가능

순서 상관 없이 같은 key-value 값들 가지면 동등한 map으로 판단한다.

val numberMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)
val numberMap = mapOf("key2" to 2, "key1" to 1, "key4" to 1, "key3" to 3)
println("The maps are equal: ${numberMap == anotherMap}") // true

creating classes and instances

class Shape // define a class

class의 properties는 declaration이나 body에 listed될 수 있다.

class Rectangle(var height: Double, var length: Double) {
	var perimeter = (height + length) * 2
}

class간 상속은 콜론(:)으로 선언

class는 default가 final. 상속을 원한다면 mark it as open

open class Shape

class Rectangle(var height: Double, var length: Double): Shape() {
	var perimeter = (height + length) * 2
}

상속을 해줄 클래스가 open을 해주어야 다른 클래스가 상속 받을 수 있다.

상속받을 클래스: 상위타입

 

Classes- Constructors

primary constructor는 상황에 따라 생략 가능

상황: annotation이나 접근 제한자

secondary constructors는 prefixed with constructor (생략 불가능)

primary constructor 있다면 각 secondary constructor는 primary constructor를 위임받아야 함

→ this

delegation to another constructor of the same class

같은 클래스의 다른 constructor에게 위임하는 경우 this keyword 사용

class Person(val name: String) {
	val children: MutableList<Person> = mutableListOf()
	constructor(name: String, parent: Person) : this(name) {
		parent.children.add(this)
	}
}
// 여기서 name이 하나의 primary constructor
// 어노테이션이나 접근 제한자 갖고 있지 않다면 constructor 키워드 생략 가능

primary constructor 없더라도 delegation은 여전히 발생

class Constructors {
	init {
		println("Init block")
	}
	constructor(i: Int) {
		println("Constructor $i")
	}
}

init 블럭(primary constructor의 일부)의 코드는 항상 secondary constructor의 body보다 먼저 실행된다.

access control (modify state, help to expose only the data wish to expose…)

→ part of a larger object-oriented concept known as encapsulation

 

getter, setter

코틀린은 var 변수 만들어주기만 해도 getter, setter 내부적으로 컴파일 단계에서 자동으로 생성해줌