코틀린은 자바와 다르게 Collection을 2종류 타입으로 나눠서 구분 - Immutable / Mutable
- Immutable (불변)
: Read-Only '읽기전용'의 Collection
한번 정의되면 수정이 불가 - (add() / put() / remove() 등) 추가, 삭제 불가
단순하게 추출하는 용도로 사용
: 생성 함수 (function)
listOf, setOf, mapOf - Mutable (가변)
: Write+Read '읽기/쓰기'의 Collection으로 add / put / remove 등이 가능
: 생성 함수 (function)
mutableListOf, mutableSetOf, mutableMapOf
arrayListOf
hashSetOf, sortedSetOf, linkedSetOf
hashMapOf, linkedMapOf, sortedMapOf
불변성이 가져오는 장점은 아래와 같습니다. (immutable 컬렉션이 필요한 이유)
- 스레드 안전성(Thread-safe)
- 낮은 커플링(Loosely-coupling)
- 참조 투명성(Reference transparency)
- 컴파일러 최적화
- 순수 함수
lateinit vs lazy
둘은 비슷해보이지만 많은 차이점이 있습니다.
- lazy는 val 프로퍼티에만 사용할 수 있지만, lateinit은 var에만 사용할 수 있습니다
- 그렇기 때문에 lateinit은 immutable(불변) 프로퍼티가 아닙니다.
- lateinit은 nullable 또는 primitive type의 프로퍼티를 사용할 수 없습니다. 반면에 lazy는 모두 가능합니다.
- lateinit은 직접적으로 프로퍼티를 갖고 있는 구조지만(자바에서 field를 갖고 있음), lazy는 Lazy라는 객체 안에 우리가 선언한 field를 갖고 있습니다. 그래서 lazy의 프로퍼티를 직접 변경할 수 없습니다
inline 함수의 장단점
장점:
인라인 함수를 사용한다면 람다식을 사용했을 때 무의미한 객체 생성을 막을 수 있습니다.
제네릭을 사용할 때 인라인(inline) 함수와 reified 키워드를 함께 사용하면 T type에 대해서 런타임에 접근할 수 있게 해줍니다. 따라서 타입을 유지하기 위해서 Class<T>와 같은 추가 파라미터를 넘길 필요가 없어집니다.
단점
public inline 함수는 private 함수를 호출할 수 없음
inline fun doSomething() {
doItPrivately() // Error
}
private fun doItPrivately() { }
가비지 컬렉터
지정하지 않으면 Java 7 부터 G1 GC가 default GC
코틀린의 타입 시스템은 코드가 런타임에서 NullPointerException을 제거하는 것을 목표로 하고 있습니다. 기본적으로 NullPointerException(이하 NPE)가 일어날 수 있는 상황에서는 컴파일이 되지 않습니다. 그럼에도 NPE가 발생할 수 있으며 그 상황은 아래에 한정되어집니다.
- throw NullPointerException() 으로 코드에서 명시적으로 예외 던짐
- !! 키워드를 사용했을 때 null 이 들어갔을 경우
- 객체 초기화 시 아래의 이유로 데이터의 불일치의 경우
- 생성자에서 this를 초기화하지 않고도 사용할 수 있으며, 다른 곳으로 전달되어 사용할 수 경우(“leaking this”)
- 부모 클래스 생성자와 자식 클래스의 구현에서 초기화되지 않은 상태를 사용하는 open member를 호출 했을 경우
- Java와의 상호 작용
- java의 null 참조중인 객체에 접근 (kotlin은 java와 100% 상호 운용 가능)
- java와 상호작용하는 collection 등의 제네릭 타입의 이유로 잘못된 null이 들어올 수 있습니다. java code에서 list에 null 이 들어오고 이를 코틀린에서 null인지 인지하지 못한채 사용하는 것입니다.
- java와 병행하여 코드운영하며 발생할 수 있는 기타 예외가 있음
Null 체크 방법
조건문으로 체크하기 (if)
안전한 호출(safe call) (?.) -> 이렇게 하면 null 일 경우 null을 반환하며 그렇지 않을경우 정상적으로 값을 반환합니다.
추가적으로 Scope Functions 중 let을 사용하면 값이 null 이 아닐경우에만 실행하도록 할 수 있습니다.
val name = outterEntity?.innerEntity?.name
println("name = $name") // 결과 : name = sabarada
엘비스 연산자(Elvis operator) (?:) -> 엘비스 연산자 값에는 literal value 뿐만 아니라 return, function 그리고 exception 호출까지 가능합니다.
The !! operator
스코프 Function