Kotlin-In-Action | #6. 코틀린 타입 시스템

보람·2022년 5월 10일
1

Kotlin-In-Action

목록 보기
7/12

코틀린은 널이 될 수 있는 타입을 지원해 NPE 오류를 컴파일 시점에 감지 가능

  • 널가능성NullPointerException(NPE)오류를 피할 수 있게 하는 타입 시스템의 특성
  • 요즘 언어들은.. 사용 시점이 아닌 컴파일 시점에 null에 대한 오류를 검사할 수 있도록 함
    • 즉! 컴파일 실행 시점에 오류가 발생할 수 있는 상황을 미리 감지하는 것!

어떻게 가능하쥬?🥺

이제부터 나오는 내용을 통해 프로그램 내부에서 널이 아닌 경우에만 코드를 실행할 수 있도록 하면 되쥬!!🌝

아래 타입을 사용하여 간결한 코드를 만들어 보아요💁

nullability Type? = Type or null

  • 이 값을 널을 허용할거니?
  • fun strLen(s: String) = s.length 여기서 s는 무조건 notnull 임!
  • fun strLenSafe(s: String?): Int = if (s != null) s.length else 0 여기서 s는 null이 들어와두 됨!

안전한 호출 ?.

  • foo?.bar()
    • != null -> foo.bar()
    • == null -> null
  • s?.toUpperCase() : null or s의 대문자

엘비스 연산자 ?:

-엘비스영화 검색 캡쳐..

  • 널일때 다른 값으로 바꾸고 싶다면?! 엘비스연산자를 사용하자
  • foo?:bar
    • != null -> foo
    • == null -> bar
  • 예외처리 한줄로 가능 : person.company?: throw IllegalArgumentException("No Company") --> 회사가 없으면 에러, 있으면 회사 획득

널 아님 단언 !!

  • s!!
    • != null -> s 획득
    • == null -> NPE 획득
  • person.company!!.address!!.country
    • 에러 발생시 어떤 값에서 난지 확인 불가능(한줄로 나타내는 것은 피하자)

let , null이 아닌 경우에만 함수 호출 가능

  • 어떤 값이 null이 아닐때 수행해야 하는 로직이 있다면 유용함
  • 플러그인 작업시 유용하게 사용했다.
fileToCopy?.let {   
	it.setBinaryContent(DefaultEnvExample.laravelEnv.toByteArray(Charsets.UTF_8))
    it.refresh(false, false)
}
// 스위칭할 env 파일이 있다면 복사하고 파일 리로딩 처리 해줘~

as?

  • 값을 다른 타입으로 변환하는 것과 변환이 불가능한 경우를 한꺼번에 처리 가능
  • o as? Person
val p1 = Person("Dmitry", "Jemerov")
println(p1.equals(42))

//equals 함수에서..
println("${o as? Person}") // o as? Person : null
val otherPerson = o as? Person ?: return false 
//요런 식이 가능!! 변환할 수 없다면 null이 나오므로 ?: 사용해서 false 반환 가능!
  • 타입이 서로 일치하지 않다면 null

플랫폼 타입, 자바 Type = 코틀린의 Type? or Type

  • 널 관련 정보를 알 수 없는 타입을 플랫폼 타입이라고 한다.
    • 자바 @Nullable -> Type? / @NotNull -> Type | @이 없으면 자바 타입은 코틀린의 플랫폼 타입이 됨
  • 널이 될수도 있고 널이 되지 않을 수도 있으나 모든 연산의 책임은 개발자에게 있음🥺
  • 플랫폼 타입이 왜 도입된거쥬? notnull인 값에 대해서까지 불필요한 null 검사를 하지 않기 위함(비용 감소)

Int, 컴파일은 원시타입(int)으루

(원시타입, 래퍼타입, 박싱에 대해 궁금하다면 위 파란색 원시타입 링크 클릭)

  • 코틀린은 원시 타입과 래퍼 타입을 구분하지 않고 한 타입으로 사용하나 컴파일은 원시타입으로 된다.
  • val list: List<Int> = listOf(1,2,3)
    • 원시 타입과 래퍼 타입을 구분하여 사용하는 자바와 달리 래퍼 타입을 따로 구분하지 않기 때문에 편리
  • Int 는 null을 허용하지 않기 때문에 자바 원시 타입으로 쉽게 컴파일 가능

그렇다면 null 허용되는..

Int? 은 자바의 Integer와 대응

  • null을 허용하는 Int?는 자바의 원시타입으로 표현 X
  • 자바의 래퍼 타입과 컴파일 된다.

조상 타입 Any

  • Any는 자바의 Object에 해당
  • Any는 notnull, Any? 는 nullable
  • 4장의 toString, hashCode, equals는 Any에 정의된 메서드를 상속한 것

Void와 비슷한 Unit

  • fun f(): Unit{} : 반환 타입이 없어용
  • Unit은 모든 기능을 갖는 일반적인 타입이며, void와 달리 Unit을 타입인자로 사용 가능

정상적으로 끝나지 않을때는 Nothing

  • PHP 8버전의 Never와 비슷한 느낌(이라구 팀원분들이 말해주셨다)
fun fail(message: String): Nothing {
    throw IllegalStateException(message)
}
  • 아무런 값을 반환하지 않고 에러만 내뿜고 실패처리한다.

MutableCollection vs Collection

  • 코틀린의 컬렉션은 읽기 전용 컬렉션(Collection)과 변경 가능 컬렉션(MutableCollection)을 구별하여 제공
  • Collection : size, iterator(), contains()
    • MutableCollection : 위 3개 받고 add(), remove(), clear() ==> 수정 가능!!!
  • 수정 가능한 MutableCollection 을 인자로 받은 함수에서는 원본의 변경을 막기 위해 컬렉션을 복사해 야 할 수도 있음(방어적복사)

자바와 코틀린 호환시에 Null&변경가능 여부를 잘 판단할 것!

  • val list = MutableCollection<Int?>? : 원소에 null 허용하면서 컬렉션 자체가 null 가능
    • 컬렉션은 val로 선언해도 그 내부 값은 변경 가능

배열 Array, IntArray

  • val letters = Array<String>(26) {i->('a'+i).toString()}
    • 일반 제네릭 클래스처럼 보이는 Array는 자바 배열로 컴파일됨
  • 각 원시 타입마다 배열을 표현하는 별도 클래스 제공 - ByteArray, CharArray, BooleanArray 등
val squares = IntArray(5) {it+1} //IntArray : int 원시 타입의 배열만을 표현
println(squares.joinToString()) //1, 2, 3, 4, 5

아래부터는 더 알아보기..

원시타입? 래퍼타입? 박싱? 언박싱?0?

쉽게 말하면 래퍼타입은 원시타입을 객체화 한 것이다!

  • int num =1;1,2,3 같이 딱딱 떨어지는 값들을 표현할 수 있는 값이 원시타입이라고 한다면
    • 원시타입은 null 선언 불가능
  • Integer wNum = new Integer(num); 처럼 원시 타입을 객체화한 것이 래퍼 타입이다!
    • 래퍼 타입은 함수를 호출해도 되고 null로 선언하는 것도 가능하다.
  • 박싱이란 원시타입->래퍼타입으로 변환하는 것, 언박싱이란 래퍼타입->원시타입으로 변환하는 것을 의미

그래서 코틀린의 null허용되지 않는 Int는 원시타입으로 컴파일 되고 null이 허용되는 Int?는 래퍼타입으로 컴파일 된다는게 이 의미이다!!🌝

int num = 1; //null허용X 원시타입
Integer wNum = new Integer(num); 
// int Boxing 동작 -> int boxing (원시타입에서 래퍼타입)
Integer wNum2 = new Integer(null); 
// null 을 담을 수 있는 래퍼 타입 -> 사용하려면 null체크나 다른 값을 넣긴 해야 하나 null로 선언은 가능
profile
백엔드 개발자

0개의 댓글