코틀린은 널이 될 수 있는 타입을 지원해 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 반환 가능!
플랫폼 타입, 자바 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 같이 딱딱 떨어지는 값들을 표현할 수 있는 값이 원시타입이라고 한다면
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로 선언은 가능