Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- KotlinInAction
- 코틸린인액션
- 스프링 핵심 원리
- Kotlin
- kotlin in action 정리
- 코틀린
- 13460 구슬탈출 2
- 7장 고급매핑
- spring
- 스프링 컨테이너와 스프링 빈
- 스프링 핵심 원리 - 기본편
- 자바 ORM 표준 JPA 프로그래밍 7장
- 객체 지향 설계와 스프링
- Python
- 기능개발 python
- 스프링 핵심 원리 이해
- 코틀린인액션
- 고급매핑
- Kotlin in action 5장
- 백준 20055 컨베이어 벨트 위의 로봇
- 20055
- 20055 컨베이어 벨트 위의 로봇
- Kotlin in action 10장
- Kotlin in action 3장
- 백준 13460 Python
- 컨베이어 벨트 위의 로봇 Python
- Kotlin in action 6장
- 싱글톤 컨테이너
- 백준
- Kotlin In Action
Archives
- Today
- Total
기록하는 습관
[Kotlin In Action]2장 - 코틀린 기초 본문
** 이 글은 Kotlin In Action을 읽고 정리한 글입니다. **

1. 기본 요소 : 함수와 변수
1-1. 함수
-
코틀린에서 if 는 식(expression)이지 문(statement)이 아니다.
-
식 : 값을 만들어내며 다른 식의 하위 요소로 계산에 참여할 수 있다.
-
문 : 자신을 둘러싸고 있는 가장 안쪽 블록의 최상위 요소로 존재하며 아무런 값을 만들어내지 않는다.
-
-
자바에서는 모든 제어 구조가 ‘문’ 인 반면, 코틀린은 루프를 제외한 대부분의 제어 구조가 ‘식’이다.
// 블록이 본문인 함수 (본문이 중괄호로 둘러싸인 함수)
fun max(a : Int, b : Int) : Int {
return if ( a > b ) a else b
}
// 식이 본문인 함수 (등호와 식으로 이뤄진 함수)
fun max(a : Int, b : Int) = if ( a > b ) a else b
-
식이 본문인 함수 에서는 타입 추론이 가능하다.
- 블록이 본문인 함수는 반드시 반환 타입을 지정하고 return문을 사용해 반환 값을 명시해야 함.
1-2. 변수
- 코틀린에서는 타입 지정을 생략하는 경우가 흔하므로 변수 선언을 시작하는 대신 변수 이름 뒤에 타입을 명시하거나 생략하게 허용한다.
- 초기화 식이 있는 경우 변수 타입을 생략할 수 있다.
- 초기화 식이 없으면 컴파일러가 추론할 수 없다.
// 초기화 식 사용할 때
val answer = 42
val answer: Int = 42
// 초기화 식 사용하지 않을 때
val answer: Int
answer = 42
-
val (value) : 변경 불가능한 (immutable) 참조를 저장하는 변수. 초기화 후에 제대입이 불가능 하고 자바의 final 변수에 해당한다.
-
var (variable) : 변경 가능한 (mutable) 참조. 자바의 일반 변수.
기본적으로는 모든 변수를 val 키워드를 사용해 불변 변수로 선언하고,나중에 꼭 필요할 때에만 var로 변경하기.
- val 변수는 블록 실행시 정확히 한 번만 초기화 되어야 함.
- val 참조 자체는 불변일지라도 그 참조가 가리키는 객체의 내부 값은 변경될 수 있다.
val languages = arrayListOf("Java") // 불변 참조를 선언
languages.add("Kotlin") // 참조가 가리키는 객체 내부를 변경
var 키워드를 사용하면 변수의 값을 변경할 수 있지만 변수의 타입은 고정된다.
- 컴파일러는 변수 선언 시점의 초기화 식으로부터 변수 타입을 추론하고, 변수 선언 이후 변수 재대입이 이뤄질 때는 이미 추론한 변수의 타입을 염두에 두고 대입문의 타입을 검사한다.
1-3. 문자열 템플릿
- 문자열 리터럴 안에서 변수를 사용하는방법
val name = if (args.size > 0) args[0] else “Kotlin.”
println(“Hello, $name”);
2. 클래스와 프로퍼티
- 값 객체: 코드 없이 데이터만 저장하는 클래스
- 코틀린 기본 가시성은 public이다.
2-1. 프로퍼티
-
클래스라는 개념의 목적은, 데이터를 캡슐화하고 캡슐화한 데이터를 다루는 코드를 한 주체 아래 가두는 것이다.
-
자바에서는 데이터 필드에 저장하고, 멤버 필드의 가시성은 보통 비공개다. 클래스는 클라이언트의 접근을 위해 접근자 메소드를 제공한다. 필드를 읽고 쓰기 위해서는 getter, setter 를 제공해야 한다.
-
자바에서는 필드, 접근자를 묶어 프로퍼티 라고 부른다.
-
코틀린은 프로퍼티를 언어 기본 기능으로 제공하며 자바의 필드, 접근자 메소드를 대신한다.
- val: 읽기 전용, getter만 제공
- var: 읽기/쓰기 가능, getter / setter 모두 제공
class Person{
val name: String
var isMarried: Boolean
}
val person = Person("Hue", false)
// 필드 이름으로 직접 접근
println(person.name)
println(person.isMarried)
person.isMarried = true
2-2. 커스텀 접근자
- 프로퍼티의 접근자를 사용자 정의로 작성하는 방식
class Rectangle (val height : Int, val width : Int) {
val isSquare : Boolean
get() { // 프로퍼티 게터 선언
return height == width
}
}
2-3. 코틀린 소스코드 구조 : 디렉터리와 패키지
-
코틀린의 패키지는 자바의 패키지와 비슷하다. 같은 패키지에 속해 있다면 다른 파일에서 정의한 선언일지라도 직접 사용할 수 있다.
-
다른 패키지에 정의한 선언을 사용하려면 import 키워드를 통해 사용할 수 있다.
-
자바에서는 디렉터리 구조가 패키지 구조를 그대로 따라야 하지만, 코틀린에서는 패키지구조와 디렉터리 구조가 동일하지 않아도 상관없다.
-
코틀린에서는 여러 클래스를 한 파일에 넣을 수 있다. -> 소스코드 크기가 아주 작은 경우 유용하다.
-
다만, 자바와 코틀린을 함께 사용할 때는 자바의 방식에 따르는 게 중요하다. 자바 클래스를 코틀린 클래스로 마이그레이션시 문제가 생길 수 있다.
3. 선택 표현과 처리 : enum 과 when
-
코틀린의 when 은 자바의 switch 를 대치하되 더 강력하다.
3-1. enum 클래스 정의
-
자바는 enum, 코틀린은 enum class 를 사용한다.
- 소프트 키워드
- class 앞에서는 enum 클래스를 의미, class가 없다면 키워드가 아님
- enum에서도 일반적인 클래스와 마찬가지로 생성자와 프로퍼티를 선언
enum class Color {
val r : Int, val g : Int, val b : Int
} {
RED(255,0,0), … BLUE(0,0,255) … VIOLET(238, 130, 238);
fun rgb() = (r * 256 + g) * 256 + b
}
3-2. when 으로 enum 클래스 다루기
-
when 은 자바의 switch 와 같이 분기의 끝에 break 를 넣지 않아도 된다.
-
한 분기 안에서 여러 값을 매치 패턴으로 사용할 때는 콤마(,)를 사용하면 된다.
fun getWarmth(color : Color) = when(color) {
RED, ORANGE, YELLOW -> “warm”
GREEN -> “neutral”
}
3-3. when 과 임의의 객체를 함께 사용
-
switch 달리 when은 분기 조건에 임의의 객체를 허용한다.
- 객체 사이를 매치할 때 동등성(값 비교)을 사용
fun mix(c1: Color, c2: Color) =
when (setOf(c1, c2)) {
setOf(RED, YELLOW) -> ORANGE
...
else -> throw Exception(“Dirty Color”)
}
3-4. 인자 없는 when 사용
-
위의 코드는 계속해서 setOf 를 호출하기 때문에 효율적으로 보이지 않을 수 있다. 이런 경우 인자가 없는 when 을 사용하려 불필요한 객체 생성을 막을 수 있다.
fun mixOptimized(c1 : Color, c2 : Color ) =
when {
(c1 == RED && c2 == YELLOW) ||
(c1 == YELLOW && c2 == RED) -> ORANGE
…
else -> throw Exception(“Dirty Color”)
}
참고) Kotlin의 동등성이란?
- 자바에서는 == 동등성 비교 연산자가 원시 타입의 비교에서는 값 비교, 객체의 비교에서는 참조값(주소)를 비교한다.
- 코틀린에서는 Object에 대응하는 Any 클래스에 equals가 정의되어 있고 Any 클래스는 모든 클래스의 조상이다. == 연산자는 내부적으로 equals 메소드를 수행한다.
- 참조값 비교는 '==='를 사용한다.
3-5. 스마트캐스트 : 타임 검사와 타입 캐스트를 조합
-
(1 + 2) + 4 산술식을 계산하는 함수를 만들어보자.
interface Expr
class Num(val value : Int) : Expr
class Sum(val left : Expr, val right : Expr) : Expr
// (1+2)+4 표현
Sum (Sum (Num(1), Num(2)), Num(4))
fun eval(e : Expr) : Int {
if (e is Num) {
val n = e as Num // 불필요한 중복
return n.value
}
if (e is Sum) {
return eval(e.right) + eval(e.left) // 스마트 캐스트 사용
}
throw IllegalArgumentException(“Unknown expression”)
}
-
코틀린은 is 를 통해 변수 타입을 검사한다. is 는 자바의 instanceOf 와 비슷하다.
-
자바의 instanceOf 는 타입 확인 후, 해당 타입에 접근하기 위해서는 명시적으로 변수 타입을 캐스팅 해야 한다. 그러나 코틀린은 컴파일러가 이런 캐스팅을 대신 해준다.
-
스마트 캐스트란, 코틀린에서 is 로 검사를 하고 나면 컴파일러가 캐스팅을 수행해줘서 해당 타입으로 사용할 수 있게 되는 것이다.
- val로 정의 되어야하며 커스텀 접근자를 사용한 것이면 안됨.
-
원하는 타입으로 명시적으로 캐스팅 하려면 as 를 사용하면 된다.
3-6 리팩토링 : if 를 when 으로 변경
// 값을 만들어 내는 if 식
fun eval(e : Expr) : Int =
if (e is Num) {
e.value
} else if (e is Num) {
eval(e.right) + eval(e.left)
} else {
throw IllegalArgumentException(“Unknown expression”)
}
// when 으로 리팩토링
fun eval(e : Expr) : Int =
when(e) {
is Num -> e.value
is Sum -> eval(e.right) + eval(e.left)
else -> throw IllegalArgumentException(“Unknown expression”)
}
4. 대상을 이터레이션 : while 과 for 루프
4-1. while 루프
-
코틀린의 while, do-while 은 자바와 비슷하다.
4-2. 수에 대한 이터레이션 : 범위와 수열
-
코틀린은 자바의 for 루프 요소가 없다. 대신 범위를 사용한다.
-
범위는 기본적으로 두 값으로 이뤄져있으며, ‘..’ 연산자로 시작과 끝을 연결해 범위를 만든다.
- ex) val oneToTen = 1..10
-
어떤 범위에 속한 값을 일정한 순서로 이터레이션 하는 경우를 수열이라고 부른다.
4-3. 맵에 대한 이터레이션
val binaryReps = TreeMap<Char, String>()
for (c in ‘A’..’F’) {
val binary = Integer.toBinaryString(c.toInt())
binaryReps[c] = binary
}
for((letter, binary) in binaryReps) {
println(“$letter=$binary”)
}
-
.. 연산자는 숫자 타입 뿐 아니라 문자 타입에도 적용 가능
4-4. in으로 컬렉션이나 범위의 원소 검사
-
in 을 사용하여 어떤 값이 범위에 속하는지 검사할 수 있다. 반대의 경우는 !in 을 사용하면 된다.
fun isLetter(c : Char) = c in ‘a’..’z’ || c in ‘A’..‘Z'
5. 코틀린의 예외 처리
5-1. try, catch, finally
fun readNumber(reader : BufferedReader) : Int? {
try {
val line = reader.readLine()
return Integer.parseInt(line)
}
catch (e : NumberFormatException) {
return null
}
finally {
reader.close()
}
}
-
자바와 코틀린 차이점
-
코틀린에는 자바와 달리 throws 절이 코드에 없다.
- 자바에서는 checked exception을 명시적으로 처리해야 한다.
- 코틀린은 unchecked exception과 checked exception을 구별하지 않는다.
- 코틀린에서는 함수가 던지는 예외를 지정하지 않고 발생한 예외를 잡아도 되고, 잡아내지 않아도 된다.
-
5-2. try를 식으로 사용
fun readNumber(reader : BufferedReader) {
val number = try {
Integer.pasreInt(reader.readLine())
} catch ( e : NumberFormatException) {
return
}
println(number)
}
-
코틀린의 try 키워드는 if나 when 과 같이 식이다. 따라서 try 의 값을 변수에 대입할 수 있다.
'스터디 > Kotlin In Action' 카테고리의 다른 글
[Kotlin In Action]6장 - 코틀린 타입 시스템 (0) | 2023.03.13 |
---|---|
[Kotlin In Action]5장 - 람다로 프로그래밍 (0) | 2023.02.27 |
[Kotlin In Action]4장 - 클래스, 객체, 인터페이스 (0) | 2023.02.20 |
[Kotlin In Action]3장 - 함수 정의와 호출 (0) | 2023.02.06 |
[Kotlin In Action]1장 - 코틀린이란 무엇이며, 왜 필요한가? (0) | 2023.01.16 |
Comments