- Today
- Total
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- CustomTab
- 책리뷰
- GIT
- 안드로이드
- androidstudio
- n3문법
- 일본어문법
- Android
- 진짜학습지
- 학습지
- Kotlin
- blog
- PR
- 책추천
- 일본어기초
- posting
- 진짜학습지후기
- errorhandling
- jlpt
- KotlinInAction
- webflux
- 진짜일본어
- github
- coroutine
- 인공지능
- pullrequest
- rxjava
- ai
- suspend
- 코틀린
코딩하는 개굴이
[Kotlin IN ACTION] 코틀린 기초 문법 본문
본 내용은 Kotlin IN ACTION (드미트리 제메로프, 스베트라나 이사코바 지음 / 에이콘 출판사) 책을 기반으로 작성되었습니다.
Kotlin IN ACTION 2강 : 코틀린 기초
Hello World!
fun main(args: Array<String>) {
println("Hello World!")
}
해당 코드에서 코틀린의 특징을 알아보자.
- 함수를 선언 시에, fun 키워드를 사용한다.
- 파라미터 이름 뒤에 파라미터의 타입을 쓴다. (변수 선언 시에도 마찬가지)
- 함수를 최상위 수준에 정의할 수 있다. (클래스 안에 함수를 넣어야 할 필요가 없다.)
- 배열 처리를 위한 문법이 따로 존재하지 않는다.
- 출력 시 println을 사용한다. (표준 자바 라이브러리 함수를 간결하게 사용 할 수 있도록 감싼 wrapper 를 제공하기 때문에 가능한 것)
- 세미 콜론을 붙이지 않아도 된다.
함수
fun max (a: Int, b: Int): Int{
return if (a > b) a else b
}
해당 식에서 코틀린의 특징을 알아보자.
- 함수 선언 키워드인 fun 뒤에는 함수 이름이 온다.
- 함수 이름 뒤에는 괄호 안에 파라미터 목록이 온다.
- 함수의 반환 타입은 파라미터 목록 다음에 콜론(:)으로 구분 후 다음에 온다.
- 코틀린에서의 if 는 식이다.
- 해당 코드는 본문이 중괄호로 둘러싸인 함수 즉, 블록이 본문인 함수이나, 등호화 식으로 이루어진 식이 본문인 함수로 변환할 수 있다.
- 코틀린에서는 아래와 같은 형태로, if, when, try 등에도 사용한다.
- 식이 본문인 함수에 한해서 반환 타입을 생략 가능하다.
fun max(a: Int, b: Int): Int = if (a > b) a else b
//반환 타입 생략 가능
fun max(a: Int, b: Int) = if (a > b) a else b
식과 문
자바에서 주로 if 를 표현 시 if문이라고 배웠을 것이다. 그러나, 코틀린에서의 if는 식에 해당한다. 둘은 각각 정확히 무엇인가?
- 식 : 값을 만들어 내며, 다른 식의 하위 요소로 계산에 참여할 수 있다.
- 문 : 자신을 둘러써고 잇는 가장 안쪽 블록의 최상위 요소로 존재하며, 아무런 값을 만들어 내지 않는다.
- 코틀린에서의 식 : 코틀린에서는 루프를 제외한 대부분의 제어 구조가 식에 해당한다.
변수
val doraemonHeight = 129.3
//타입을 명시해도 된다
val doraemonHeight: Double = 129.3
- 타입을 지정하지 않을 시, 컴파일러가 초기화 식을 분석하여 초기화 식의 타입을 변수 타입으로 지정
- val : 변경 불가능한 참조를 저장하는 변수로, 초기화하고나면 재대입이 불가한 final 에 해당하는 변수
- 기본적으로 모든 변수를 val 로 선언해 사용하고 꼭 필요할 때만 var 을 사용할 것을 권장
- 참조 자체는 변경될 수 없지만 참조가 가리키는 객체의 내부 값은 변경될 수 있다. (예시 > array 추가 등)
- var : 변경 가능한 참조로, 일반 변수에 해당
- 변수의 값을 변경할 수는 있지만 변수의 타입을 변경할 수는 없다
문자열 형식 지정
Hello World 예제를 사용자의 이름을 받아 인사를 출력하는 프로그램을 구현해 보자.
fun main(args: Array<String>) {
val name = if (args.size > 0) args[0] else "World" //만일 사용자가 인자를 넘기지 않았다면 Hello Wordl!을 출력한다.
println("Hello $name!") //문자열 템플릿
}
//중괄호를 이용해 문자열 템플릿에 식을 넣어 더 간략하게 사용 가능
fun main(args: Array<String>) {
println("Hello ${if (args.size > 0) args[0] else "World"}!") //문자열 템플릿
}
- 문자열 템플릿 : $을 앞에 붙여 변수를 문자열 안에 사용할 수 있다
- 컴파일러는 각 식을 정적으로 컴파일 시점에 검사하며, 이때 존재하지 않는 변수가 발견될 경우 컴파일 오류를 발생시킨다.
- 참고 : $을 문자열에 넣고 싶을 경우 \을 앞에 붙인다.
- 중괄호로 둘러 쌓아 식의 형식을 넣을 수 있다.코틀린도 자바처럼 한글을 변수처럼 사용할 수 있기 때문에 문자열 템플릿 사용 시 '$name님이 접속하였습니다.' 와 같은 형태 사용 시 영문자와 한글을 동시에 인식하여 'name님' 을 변수로 인식할 수 있다. 따라서, 식이 아닌 일반 변수이 더라도 '${name}'의 형태로 쓰는 습관을 가지자.
클래스
자바에서의 클래스와 코틀린의 클래스 선언 형태를 비교해보자.
class Doraemon {
private double height;
public Doraemon(double height) {
this.height = height;
}
public double getHeight() {
return height;
}
}
자바에서는 클래스의 필드가 늘어날수록 생성자의 파라미터와 getter/setter가 점점 늘어나게 된다.
그에 비해 Kotlin은 간단하게 해결이 가능하다.
class Doraemon(val height: Double) //정말 이게 끝이다. 어메이징 :D
- java와 달리 클래스의 접근자 public이 생략되었는데, 코틀린은 기본 가시성이 java와 달리 public이므로, 생략해도 된다.
프로퍼티
클래스의 개념은 데이터를 캡슐화 하는 것에 있다. 자바에서는 필드와 접근자(getter/setter)를 한데 묶어 프로퍼티라고 부르나, 코틀린은 프로퍼티를 언어의 기본으로 제공하고 선언 시에 변수와 마찬가지로 val(읽기 전용) 이나 var(변경도 가능)을 사용한다.
class Doraemon(
val height: Double,
var weight: Double,
)
...
//사용
val miniDora = Doraemon(129.3, 129.3)
println(miniDora.height)
miniDora.weight = 132.9 //변경 가능한 프로퍼티의 경우 자바의 세터 대신 위와 같이 사용한다.
println(miniDora.weight)
- 커스텀 접근자 : 별도의 필드에 저장할 필요가 없이 구현을 제공하는 getter만 존재하며, 프로퍼티에 접근할 때마다 getter가 프로퍼티 값을 매번 다시 계산한다.
class Doraemon(
val height: Double,
var weight: Double,
) {
val doreamonBMI : Double
get(){
return weight/(height * height)
}
}
...
//사용
val miniDora = Doraemon(129.3, 129.3)
println(miniDora.doraemonBMI)
코틀린 소스 코드 구조
기본적인 import는 자바와 유사하다. 하위 정의된 함수와 프로퍼티를 구체적으로 import 가능하나, 상위를 import 하여 사용해도 컴파일에 문제가 없다. 코틀린에서는 클래스 뿐 아니라 함수와 프로퍼티까지 단위로 임포트 가능하다.
위의 코드를 예로 들어, package comics.doreamon
에 fun getTools
라는 함수가 존재한다고 하면, import comics.doraemon.getTools
를 하면 해당 함수만 import 가능하다.
- 자바에서는 디렉터리 구조가 패키지 구조를 그대로 따라야 하여, comics package 아래 doraemon 패키지가 존재해야만 하나, 코틀린에서는 여러 클래스를 한 파일에 넣을 수 있고 이름도 자유롭게 정할 수 있기 때문에 패키지 구조와 디렉터리 구조가 일치해야 할 필요가 없다.
- 여러 클래스를 한 파일에 넣는 것을 주저하지 않으면서, 일반적으로 자바의 방식대로 패키지 별로 디렉터리를 구성할 것을 권장한다.
enum 클래스 정의
enum class Tools { //enum class 를 사용해야 한다.
POCKET, DOOR, COPTER, LIGHT, TIMEMACHINE
}
//위와 같이 단순히 열거할 수도 있으나, 클래스 안에 프로퍼티나 메소드를 정의할 수 있다.
enum class Tool(val name: String, val id: Int) {
POCKET("주머니", 0),
DOOR("어디로든 문", 1),
COPTER("대나무 헬리콥터",2),
LIGHT("스몰라이트", 3),
TIMEMACHINE("타임머신", 4); //끝나는 부분에 반드시 세미콜론을 사용해야 한다.
fun getInfo() = "[ID : ${id}] ${name}"
}
- 코틀린에서 유일하게 세미콜론을 필수로 넣어야 한다.
- enum클래스 안에 메소드를 정의하는 경우는 반드시 상수목록과 메소드 정의 사이에 구분을 위해 세미콜론을 넣어야 한다.
When
- 자바에서의 switch 에 해당한다.
- if 와 마찬가지로 식이며, 식이 본문인 함수에 바로 사용할 수 있다.
- 자바와 같이 한 분기에 여러 식을 사용할 수도 있다.
- 임의의 객체 형태 또한 허용하여 switch 보다 강력하다.
- 각 분기의 조건이 boolean 결과를 계산하는 식이라면 when 에 인자가 없어도 된다.
import example.colors.Color
fun checkWarmColor(c: Color) =
when (c) {
RED, ORANGE, YELLOW -> true
BLUE, BLACK -> false
}
fun mixColor(c1: Color, c2: Color) =
when (setOf(c1, c2)) {
setOf(RED, YELLOW) -> ORANGE
setOf(YELLOW, BLUE) -> GREEN
setOf(RED, BLUE) -> PURPLE
else -> throw Exception("Color Not Supported")
}
//동일한 코드를 아래와 같이도 구현 가능하다.
fun mixColor(c1: Color, c2: Color) =
when {
(c1 == RED && c2 == YELLOW) ||
(c1 == YELLOW && c2 == RED) -> ORANGE
(c1 == YELLOW && c2 == BLUE) ||
(c1 == BLUE && c2 == YELLOW) -> GREEN
(c1 == RED && c2 == BLUE) ||
(c1 == BLUE && c2 == RED) -> PURPLE
else -> throw Exception("Color Not Supported")
}
타입 캐스팅
- 원하는 타입으로 명시적 타입 캐스팅 시 as 키워드를 사용한다.
val value = v as Num
- 원하는 타입이 맞는지 확인 시 is 키워드를 사용한다.
fun eval (e: Expr) : Int =
if(e is Num) {
e.value
} else if (e is Sum) {
eval(e.right)+ eval(e.left)
}
//when 으로 변경
fun eval (e: Expr) : Int =
when (e) {
is Num -> e is Num
e.value
is Sum -> e is Sum
eval(e.right)+ eval(e.left)
}
이터레이션
while
while(조건) {
//해당 조건이 참인 동안 반복 실행한다.
}
do {
//맨 처음에 무조건 한번 실행 한 후, 조건이 참인 동안 반복 실행한다.
} while(조건)
for
for (i in 1..100) {
print("count : ${i}")
}
for (i in 100 downTo 1 step 2) {
//downTo는 역방향 수열을 만든다
//step은 증가 값의 절댓값이 2로 바뀐다.
print("even count down : ${i}")
}
val list = arrayListOf("사이다", "콜라", "주스")
println("[메뉴]")
for((index, element) in list.withIndex()) {
//인덱스와 함께 컬렉션을 이터레이션 한다.
println("${index} : ${element}")
}
in으로 컬렉션이나 범위 검사
fun recognize(c: Char) = when (c) {
in '0'..'9' -> "digit"
in 'a'..'z', in 'A'..'Z' -> "letter"
else -> "ERROR"
}
print("OrangeJuice" in "Milk".."Coffee") //"OrangeJuice" <= "Milk" && "OrangeJuice" <= "Coffee"와 동일하다
print("OrangeJuice" in setOf("Milk","Coffee")) //이 집합에 OrangeJuice가 들어있는지 확인한다.
예외 처리
if(number !in 0..100) {
throw IllegalArgumentException("This is not between 0~100 : ${number}") //throw 또한 식으로, 다른 식에 포함될 수 있다.
}
val checkNumber = if(number !in 0..100) {
number
} else {
throw IllegalArgumentException("This is not between 0~100 : ${number}") //false 이면 변수가 초기화 되지 않는다. 출력시 null 이 반환된다.
}
//예외 처리 시 try, catch, finally를 함께 사용하며, 자바와 동일하다.
val readNumber(reader: bufferedReader) : Int? {
try{
val line = reader.readLine()
return Integer.parseInt(line)
//try 또한 if, when 과 같이 식이므므로 변수에 대입할 수 있다. 이때 catch 는 return 만 사용하면 그 이상 실행되지 않으나, 해당 대입 이후 기본 값으로 진행을 원할 때는 null 등을 이용하면 된다.
} catch (e: NumberFormatException) {
return null
} finally {
reader.close()
}
}
'안드로이드 > KOTLIN' 카테고리의 다른 글
[Kotlin IN ACTION] 코틀린 타입 시스템 (0) | 2021.04.11 |
---|---|
[Kotlin IN ACTION] 클래스, 객체, 인터페이스 (0) | 2021.04.04 |
[Kotlin IN ACTION] 함수 정의와 호출 (0) | 2021.03.29 |
[Kotlin IN ACTION] 코틀린이란 무엇이고 왜 필요할까? (0) | 2021.03.21 |
[Kotlin] let, apply, run, with, also (0) | 2021.03.01 |