# 2. Null-safety

## 널 처리와 Null-safety

\
코틀린은 \*\*“널이 될 수 있는 타입은 완전히 다른 타입”\*\*으로 취급합니다. `?`를 붙여야만 null 가능, 그에 맞는 도구(`?.`, `?:`, `!!`)를 제공합니다. 자바와 달리 **컴파일 단계에서 null 안전성 확보**가 가능하다는 점이 핵심입니다.

***

### 1) Null은 왜 문제인가?

* Java의 대표적인 버그 원인: **NPE (NullPointerException)**
* Java에서는 모든 참조형 변수에 기본적으로 null이 들어갈 수 있습니다.
* 방어 코드: `if (obj != null)`을 반복적으로 작성 → 가독성/생산성 저하

코틀린은 이 문제를 “언어 차원”에서 풀어냅니다.

***

### 2) Nullable vs Non-nullable 타입

```kotlin
val a: String = "kotlin"
// a = null   // 컴파일 에러

val b: String? = null   // ? 붙여야 null 가능
```

* `String` → null 불가능
* `String?` → null 허용

👉 자바에서 `String` 하나만 있던 것이 코틀린에선 두 개로 분리됨.\
👉 덕분에 **컴파일러가 null 가능성을 추적**할 수 있습니다.

***

### 3) Safe Call (`?.`)

“null일 때는 그냥 건너뛰자”라는 의도를 코드로 표현합니다.

```kotlin
val len: Int? = b?.length
```

* `b`가 null → 결과는 null
* `b`가 non-null → `length` 실행

***

### 4) Elvis 연산자 (`?:`)

null일 때 기본값을 지정할 수 있습니다.

```kotlin
val len = b?.length ?: 0
```

* `b`가 null → `len = 0`
* `b`가 non-null → 문자열 길이

→ Java의 `ternary` 연산자 패턴 `(b != null ? b.length() : 0)`을 훨씬 간결하게 표현.

***

### 5) Non-null 단언 (`!!`)

```kotlin
val len = b!!.length
```

* “개발자가 확신하니 그냥 non-null로 취급해!”
* 만약 null이라면 → NPE 발생

👉 **지양할 것**. “자바 스타일” NPE를 그대로 불러옵니다. 정말 확신이 있을 때만 사용하세요.

***

### 6) 스마트 캐스트 (Smart cast)

코틀린은 null 체크 후 자동으로 타입을 좁혀줍니다.

```kotlin
if (b != null) {
    println(b.length) // 여기선 String으로 캐스트됨
}
```

자바였다면 `if (b != null) { System.out.println(b.length()); }`와 같지만,\
코틀린은 **별도의 캐스팅 없이** 안전하게 접근 가능합니다.

***

### 7) 플랫폼 타입 (Platform type)

자바와 연동할 때 등장하는 개념입니다 .

```java
// Java
String getName(); // @Nullable 붙어있지 않음
```

```kotlin
// Kotlin
val name = obj.name  // 타입은 String!
```

* 자바에서 null 가능성이 명시되지 않으면, 코틀린은 “플랫폼 타입”(`String!`)으로 인식
* 이 경우 컴파일러가 null 여부를 알 수 없어, **개발자가 책임지고 처리**해야 함
* 해결책: 자바 코드에 `@Nullable` / `@NotNull` 붙이기, 또는 코틀린 쪽에서 `?`/`!!`로 방어

***

### 8) 실무 예시

#### A. API 응답 DTO

```kotlin
data class UserDto(
    val id: Long,
    val name: String,
    val nickname: String?,  // 옵션 필드
    val email: String?      // 서버에서 null 가능
)
```

→ **nullable을 타입에 드러내므로** API 클라이언트가 강제적으로 null 처리.



#### B. Repository 패턴

```kotlin
fun findUser(id: Long): User? {
    return db.findById(id) // 없으면 null
}

val user = repo.findUser(1) ?: throw NotFoundException()
```

→ Elvis 연산자로 “없으면 바로 예외”를 던지는 패턴.

***

### 9) 체크리스트 & 관용구

* **기본은 non-null 타입**
* null 가능성 있으면 **반드시 `?` 표기**
* null 접근: `?.` (safe call)
* 기본값 제공: `?:` (elvis)
* 정말 확신 있을 때만 `!!`
* 자바 interop → “플랫폼 타입 주의”
* DTO는 null 가능성을 타입에서 바로 드러내라
* Android 생명주기/DI 초기화 등은 `lateinit` 또는 safe call로 처리

***

### 10) 미니 치트시트

* 선언: `val s: String? = null`
* safe call: `s?.length`
* elvis: `s?.length ?: 0`
* not-null 단언: `s!!.length` (주의)
*   null 체크 후 스마트 캐스트:

    ```kotlin
    if (s != null) println(s.length)
    ```
* 자바 interop: 어노테이션으로 null 정보 명확히
