리터럴
변수에 할당되거나 표현식에서 사용되는 고정된 값
매직 리터럴(넘버)을 사용하면 해당 숫자가 어떤 의미인지 바로 파악이 어렵습니다. 따라서 이를 지양하고 상수를 사용해서 직관성을 높이는 것이 좋습니다. 위의 코드는 제가 작업하고 있는 프로젝트에서 counter 변수에 사용되고 있던 매직 넘버를 상수로 리팩토링한 예시입니다.
val, var
변수를 선언할 때 value를 재할당할 수 있는 경우 var을 사용하고, 그렇지 않을 경우 val을 사용합니다.
time은 var로 선언된 변수입니다. "val로 선언한 변수는 value 재할당이 안 되지 않나? time은 가변적이어서 hour 값이 계속 바뀌니까 hour, minute, second는 var로 선언돼야하는 거 아닌가?"라는 생각이 들면서 헷갈릴 수 있는데 이는 값이 아닌 식의 결과를 담는 것이므로 문제가 되지 않습니다.
* val 키워드로 선언된 변수의 내용은 변경될 수 있지만 변수의 값 자체는 변경될 수 없습니다. 가령 val list = mutableListOf(1, 2, 3) 처럼 선언된 경우에는 list 변수가 가리키는 MutableList 객체 내용을 변경할 수 있지만, list 변수에 새로운 MutableList 객체를 할당할 수는 없습니다.
포매팅(Formatting)
특수한 편집기호를 사용하여 객체를 처리하는 방식
val string = "문자열"
println("string = %10s".format(string))
// string = 문자열
// *s는 문자열을 처리하는 형식문자
val float = 1234.5
println("float = %6.2f".format(float))
// float = 1234.50
// *f는 실수를 처리하는 형식문자이며 %6.2f는 전체 실수는 6자리이고 그중에 소수점 이하는 2자리라는 것을 나타냅니다
입력받은 인자를 포함해 '%'뒤로 length가 10이 되게 포매팅합니다. 위의 예시는 입력받은 string의 length가 3이므로 좌측에 공백을 7만큼 추가한 것입니다. 아래는 제가 작업하고 있는 프로젝트에 포매팅을 활용해본 예시입니다.
timer 기능을 구현해서 화면에 시/분/초를 보여줘야 했는데 timer가 한 자릿수여도 10의 자리를 0으로 표현해야 했습니다. 마땅한 방법이 안 떠올라서 하드코딩을 했습니다. if문 조건에 사용된 10이라는 숫자가 매직넘버로 적혀있어 다른 사람이 보기에 의도가 모호하고 전반적으로 코드가 깔끔하지 않습니다. 아래는 포매팅을 활용하여 간결하게 리팩토링을 한 것입니다.
빈공간이 있을 경우 '0'으로 대체되게 해주었습니다. 특수문자로도 대체할 수 있습니다.
*0이 아닌 다른 숫자로 대체하고싶을 경우 String.format("%02d", hour).replace('0', '1')와 같이 replace를 활용해주면 됩니다.
상수
- 패키지나 object 예약어를 사용하는 곳에서만 정의할 수 있습니다.
- 상수는 const val 예약어를 사용합니다.
- 상수(const val)는 변수와 구별하기 위해 상수 이름을 모두 대문자로 씁니다. 단어를 연결해 쓸 때는 스네이크 표기법도 같이 사용합니다.
val, const val 차이
val은 런타임 시점에 값을 할당하지만 const val은 컴파일 시점에 값을 할당합니다.
따라서 const val은 프로그램의 실행이 시작되기 전 값을 미리 알고 있어야 하기 때문에 문자열이나 기본 자료형 타입으로만 선언될 수 있고 최상위 수준 또는 object의 멤버로 선언되어야 합니다. class의 property나 지역 변수로 사용이 불가합니다. 실행 중에 값을 계산할 필요가 없으므로 앱 실행 시간을 단축시키고 성능 향상을 가져올 수 있습니다.
object, companion object 차이
object과 companion object 모두 싱글톤 패턴을 구현하는데 사용되지만 몇가지 차이점을 가집니다.
먼저 object는 클래스 전체가 하나의 싱글톤 객체로 선언되지만, companion object는 클래스 내에 일부분이 싱글톤 객체로 선언되는 것입니다. 또한 둘은 초기화 시점이 다릅니다. object로 선언된 클래스는 해당 클래스가 사용될 때 초기화가 되지만, companion object는 해당 클래스가 속한 클래스가 load될 때 초기화가 이루어집니다.
연산자 오버로딩
+, - 등과 같은 연산자가 상황에 따라 다르게 동작할 수 있도록 커스터마이징하는 것
코틀린에서는 연산자를 표기하면 내부에서 해당하는 메서드로 변환해 처리합니다. operator 키워드를 사용하여 내부에서 전환되는 메서드를 새롭게 정의할 수 있고 이를 통해 연산자 오버로딩을 구현할 수 있습니다.
data class Person(val height: Int) {
operator fun plus(tmp: Person): Person {
return Person(height + tmp.height)
}
}
val a: Person = Person(height = 170)
val b: Person = Person(height = 180)
println("result: ${a + b}")
// result: 350
*참고 https://sabarada.tistory.com/174
Immutable 객체
Kotlin의 기본 숫자 타입(Int, Long, Float, Double, Short, Byte 등) Immutable 객체는 연산자를 수행하면 새로운 객체가 생성됩니다. String의 경우 StringBuilder를 활용하면 되지만 숫자는 객체를 새로 생성하지 않고 숫자의 값을 변경하려면 inplace 메서드(+=,-= 등), 증감연산자(++,--)를 사용해야 합니다.
getter, setter
코틀린에서는 지역변수를 제외하고 모두 속성입니다. 왜냐하면 실제 변수를 정의하면 getter와 setter(변수를 참조하는 메서드)를 내부적으로 제공하기 때문에 변수 이름으로 참조하면 메서드가 실행됩니다.
backing property
class Example {
private var _data: String = "initial value"
var data: String
get() = _data
set(value) {
_data = "Modified: $value"
}
}
프로퍼티를 외부에서 직접 접근하지 못하도록 하기 위해, 백킹 프로퍼티를 private으로 선언하여 접근 제어를 할 수 있습니다. 이렇게 하면 클래스 외부에서는 직접 프로퍼티에 접근하지 못하고, 커스텀 접근자를 통해 접근하게 됩니다. 변수의 이름은 언더스코어(_)로 시작합니다.
메모리 구조에서 클래스의 메서드가 저장되는 곳
객체의 데이터(프로퍼티)는 힙에 저장되고, 객체의 동작(메서드)는 코드 영역에 저장됩니다. 이렇게 함으로써 객체를 생성할 때마다 메서드를 복제하는 비효율성을 피하고, 클래스의 메서드를 공유하여 메모리 사용을 최적화할 수 있습니다. 점연산자로 클래스에 있는 메서드를 참조해서 사용합니다.
*참고 https://inpa.tistory.com/entry/JAVA-%E2%98%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD-%EC%8B%AC%ED%99%94%ED%8E%B8
ETC
- 이스케이프된 문자열 은 큰따옴표(" ") 안에 선언되며 '\n', '\t', '\b' 등과 같은 이스케이프 문자를 포함할 수 있습니다.
- 원시 문자열 은 삼중 따옴표(""" """) 안에 선언되며 이스케이프 문자 없이 여러 줄의 텍스트를 포함할 수 있습니다.
- 이진연산은 연산자를 제공하지 않고 메서드로만 처리합니다.
- 이진연산을 처리하고 문자열로 2진수, 16진수를 출력하려면 toString(2), toString(16)를 사용합니다
- 보통 표준 입력은 readLine 함수를 실행할 때 반드시 값이 들어오므로 !!를 사용해서 null이 아닌 것을 표현합니다.
'Kotlin > 스터디' 카테고리의 다른 글
코틀린 스터티 - 8장 (0) | 2023.09.03 |
---|---|
코틀린 스터디 - 6장 (0) | 2023.08.20 |
코틀린 스터디 - 5장 (0) | 2023.08.13 |
코틀린 스터디 - 4장 (0) | 2023.08.06 |
코틀린 스터디 3장 (0) | 2023.07.30 |