Kotlin을 코틀린스럽게 사용하기 위해 Kotlin in Action 정주행을 시작했다.
앞으로는 아래의 내용들에 대해 정리해서 기록할 계획이다.
- 새롭게 알게된 사실이나 키워드
- 텍스트로는 이해가 잘 안되는 부분
-> 직접 구현 또는 추가 학습
- 기본적인 개념 및 중요한 내용
- 다시 한 번 리마인드할 내용
- 학습하며 생긴 의문점 해결하기
- 전부터 고민하던 부분에 대한 해답을 얻은 경우!
- 개인적으로 신기했던 내용 - ex) Kotlin에 이런 기능도 있구나!
1. 코틀린이란 무엇이며, 왜 필요한가?
- 자바 메서드를 리팩토링하면 그 메서드와 관련 있는 코틀린 코드까지 변경된다. 역의 상황도 같다.
2. 코틀린 기초
2-1. 문(statement)과 식(expression)의 구분
- 식 : 값을 만들어 내며, 다른 식의 하위 요소로 계산에 포함될 수 있음
문 : 값을 만들어내지 않고, 자신을 둘러싸고 있는 가장 안쪽 블록의 최상위 요소로 존재
-> if나 when을 통해 변수에 값을 대입할 수 있으므로 둘은 식이다. 반면에 for, while은 문이다.
-> 루프(for, while 등)를 제외한 대부분의 *제어 구조가 식이다.
* 제어 구조란 프로그램의 흐름을 제어하는데 사용되는 구문이나 구조를 의미한다.
ex) 대입문, 제어문, 반복문, 분기문 등 -> if, when, for, while, return, break, continue
2-2. val과 var의 프로퍼티 차이
- val로 선언 시 백킹 필드로 getter만 생성되고, var로 선언해야 getter-setter 둘 다 생성된다.
2-3. 매개변수의 개수를 최소화 하는 소소한 팁(매개변수를 커스텀 게터로)
class Rectangle(val height: Int, val width: Int, val isSquare: Boolean)
isSquare의 경우, height와 width로 구할 수 있으므로 불필요한 매개변수이다.
따라서, 아래와 같이 커스텀 게터로 이동시켜 클래스 생성 시 입력하는 매개변수의 개수를 최대한 줄이는 습관을 가지자
= 새로운 매개변수를 추가할 때, 기존의 매개변수 값으로 구할 수 없는 값인지 한 번 더 생각하고 추가하자
class Rectangle(val height: Int, val width: Int) {
val isSquare: Boolean get() = height == width
}
2-4. 매개변수의 개수를 최소화 하는 소소한 팁? (매개변수를 메서드로)
enum class Color(val colorText:String, val r: Int, val g: Int, val b: Int) {
RED("빨강", 255, 0, 0), YELLOW("노랑", 255, 255, 0);
}
뭔가 한 눈에 관리할 수 있다는 측면에서는 위의 코드가 나아보이지만, 너무 많은 값들을 프로퍼티로 필요로 할 때는 아래 코드처럼 메소드로 분리하는 게 좋을 것 같다는 생각이 든다. -> 이해한 내용 Q&A
-> [Q&A] 다국어 지원 같이 나라별로 텍스트 내용을 다르게 해줘야 하는 부분도 있어서 별도로 관리하는 게 좋을 것 같다.
enum class Color(val r: Int, val g: Int, val b: Int) {
RED(255, 0, 0), YELLOW(255, 255, 0);
fun getColorText(color: Color) = when(color) {
RED -> "빨강"
YELLOW -> "노랑"
}
}
2-5. when - 한 분기 안에 여러값 사용하기, 분기 조건에 임의의 객체 사용하기
- 한 분기 안에서 여러 값을 사용하려면 각 값들 사이에 ", "를 구분자로 추가해주면 된다.
- 코틀린 when의 분기 조건은 임의의 객체를 허용한다!!
fun getMixColor(c1: Color, c2: Color) =
when (setOf(c1, c2)) {
setOf(RED, YELLOW) -> ORANGE
setOf(YELLOW, BLUE) -> GREEN
else -> throw Exception("예외 처리")
}
2-6. 스마트 캐스트 : 타입 검사 시 자동으로 타입 캐스팅
- 상속 관계에서 부모의 타입인 변수를 자식의 타입으로 검사(is)시, 컴파일러에 의해 자동으로 타입 캐스팅 된다.
- 주의사항 : 그 값이 바뀔 수 없는 경우에만 작동한다. (불변성의 원칙이 보장되는 변수에 한해서 가능하다)
- 사용할 것 같은 case : A와 B, C의 프로퍼티가 각각 다르고, 공통 부모인 D를 가질 때 when문의 조건 분기에 is를 넣으면,타입별 객체로 캐스팅이 불필요해져 코드가 간결해질 것 같다.
-> Q&A. API들에서 리턴받은 데이터들의 집합이 필요할 때, 사용할 수도 있을 것 같다!
// Expr = 마커 인터페이스
interface Expr
class Num(val value: Int) : Expr
fun eval (e: Expr): Int {
if (e is Num) { // if문에서 타입 검사시 e를 Expr에서 Num type으로 캐스팅 해준다.
val n = e as Num // 이 코드는 생략 가능함
return n.value
}
// 여기에서 e는 다시 value로 접근이 안됨 -> if문 내의 블럭에서만 e가 cast 된다!
return e.value // Error
}
* marker interface(마커 인터페이스) : 사실상 아무 메소드도 선언하지 않은 인터페이스를 말함
2-7. when에서 많은 조건 분기를 처리해야 할 때, 분기 우선순위 팁
- 최대의 교집합의 조건 부터 먼저 처리할 것.
fun fizzBuzz(i: Int) = when {
i % 15 == 0 -> "FizzBuzz" // 표현을 어떻게 해야할지 모르겠지만, 내 기준으로는 최대의 교집합임.. 언어의 한계
i % 5 == 0 -> "Fizz"
i % 3 == 0 -> "Buzz"
}
2-8. 문자열 간의 대소 비교
"Kotlin" in "Java".."Scala"가 true로 나와서 이해가 안됐다.
이 코드를 풀어서 보면 "Java" <= "Kotlin" && "Kotlin" <= "Scala" 인데
뒤의 조건에서 각각 앞의 2자리로 잘라서 보면 "Ko" <= "Sc"이다.
여기서 직관적으로 알파벳 앞에 있는 c와 o를 비교했고 결론을 내려 false가 나와야 한다고 생각했다.
-> 비슷한 사례로 "321" <= "510"을 예시로 본다면 당연히 true가 맞다. 왜 이런 혼동이 생긴 걸까?
-> 문자열 비교에서는 각 자리수를 차례대로 비교하는데, 서로 차이가 난다면 다음 자리를 비교하지 않고 끝이 나기 때문이다.
앞으로는 헷갈리지 말자~
2-a. 새롭게 알게된 사실, 키워드
- double 표현으로 ~.~e~도 가능하다.
val price = 7.5e6 // 7.5 * 10^6과 같음! == 7500000.0 == 7_500_000.0 가독성은 제일 뒤에가 더 좋긴 한듯
Log.d("check", "price : $price") // price : 7500000.0
Log.d("check", "price's type : ${price.javaClass}") // price's type : double
- enum class : 상수 목록과 메서드 정의는 세미콜론으로 구분되기 때문에 꼭 추가해야 한다. "-> 나중에 왜 빨간줄 떠? 하지 말기~"
enum class Color(val r: Int, val g: Int, val b: Int) {
RED(255, 0, 0), ORANGE(255, 165, 0), YELLOW(255, 255, 0);
fun rgb() = (r * 256 + g) * 256 + b // 예제로 나와서 무슨 공식일까 했는데, RPG 색상 값을 24비트 정수로 변환하는 공식이였음
}
- 발생한 예외를 함수 호출 단에서 처리(catch)하지 않으면 함수 호출 스택을 거슬러 올라가면서 예외를 처리하는 부분이 나올 때까지 예외를 다시 던진다.
* star import : import 패키지명.* 이런 구문을 말함
* iteration(이터레이션) : 결과를 생성하기 위한 프로세스의 반복
TODO. LinkedHashMap, TreeMap, HashMap, Map의 정의와 각각의 사용시기(장점-특징) 구분하기
- 다음에 새로운 포스트로 작성할 예정
'Kotlin' 카테고리의 다른 글
[Kotlin in Action 4장] 정주행 (0) | 2024.03.20 |
---|---|
Kotlin Scope Functions 정리 (1) | 2024.03.11 |
[Kotlin in Action 3장] 정주행 (1) | 2024.03.01 |
shuffle()와 shuffled()의 차이점 및 배열(Array), 리스트(List) 정리 (0) | 2024.02.19 |