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!
} ```
안전한 타입 변환을 수행하는 데 사용
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!
}
널이 될 수 없는 프로퍼티인대 생성자 안에서 널이 아닌값으로 초기화할 방법
Ex) @Before
코틀린은 일반적으로 생성자 안에서 초기화 해야된다.
코틀린에서 클래스 안의 프로퍼티를 선언할 때, 해당 프로퍼티가 null이 될 수 없 는 타입이라면 해당 프로퍼티는 반드시 생성자에서 초기화해야 함.
lateinit 키워드를 사용함 이는 클래스의 인스턴스를 생성할 때 프로퍼티를 초기화하지 않고, 나중에 특정 시점에 초기화할 수 있도록 해줌 의존성 주입이나 유니테스트 할때 주로 사용
이런식으로 설명을 함...
확장함수로 정의하면 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컬렉션을 사용하려면 Collection사용해야 된다 함.
원시타입 = 참조 타입? 코틀린은 어떤 걸 선택할까
실행 시점 타입에대해 가장 효율 적인 방식을 표현함. int는 자바 Int로
항상 객체로 표현하지않는다.
코틀린은 여러가지 리터럴 숫자타입 표현 가능함.
명시적으로 형변환 해줘야 사이드 이펙트 예방
코틀린은 자동타입 변환을 못해주기때문에 .toLong같은걸써줘야됨
재네릭 클래스는 래퍼 클래스사용
jvm에서 원시타입을 허용하지 않기 때문
코틀린은개발자의혼란을피하기위해타입변환을명시
int 등 모든 타입에 조상임
any 널 안됨 / any? 널 가능 .
interface Processor<T> {
fun process(): T
}
class NoResultProcessor : Processor<Unit> {
override fun process() {
// 업무 처리 코드
}
}
자바 void 와 같은 기능
자바 void와 달리 타입 인자로 쓸수 있으며
위 코드에서 딱히 Return을 해주지 않아도됨 . 묵시적 Unit 반환
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?
부분 널과 전체 널 차이
변경 가능 컬렉션을 인자로 받으면?
원본의 변경을 막기위해 컬렉션 복사 할 수 있다(방어적 복사)
그냥 컬렉션은 변경가능 컬렉션에 복사 못함 타입불 일치 .
읽기 전용이라도 항상 스레드에 안전하지는 않다.
변경 가능 불가능한 컬렉션이 같은 객체를 가르키고 변경 이 일어나는 상황도 생김.
자바 컬렉션 기본 구조를 그대로 옮기고 추가로 읽기전용 컬렉션을 확장함
컬렉션 타입에 대한 처리 방식이 다르기 때문에 호환성 문제가 발생
코틀린에선 변경불가능인대 자바에선 변경이가능하게 됨..
그래서 자바코드로 넘길때 자바쪽에서 신경써서 작업해줘야됨.
코틀린과 자바는 상호 운용성을위해 플랫폼 타입을 사용함
플랫폼 타입은 널가능성이나 가변성에 대한 정보가 없음.
코틀린에선 플랫폼타입을 널이 될수있는 타입이나 될수 없는타입으로 사용
자바에서는 선언한 컬렉션 타입변수를 코틀린에서 사용하려면?