[코틀린] 코틀린에서 null을 다루는 방법

J·2023년 3월 20일
1

안드로이드

목록 보기
13/29

1. Kotlin에서의 null 체크

a. Java에서의 null 체크방법

public boolean startsWithA(String str) {
  return str.startsWith("A");
}

위의 코드는 null 값을 갖고오면 NPE가 나기 때문에 안전한 코드가 아니다.

따라서 자바에서 null을 체크하는 안전한 코드로 고치는 방법은,

public boolean startsWithA1(String str) {
  if(str == null) {
    throw new IllegalArgumentsException("null이 들어왔습니다.");
  }
  return str.startsWith("A");
}

=> 위와 같이 str이 null일 경우 Exception을 내거나,

public Boolean startsWithA2(String str) {
  if(str == null) {
    return null;
  }
  return str.startsWith("A");
}

=> 위와 같이 str이 null일 경우 null을 반환하거나, (null 값을 반환해주므로 메소드 타입은 null 값 반환 가능한 Boolean)

public boolean startsWithA3(String str) {
  if(str == null) {
    return false;
  }
  return str.startsWith("A");
}

=> 위와 같이 str이 null일 경우 false를 반환한다.

b. Kotlin에서의 null 체크방법

fun startsWithA1(str: String?): Boolean {
  if(str == null) {
    throw IllegalArgumentException("null이 들어왔습니다.")
  }
  return str.startsWith("A")
}

=> 들어오는 값(파라미터, str)이 null 일 수 있으므로, 타입 지정 후 오른쪽에 “?(물음표)”를 붙여주고, 함수 값 반환 시 Boolean 타입으로 표시를 해주므로(단, null 값을 반환할 수는 없음), 함수의 타입(Boolean)을 맨 오른쪽에 표시해준다.

fun startsWithA2(str: String?): Boolean? {
  if(str == null) {
    return null
  }
  return str.startsWith("A")
}

=> 들어오는 값(파라미터, str)이 null 이라면 null 값을 반환하므로, 파라미터 타입 뿐만 아니라, 함수의 타입(Boolean) 오른쪽에도 “?(물음표)”를 표시해준다.

fun startsWithA3(str: String?): Boolean {
  if (str == null) {
    return false
  }
  return str.startsWith("A")
}

=> Kotlin은 null 일 수 있는 변수에 대해서 바로 메소드콜을 할 수 없는데, 문맥상 위에서 null 체크를 해주면 자동으로 아래에 있는 변수는 null이 아닐거라고 컴파일러가 자동으로 추측을 해준다.

따라서, 아래에 있는 str 변수는 null 값이 아니라는 의미로 초록색으로 표시되게 된다.

번외로,

fun startsWithA(str: String?): Boolean {
  return str.startsWith("A")
}

=> 맨 위의 NPE 위험이 있는 JAVA 코드처럼 Kotlin에서도 null에 대한 체크 없이 바로 파라미터 값을 반환하려고 하면, str 값이 null 일수도 있기 때문에 바로 에러가 난다.

fun startsWithA(str: String): Boolean {
  return str.startsWith("A")
}

=> 위의 코드의 경우, 파라미터 타입 뒤에 “?(물음표)” 가 없으므로, null 값일 때 파라미터 값으로 받아올 수 없는 것으로 간주하고, str.startsWith(“A”)가 바로 호출된다.

2. Safe Call과 Elvis 연산자

Kotlin에서는 null이 가능한 타입을 완전히 다르게 취급한다.
=> null이 가능한 타입만을 위한 기능은 없을까?!
==> 있다!!!

a. Safe Call

val str: String? = "ABC"
str.length // 불가능
srt?.length // 가능!!

null이 아니면 실행하고, null이면 실행하지 않는다. (그대로 null)

b. Elvis 연산자

val str: String? = "ABC" //null이 아니라면 그 값이 호출
str?.length ?: 0 // null인 경우 0 호출

앞의 연산 결과가 null이면 뒤의 값을 사용
Elvis 연산은 early return 에도 사용할 수 있다.

< JAVA.ver >

public long calculate(Long number) {
  if (number == null) {
    return 0;
  }
  //다음 로직
}

< Kotlin.ver >

fun calculate(number: Long?): Long {
  number ?: return 0
  //다음 로직
}

3. null 아님 단언!!

nullable type 이지만, 아무리 생각해도 null이 될 수 없는 경우

fun startsWithA1(str: String?): Boolean {
  return str!!.startsWith("A")
}

=> 변수!!.startsWith(“값”) → 절대 null 이 아니야!! 라는 뜻

4. 플랫폼 타입

Kotlin에서 Java 코드를 가져다 사용할 때 어떻게 처리될까?!

<Person.java>

import org.jetbrains.annotation.Nullable;

public class Person {
  private final String name;
  
  public Person(String name) {
    this.name = name;
  }
  
  @Nullable
  public String getName() {
    return name;
  }
}

<Lec02Main.kt>

package com.lannstark.lec02

fun main() {
  val person = Person("공부하는 개발자") //Person.java를 불러옴
  startsWithA(person.name) //null 을 쓸 수 없으므로 빨간 밑줄이 쳐진다.
  //사용하고 싶다면 java 코드에서 @Nullable => @NotNull로 바꾸거나, startsWithA 함수의 파라미터의 타입 뒤에 "?" 를 붙여준다.
}

fun startsWithA(str: String): Boolean {
  return str.startsWith("A")
}
  • javax.annotation 패키지
  • android.support.annotation 패키지
  • org.jetbrains.annotation 패키지
  • Nullable이 없다면?! : Kotlin에서는 이 값이 nullable인지 non-nullable 인지 알 수가 없다.
  • 플랫폼 타입 : 코틀린이 null 관련 정보를 알 수 없는 타입. Runtime 시 Exception이 날 수 있다.

※ 코틀린에서 null을 다루는 방법 (정리) ※

  • 코틀린에서 null이 들어갈 수 있는 타입은 완전히 다르게 간주된다
  • 한 번 null 검사를 하면 non-null임을 컴파일러가 알 수 있다
  • null이 아닌 경우에만 호출되는 Safe Call (?.) 이 있다
  • null인 경우에만 호출되는 Elvis 연산자 (?:) 가 있다
  • null이 절대 아닐 때 사용할 수 있는 널 아님 단언 (!!) 이 있다
  • Kotlin에서 Java 코드를 사용할 때 플랫폼 타입 사용에 유의해야 한다.
  • Java 코드를 읽으며 null 가능성 확인 / Kotlin으로 wrapping

0개의 댓글