본문 바로가기

Kotlin

AtomicKotlin _ 4(30 ~ 41) 사용성

확장함수

  1. 확장함수(extension function)는 기존 클래스에 멤버 함수를 추가하는 것과 같은 효과

  2. 확장할 대상타입은 수신 객체 타입이라고 함 (receiver type)

  3. fun 수신타입.확장함수() {..} : ex) fun String.singleQuote() = “’$this’”

이름 붙은 인자와 디폴트 인자

  1. 이름 붙은 인자를 사용하면 코드 가독성이 좋아진다.

  2. 모든 인자의 의미가 명확하다

  3. 디폴트 인자와 결합하면 더 유용하다.

  4. 객체 인스턴스를 디폴트 인자로 전달하는 경우 호출할 때 마다 같은 인스턴스가 반복해서 전달된다.

  5. 디폴트 인자로 함수 호출이나 생성자 호출등을 사용하는 경우 호출할 때 마다 새 인스턴스가 생긴다.

오버로딩

  1. 함수의 시그니처: 함수 이름, 파라미터 목록, 반환 타입

  2. 함수를 오버로딩할 때는 함수 파라미터 리스트를 서로 다르게 해야함

  3. 함수의 반환 타입은 오버로딩의 대상이 아님 : 오버로딩하고 싶은 함수는 파라미터를 서로 다르게 만들어야 

  4. ‘같은 주제를 다르게 변경한다’ 라는 개념을 더 명확하게 표현 가능

when 식

  1. 두 세가지 이상의 선택지가 있는 경우 when식을 사용하면 좋음

  2. if식 보다 when식이 훨씬 좋다

  3. when이 더 유연하기 때문에 선택의 여지가 있다면 when을 사용하는 것을 권장함

  4. 인자를 취하지 않을 수도 있음. 인자가 없으면 화살표 왼쪽 식에 항상 Boolean type의 식을 넣어야 함

이넘

  1. 이름을 관리하는 편리한 방법
  2. 한 enum안에서 맨 처음 정의된 상수에 0이라는 ordinal값이 지정됨. 이후에는 순서대로 1씩 증가된 ordinal 값이 부여됨

  3. 이넘은 인스턴스 개수가 미리 정해져 있고 클래스 본문 안에 이 모든 인스턴스가 나열되어 있는 종류의 클래스

  4. 코드 가독성을 높여주므로 항상 사용하는 게 바람직함

 

데이터 클래스

  1. data 클래스의 모든 생성자 파라미터는 var나 val로 선언해야 한다.

  2. data 클래스에서는 equals()가 자동으로 생성, 파라미터에 열거된 모든 프로퍼티가 같은 지 검사한다.
class Person(val name: String)

data class Contact(val name: String, val number: String)

fun main() {
		// 아래 둘은 같아 보이지만 인스턴스가 다르다.
		Person("Cleo")
		Person("Cleo")
		// 데이터 클래스는 같다
		Contact("Cleo", "010-1234-1234")
		Contact("Cleo", "010-1234-1234")
}

  3. 객체를 HashMap이나 HashSet에 넣을 때 키로 사용할 수 있는 해시 함수를 자동으로 생성

 

널이 될 수 있는 타입

  1. 무언가 null 결과를 내놓을 수 있다면, 타입 이름 뒤에 물음표(?)를 붙여서 결과가 null이 될 수도 있음을 표시해야 한다.

  2. 널이 될 수 있는 타입의 식별자를 널이 될 수 없는 타입의 식별자에 대입할 수는 없다.

  3. String 과 String? 은 다른 타입이다.

  4. 자바에서는 멤버 함수의 수신 객체가 null 이면 예외를 발생시키면서 실패한다(NPE)

  5. 코틀린에서는 null이 될 수 있는 타입을 단순히 역참조(dereference)한다.

  6. 객체에 접근하기 위해서는 메모리에서 객체를 가져와야 한다.

  7. 널이 될 수 있는 타입을 역참조 해도 NPE가 발생하지 않도록 보장하는 가장 단순한 방법은 명시적으로 참조가 null인지 검사하는 것

안전한 호출 & 엘비스 연산

  1. 안전한 호출은 일반 호출에 사용하는 점(.)을 물음표와 점(?.)으로 바꾼 것
fun main(){
	val s: String? = null
	//s.length 는 컴파일 되지 않음
	//s?.length : 안전한 호출이므로 가능
}

  2. 안전한 호출은 수신 객체가 null이 아닐 때만 연산을 수행

 

  3. ?.의 결과로 null 이상의 일이 필요할 때 엘비스연산자 사용

 

  4. 왼쪽 식이 null인 경우, ?:의 오른쪽 식의 값이 전체 결괏값이 된다.

 

  5. s.length의 값이 null인 경우 결과값은 0이 된다 : s?.length ?: 0

 

널 아님 단언

  1. null이 될 수 없다고 주장하기 위해 느낌표 두개(!!)를 쓴다.

  2. 이를 널 아님 단언이라고 한다.

  3. x!!의 뜻 : x가 null일 수도 있다는 사실을 무시하셈. 무조건 null 아님

  4. x!!는 null이 아니면 x, null이면 오류를 발생

  5. 널 아님 단언을 사용하지 않고 안전한 호출이나 명시적인 null 검사를 활용하는 쪽을 권장

제네릭스

  1. 제네릭 타입을 정의하려면 클래스 이름 뒤에, 부등호(<>) 를 추가한다. ex)class GenericHolder<T>(){}

  2. T라는 플레이스홀더는 지금은 알 수 없는 어떤 타입을 대신한다, 제네릭 클래스 안에서는 일반 타입으로 쓰임

  3. T 대신에 유니버셜 타입(universal type) : 모든 타입의 부모 타입으로 대체할 수 있지 않을까?

  4. 간단한 경우에는 가능하다

  5. 하지만 객체를 Any 타입으로 대입하면 객체 타입을 추적할 수 없기 때문에 제대로 작동하지 않는다.

  6. 제네릭 함수를 정의하려면 부등호로 둘러싼 제네릭 타입 파라미터를 함수 이름 앞에 붙인다.