반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 롬복 어노테이션
- @Data
- kubenetes
- K번째수
- 정렬
- 모던 자바 인 액션
- 코딩 테스트
- 검색 기능 확장
- 스프링 스케쥴러
- 쿠버네티스
- @configuration
- Java
- 다리를 지나는 트럭
- @EnableScheduling
- 루씬 인 액션
- 고차원 함수
- 커링
- 영속 자료구조
- 가장 큰 수
- H-index
- @Getter
- 프로그래머스
- 크론 표현식
- 스택/큐
- @Setter
- 해시
- 완주하지 못한 선수
- 알고리즘
- 기능개발
- 전화번호 목록
Archives
- Today
- Total
Today I Learned
오류를 예방하는 타입 안정성(1) 본문
728x90
- 코틀린은 함수나 메소드가 null을 받거나 리턴할 수 있는지 명확하게 표현되며, 그 시점도 알 수 있다.
- 참조가 null이 될 수 있다면 참조하고 있는 객체의 속성이나 메소드를 사용할 땐 언제나 null 체크를 하도록 강제한다.
Any와 Nothing 클래스
- 코틀린의 모든 클래스는 Java의 Object 클래스처럼 Any 클래스에 상속을 받는다.
- Any 클래스는 코틀린의 모든 클래스에서 사용 가능한 유용한 메소드를 포함하고 있다.
- Nothing 클래스는 함수가 아무것도 리턴하지 않을 경우에 리턴하는 클래스이다.
베이스 클래스 Any
- 함수가 여러 타입의 객체를 파라미터로 받는다면, 함수의 파라미터를 Any로 설정해 놓으면 된다.
- 함수에서 특정 타입을 리턴하기 난감하다면 Any를 리턴하면 된다.
- Any 클래스는 개발자에게 최대한 유연성을 제공하지만, 제한적으로 사용해야 한다.(과한 기능)
- Any의 목적은 변수의 타입을 Any로 정의하도록 하는 게 아니라, 모든 코틀린의 타입에 공통으로 적용되는 메소드를 만들기 위해 존재한다.(equals(), hashCode(), toString() 등등)
Nothing은 void보다 강력하다
- 코틀린에서 표현식이 리턴을 하지 않을 때 void 대신 Unit을 사용한다.
- 함수가 절대로 리턴을 하지 않는 상황이라면 Nothing 클래스를 리턴타입으로 사용한다.
- 예외는 Nothing 타입을 대표한다.
- Nothing의 목적은 컴파일러가 프로그램의 타입 무결성을 검증하도록 도와주는 것이다.
Null 가능 참조
- Java에서는 NullPointerException의 해결책으로 Optional을 사용하지만 문제가 있다.
- 컴파일러가 Optional을 사용을 강제하지 않고, 개발자가 직접 사용해야 한다.
- Optional이 객체의 참조 또는 null을 감쌀 때 객체가 없다면 작은 오버헤드가 발생한다.
- 개발자가 Optional이 아닌 null을 리턴하더라도 컴파일러는 별다른 경고를 주지 않는다.
- 코틀린은 이런 이슈들이 없으며, 컴파일 시간에 null 체크 여부를 확인시켜준다.
- 일반적으로 코틀린 코트를 작성할 때 Java와 상호운용할 목적이 아니라면 null과 nullable 타입은 절대 사용하지 않는 편이 좋다.
Null 가능 타입 사용하기
- null 불가 타입들은 각자 대응하는 null 가능 타입이 존재한다. null 가능 타입은 이름 뒤에 ?가 붙는다.
- null 가능 참조 타입일 경우, 받는 쪽에서 null 체크를 해야만 사용할 수 있다.
세이프 콜 연산자
- ? 연산자(=세이프 콜 연산자)를 이용하면 메소드 호출 또는 객체 속성 접근과 null 체크를 하나로 합칠 수 있다.
if(name != null) {
return name.reversed()
}
return null
//세이프 콜 연산자 사용
return name?.reversed()
- 세이프 콜 연산자를 연결해서 사용할 수도 있다.
return name?.reversed()?.toUpperCase()
엘비스 연산자
- 엘비스 연산자 ?: 를 이용하면 좌측 표현식의 결과가 null이 아닐 경우 결과를 리턴하고 null일 경우 우측 표현식의 결과를 리턴한다.
val result = name?.reversed()?.toUpperCase()
return if (result == null) "Joker" else result
//엘비스 표현식 사용
return name?.reversed()?.toUpperCase() ?: "Joker"
사용해서는 안될 안전하지 않은 확정 연산자 !!
- 특정 참조가 절대 null이 아니란 사실을 알고 있다면 !! 연산자를 사용해서 코틀린에게 null 체크를 할 필요가 없다고 전달할 수 있다.
return name!!.reversed().toUpperCase() //Bad code
when의 사용
- null 가능 참조의 값을 추출할 때는 세이프 콜이나 엘비스 연산자를 사용하고, null 가능 참조에 대한 처리를 할때는 when을 사용한다
fun nickName(name :String?) = when (name) {
"William" -> "Bill"
null -> "Joker"
else -> name.reversed().toUpperCase()
}
- null에 해당하는 절은 else 위면 어디든 상관없다.
- null 체크를 했기 때문에 when에 있는 다른 모든 경우 전달받은 참조가 null이 아닌 경우에만 동작한다.
타입 체크와 캐스팅
타입 체크
- 타입 체크는 확장성 측면에서 봤을때 최소한으로만 해야하며, 개방-폐쇄 원칙에도 위배된다.
- 하지만 실행 시간에 타입 체크를 하는건 유용하고 꼭 필요한 경우도 있다.
- equal() 메소드를 구현하려면 현재 가지고 있는 객체가 해당 클래스의 인스턴스인지 알아야한다.
- when의 분기가 인스넡스 타입에 기반해서 이루어지는 경우 타입 체크가 필요하다.
is 사용하기
- 아래 코드에서 Animal 클래스는 equals() 메소드가 모든 Animal 클래스의 인스턴스를 동일하게 취급하도록 오버라이드한다.
- is 연산자는 객체가 참조로 특정 타입을 가리키는지 확인한다.
class Animal {
override operator fun equals(other: Any?) = other is Animal
}
val greet: Any = "hello"
var odie: Any = Animal()
var toto: Any = Animal()
println(odie == greet) //false
println(odie == toto) //true
- 코틀린은 == 연산자를 equals() 메소드에 맵핑해놨다.
- is 연산자는 모든 타입의 참조에 사용될 수 있다.
- 참조가 null이라면 is의 연산 결과는 false이다.
- !is를 사용해서 부정을 나타내는 연산자로 사용할 수도 있다.
스마트 캐스트
- java에서는 instanceof로 타입을 체크했더라도 속성을 참조하려면 직접 캐스팅을 해야한다.
ex) ((Animal)other).age - 코틀린은 참조의 타입이 확인되면 스마트 캐스팅을 한다.
class Animal(val age: Int) {
override operator fun equals(other: Any?):Boolean {
return if (other is Animal) age == other.age else false
}
}
- other.age에 if문 전에 접근하려고 했다면 컴파일 오류가 났을 것이다.
- is 연산자로 체크했기 때문에 캐스팅 할 필요가 없다.
- 스마트 캐스트는 if문 뿐만 아니라 || 혹은 && 연산자 이후에도 작동한다.
override operator fun equals(other: Any?) =
other is Animal && age == other.age
- 코틀린은 스마트 캐스트가 가능하다면 자동으로 스마트 캐스트를 해준다.
- 객체가 null 참조가 아니라고 판별하면 null 가능 타입이 null 불가 타입으로 자동으로 캐스팅된다.
when과 함께 타입 체크와 스마트 캐스트 사용하기
- when 명령문 또는 표현식에 is나 !is, 스마트 캐스팅을 사용할 수 있다.
fun whatToDo(dayOfWeek : Any) = when (dayOfWeek) {
"Saturday", "Sunday", -> "Relax"
in listOf("Monday", "Tuesday", "Wednesday", "Thursday") -> "Work hard"
in 2..4 -> "Work hard"
"Friday" -> "party"
is String -> "What?, yo provided a String of length ${dayOfWeek.length}"
else -> "No Clue"
}
명시적 타입 캐스팅
- 명시적 타입 캐스팅은 컴파일러가 타입을 확실하게 결정할 수 없어 스마트 캐스팅을 하지 못할 경우에만 사용해야 한다.
- 코틀린은 명시적 타입 캐스트를 위해 as와 as?를 제공한다.
- as 연산자는 우측에 지정된 타입과 같은 타입을 결과로 주며, 캐스팅이 실패하면 에러가 발생하고 종료된다.
- as?는 null 가능 참조 타입을 결과로 가지며, 캐스팅이 실패하면 null을 할당한다.
728x90
'Kotlin > 다재다능 코틀린 프로그래밍' 카테고리의 다른 글
객체와 클래스 (0) | 2023.08.01 |
---|---|
오류를 예방하는 타입 안정성 (2) (0) | 2023.08.01 |
콜렉션 사용하기 (0) | 2023.07.27 |
외부 반복과 아큐먼트 매칭 (0) | 2023.07.21 |
Java 개발자를 위한 코틀린 필수 사항 (0) | 2023.07.20 |
Comments