Kotlin in Action 6장

존스노우·2023년 3월 23일
0

코틀린

목록 보기
6/10

코틀린 타입시스템

널 가능성

  • NPE를 피할 수 있게 돕는 특성

  • Null에 대한 접근 방법을 실행시점 -> 컴파일러 시점으로 옮김 (코틀린)

  • 미리 감지해서 예외를 줄인다!

    널이 될 수 있는 타입

  • 널 되는 타입 명시적 지원?

  • 프로퍼티나 변수에 null을 허용하는 방법?

  • 코틀린에선 함수작성시 함수가 널을 허용하나?

  • 실행 시점에 Null 되는 모든 경우 포함

  • 타입 뒤에 ? 붙여줌으로서 Null 참조 가능

  • 그러나 널이 가능한 타입 변수 있으면 연산이 제한됨.

  • fun strLenSafe (s: String?) = s.length ()
  • 널이 될수있는 값은 ! 널이될수없는 값타입 변수에 대입 금지!

    그럼 왜사용하지?

  • 필요한 널(null) 참조 문제를 최소화할 수 있도록 설계함

  • 널을 명시적으로 표현! 널 관련 문제 방지 안정성

  • 계속해서 Null을 다루는 도구를 살펴보자

    타입의 의미

  • 타입 ? 분류로 어떤 값이 가능한지와 수행할 연산종류를 결정한다 (위키피디아)

  • 코틀린은 널이 될 수 있는 타입에 종합적인 해법 제공

  • 널이 되거나 될수없는 타입을 구분하면서 어떤 연산을 해야될지 명확해 지고/

  • 실행시점에 예외를 발생시킬 수 있는 연산을 판단함.

    안전한 호출연산자 : ?.

  • foo?.bal() null이 아니면 실행 널이면 호출 안함!

  • Null을 반환함

  • 책에서는 서보니 코드가 좀 지저분하다 더 간결한 건?

    엘비스 연산자: ?:

  • null대신 사용할 디폴트 값을 지정해 주자.

  • val t: String = s? : "hello world!"

  • foo?: bar foo / bar NotNull/null

    fun main() {
      val nullableString: String? = null
      val nonNullableString: String? = "Hello, Kotlin!"
    
      // 엘비스 연산자를 사용해 nullableString이 null일 경우 기본값인 "Default String"을 사용합니다.
      val result1: String = nullableString ?: "Default String"
      println(result1) // 출력: Default String
    
      // 엘비스 연산자를 사용해 nonNullableString이 null이 아니므로 그 값을 사용합니다.
      val result2: String = nonNullableString ?: "Default String"
      println(result2) // 출력: Hello, Kotlin!
    } ```

안전한 캐스트 : as?

  • 안전한 타입 변환을 수행하는 데 사용

    fun main() {
       val anyObject: Any = "Hello, Kotlin!"
    
       // 안전한 타입 변환을 시도합니다. 문자열을 Int로 변환할 수 없으므로, null을 반환합니다.
       val intValue: Int? = anyObject as? Int
       println(intValue) // 출력: null
    
       // 안전한 타입 변환을 시도합니다. 문자열을 String으로 변환할 수 있으므로, 변환된 값을 반환합니다.
       val stringValue: String? = anyObject as? String
       println(stringValue) // 출력: Hello, Kotlin!
    }

단언 !!

  • 이건 무조건 널이 아니다!

Let

  • t : String? -> t.let{} null아닐시 실행
  • 그러나 중첩문이 많을경우 그냥 If쓰는게..

나중에 초기화할 프로퍼티

  • 널이 될 수 없는 프로퍼티인대 생성자 안에서 널이 아닌값으로 초기화할 방법

  • Ex) @Before

  • 코틀린은 일반적으로 생성자 안에서 초기화 해야된다.

  • 코틀린에서 클래스 안의 프로퍼티를 선언할 때, 해당 프로퍼티가 null이 될 수 없 는 타입이라면 해당 프로퍼티는 반드시 생성자에서 초기화해야 함.

  • lateinit 키워드를 사용함 이는 클래스의 인스턴스를 생성할 때 프로퍼티를 초기화하지 않고, 나중에 특정 시점에 초기화할 수 있도록 해줌 의존성 주입이나 유니테스트 할때 주로 사용

    나중에 초기화하는 프로퍼티는 항상 var! 나중에 바껴야되기때문.

  • 이런식으로 설명을 함...

널이 될수 있는 타입 확장

  • 확장함수로 정의하면 Null 값 다루는 강력한 도구로 활용가능?

  • inNullOrBlank , isNullOrBlank

  • isNullOrBlank() 함수는 널이 될 수 있는 수신 객체 타입에 대해 선언된 확장 함수

  • isNul10rBlank는널을 명시적으로 검사해서널인 경우 true를반환

  • 널이아닌 경우isBlank 를호출한다

    fun verifyUserInput(input: String?) {
      if (input.isNullOrBlank()) {
          println("Please fill in the required fields")
      }
    }
    
    // 사용 예시
    verifyUserInput(" ") // 출력 결과: Please fill in the required fields
    verifyUserInput(null) // 출력 결과: Please fill in the required fields
  • 안전한 호출? 코틀린에서 Null 들어오면 예외를 발생시키지 않고 Null반환

  • 결국 말하고자하는건 ?

  • Nullable Type은 확장함수 만들때 null인경우 대비해 코드 작성해줘야 됨.

  • 안전한 호출 제공해서 Nullbalbe 변수 객체 다룰때 Null체크 하지않아도 코드 간단해 짐. 그리고 확장함수도 Nullable 타입 안전하게 호출

  • 가급적이면 쓰지말자 실수도 높아지고 가독성도 높아짐

  • 예시로 isNullOrBlank 함수를 사용

    타입 파라미터 널 가능성 ..

  • 코틀린은 함수나 클래스에 모든 파라미터 타입은 Null이 될수 있따.

  • 그래서 클래스나 함수 안에 타입이름으로 사용된 파라미터는 끝에 없더라도 Null이 될수 있따.

  • 그래서 상한선을 지정해 Null이 될수 없다고 지정해야된다.

  • 이러므로 Null이 될 수있는 값 거부.

    fun <T> printHashCode(t: T) {
    println(t?.hashCode())
    }
    
    printHashCode(null) // "null"
    printHashCode("hello") // some hash code value
    
    
      fun <T: Any> printHashCode (t: T) {
        println(t.hashCode())
    }
    
    // Error: Type parameter bound for 'T' is not satisfied
    // printHashCode(null)
    
    printHashCode(42)
  • 이런식으로 지정해 준다.

    널 가능성과 자바.

  • 자바에서 가져온 타입에 대해 널 관련 이슈를 다루는 내용

  • 코틀린은 플랫폼 타입을 도입해 자바에서 가져온 코드를 널 검사를 해줌

  • 그래서 자바코드를 사용할때 Null 사용 안해도됨.

    상속

  • 컴파일러는 자바에서 널이 될수없는 파라미터에대해

  • 널이 될가능성이있는지 없는지 다코드를 작성해서 알려줌.

    코틀린의 원시타입?

  • 코틀린은 원시타입과 래퍼타입 구분X

    원시타입 Int Boolean

  • 코틀린은 원시타입과 래퍼타입을 구분하지 않고 항상 같은 타입사용

  • 컬렉션에 원시타입을 저장하는 대신 래퍼 타입으로 변환해서 저장함

  • 원시타잆는 변수에 직접 저장하는것이 더 효율적이기 때문.

  • 자바는 Int컬렉션을 사용하려면 Collection사용해야 된다 함.

  • 원시타입 = 참조 타입? 코틀린은 어떤 걸 선택할까

  • 실행 시점 타입에대해 가장 효율 적인 방식을 표현함. int는 자바 Int로

  • 항상 객체로 표현하지않는다.

    null이 될수 있는 원시타입

  • 코틀린은 여러가지 리터럴 숫자타입 표현 가능함.

  • 명시적으로 형변환 해줘야 사이드 이펙트 예방

  • 코틀린은 자동타입 변환을 못해주기때문에 .toLong같은걸써줘야됨

  • 재네릭 클래스는 래퍼 클래스사용

  • jvm에서 원시타입을 허용하지 않기 때문

  • 코틀린은개발자의혼란을피하기위해타입변환을명시

    Any 최상위 타입

  • int 등 모든 타입에 조상임

  • any 널 안됨 / any? 널 가능 .

    Unit타입

    interface Processor<T> {
        fun process(): T
    }
    
    class NoResultProcessor : Processor<Unit> {
        override fun process() {
            // 업무 처리 코드
        }
    }
    
  • 자바 void 와 같은 기능

  • 자바 void와 달리 타입 인자로 쓸수 있으며

  • 위 코드에서 딱히 Return을 해주지 않아도됨 . 묵시적 Unit 반환

    Nothing

  • Nothing은 반환값이 없는 함수에서 예외를 처리할 때 유용하게 사용됨.

  • 반환값이 없는 함수의 반환타입에 사용 됨.

    fun fail(message: String): Nothing {
       throw IllegalStateException(message)
    }
    // 반환값을 Null로 간주하지않아 에러
    val result: Nothing = fail("error occurred") // compile error
    
    val address = company.address ?: fail("No address")
    println(address.city)
    
  • 엘비스연산자와 사용시 유용. Null일 경우 Fail호출

    널 가능성과 컬렉션

  • List<Int?> vs List?

  • 부분 널과 전체 널 차이

    읽기 전용과 변경 가능한 컬렉션

  • 변경 가능 컬렉션을 인자로 받으면?

  • 원본의 변경을 막기위해 컬렉션 복사 할 수 있다(방어적 복사)

  • 그냥 컬렉션은 변경가능 컬렉션에 복사 못함 타입불 일치 .

  • 읽기 전용이라도 항상 스레드에 안전하지는 않다.

  • 변경 가능 불가능한 컬렉션이 같은 객체를 가르키고 변경 이 일어나는 상황도 생김.

코틀린 컬렉션과 자바

  • 자바 컬렉션 기본 구조를 그대로 옮기고 추가로 읽기전용 컬렉션을 확장함

  • 컬렉션 타입에 대한 처리 방식이 다르기 때문에 호환성 문제가 발생

  • 코틀린에선 변경불가능인대 자바에선 변경이가능하게 됨..

  • 그래서 자바코드로 넘길때 자바쪽에서 신경써서 작업해줘야됨.

    컬렉션을플랫폼타입으로다루기

  • 코틀린과 자바는 상호 운용성을위해 플랫폼 타입을 사용함

  • 플랫폼 타입은 널가능성이나 가변성에 대한 정보가 없음.

  • 코틀린에선 플랫폼타입을 널이 될수있는 타입이나 될수 없는타입으로 사용

  • 자바에서는 선언한 컬렉션 타입변수를 코틀린에서 사용하려면?

  1. 컬렉션이 널이 될 수있는가
  2. 컬렉션의 원소가 널이 될 수 있는가
  3. 오버라이드하는 메소드가 컬렉션이 변경가능한가.
  • 각 상황에 맞게 적절한 코틀린 타입 선택 사용해야 함.
  • 이를 위해 자바 인터페이스나 클래스가 어떤 맥락에 사용되는지 정확히 알아야함!

    플랫폼 타입이란?

  • 자바와 상호 운용성을 위해 도입된 개념
  • 자바 코드에서 정의된 타입은 코틀린에서 플랫폼 타입으로 간주

    특징

  • 널 가능성 정보가 없음 -> 플랫폼 타입 변수는 코틀린에서 널 가능성 정보 없음
    그래서 코틀린에선 해당 타입이 널이 되거나 될수없는 타입 어느쪽으로 사용가능
  • 컬렉션 타입 정보가 부족함
    -> 자바에서 선언한 컬렉션 타입 변수도 코틀린에선 플랫폼 타입으로 간주
    플랫폼 타입 컬렉션은 기본적으로 변경 가능성 정보가 부족.
    그래서 읽기전용 컬렉션 변경가능한 컬렉션 어느쪽으로도 다룰 수 있음

    주의 상항

  • 코틀린에서 널 안전성 변경 가능성 정보가 부족하니
  • 해당 변수를 사용시 올바른 타입 선택해야됨, 자바 코드의 의도 사용방식 이해 필수
  • 결론적으로 자바코드를 보면서 알맞은 타입을 선언해 사용해야 함.
profile
어제의 나보다 한걸음 더

0개의 댓글