본문 바로가기
Android/Kotlin 기초

Kotlin 기초 문법 6 - Nullable, null, null check

by 2Plus 2020. 5. 24.

Photo by Marc Reichelt on Unsplash

 오늘은 Swift의 Optional, nil과 비슷한 개념인 Nullable, null에 대해 알아볼 것이다. Swift와 비교한 부분은 다른 글에 따로 포스팅 했으니 필요하다면 참고 바란다.

 

 

null

 먼저, Kotlin에서의 null은 다른 언어에서의 null 개념과 비슷하다고 생각하면 된다. null은 변수가 실제로 아무 객체도 가리키고 있지 않다는 뜻이다. C언어에서도 메모리를 가리키는 포인터가 실제로 가리킬 객체나 자료가 없을 때 NULL을 가질 수 있듯이 Kotlin도 null을 할당할 수 있다. 한 가지 차이점은 C언어에서의 NULL은 값이 0으로, 0번 주소가 되고 이것은 가리키는 메모리가 없다는 뜻으로 인식된다. 하지만 Kotlin에서의 null은 0이 아니라 null이 따로 정의되어 있다.

 

 

Nullable

 아무 변수나 null이 될 수 없다. null이 될 수 있는 변수는 Nullable로 선언해야 한다. 이렇게 함으로써, 프로그램이 동작하면서 절대로 null이 안 되는 변수는 일반적으로 선언해서 사용하고 null이 될 수 있는 변수는 Nullable로 선언하여 안전하고 편하게 사용할 수 있다.

 Nullable은 타입 뒤에 물음표(?)를 붙여주기만 하면 된다.

[Code]

 

 

[결과]

 

 

 "var str: String? = null" 부분처럼 타입 뒤에 물음표만 붙여주면 Nullable로 선언한 것이다.

 

 

Safe Call (?.)

 Nullable을 사용할 때는 그냥 사용하지 않고 null일 수 있으므로 체크를 하여 사용해야 한다. 이러한 체크를 통해 NullPointerException이 발생하는 것을 방지하고 각 상황에 맞게 동작하도록 프로그램을 만들 수 있다.
 참조 변수의 뒤에 "?."를 붙여주고 프로퍼티나 변수의 멤버 함수를 호출하면 된다. 참조 변수가 null이면 프로퍼티의 경우는 해당 표현식은 null이 되고, 멤버 함수의 경우는 실행되지 않는다.

 

[Code]

 

 

[결과]

 

 

 위의 예시를 보면 처음 생성한 rectangle은 null이다. 여기에 safe call로 width 프로퍼티에 접근하려 하면 해당 값은 null이고, 멤버 함수를 호출하면 호출되지 않는다(없으니까). 동일한 참조 변수에 Rectangle을 실제로 생성해서 할당해주고 safe call로 동일한 작업을 진행해보면 값이 있기 때문에 정상적으로 나오는 것을 확인할 수 있다.

 

 

Safe Call Chaining

 이처럼 Nullable을 safe call을 통해 접근하면 하위 타입도 Nullable이기 때문에 Safe Call을 연달아서 사용할 수 있다.

 

 

강제 캐스팅 (!!)

 Safe Call (?.) 대신에 해당 호출 부분에서 null이 아닌 게 확실히 보장된다면 강제로 Nullable 타입을 벗길 수 있다. "!!"를 Nullable 변수 뒤에 붙여주면 벗겨진다. 하지만 개인적으로 추천하는 방법은 아니다. 제공을 해주는 기능이기는 하지만, Nullable이 생겨난 취지와는 다르고, 이것을 사용하는 데에 편해지다 보면 null인 경우가 발생할 수 있는 데도 이를 놓칠 수 있기 때문이다. 프로그램 실행 중에 이렇게 강제로 벗겼는데 null이었다면 NullPointerException이 발생하면서 프로그램이 강제 종료된다. 사용해야 한다면 꼭 이를 주의해서 사용하자.

 

 

[Code 1]

 

 

[결과 1]

 

 

 앞선 예시와 동일한데, rectangle이 확실하게 있는 부분에서는 강제 캐스팅을 사용하였다. 정상적으로 동작하는 것을 확인할 수 있다.

 

 

[Code 2]

 

 

[결과 2]

 

 

 이번에는 null인 경우에 강제 캐스팅을 사용해보았다. null인 참조 변수를 강제 캐스팅하는 첫 순간에 바로 NullPointerException이 발생하는 것을 확인할 수 있다. 꼭 주의해서 사용하도록 하자.

 

 

Null Check (?:, 스마트 캐스팅)

 앞선 방법 외에 null을 체크할 수 있는 두 가지 방법이다. (개인적으로는 Swift에서의 guard 구문이나 if let ~ 구문을 사용하는 게 참 편했는데, Kotlin에서는 그런 것이 안 되어서 사용이 불편한 것 같다..)

 

[Code]

 

 

[결과]

 

 

 먼저 "?:"를 사용할 수 있다. 해당 연산자를 사용하면 Nullable 참조 변수가 null이 아니면 해당 값을 사용하고, null이라면 우측의 값을 사용한다. 예시 코드를 확인해보면 str이 null이면 우측 값을 사용하고, 값이 있다면 그 값을 그대로 사용한 것을 확인할 수 있다.

 

 

[Code]

 

 

[결과]

 

 

 두 번째로는 if 조건문을 사용하여 null인지를 체크하는 것이다. 이렇게 하면 해당 조건문 밑에서는 null이 아님이 보장되기 때문에 조건문 밑 부분은 컴파일러가 자동으로 해당 변수를 Nullable이 아닌 일반 타입으로 캐스팅 해준다.

 

 

Safe Call과 let 사용

 if 구문을 이용하여 체크하는 방법과 함께 개인적으로 많이 사용하는 방법이다. 앞선 safe call과 let을 사용하면, let block 안에서는 Nullable이 벗겨지기 때문에 일반 변수처럼 사용할 수 있다. null일 경우에 대해 추가 처리가 필요하지는 않고, 호출 시 여러 번 호출해야 한다면 매번 safe call을 하기는 불편하니 이 방법을 사용하면 편하게 사용할 수 있다.

 

 

 이런 식으로 사용할 수 있다. 결과는 앞선 예제들과 동일하니 생략한다.

 

 

반응형

댓글