더북(TheBook)

4.2.4 안전한 호출 연산자

널이 될 수 있는 타입의 값에 대해서는 그에 상응하는 널이 될 수 없는 타입의 값에 있는 메서드를 사용할 수 없다고 이미 설명했다. 하지만 특별한 안전한 호출 연산(safe call)을 사용하면 이런 제약을 피할 수 있다. 앞에서 본 예제를 다시 살펴보자.

fun readInt() = readLine()!!.toInt()

여러분의 프로그램이 콘솔을 표준 I/O로 사용하는 한 이 함수는 잘 작동한다. 하지만 프로그램이 파일을 표준 입력에 파이프(pipe)로 연결하면, 파일이 비어있는 경우 이 함수가 KotlinNull PointerException 예외를 발생시키면서 실패할 수 있다. 안전한 호출 연산자를 사용하면 다음 형태로 코드를 다시 작성할 수 있다.

fun readInt() = readLine()?.toInt()

앞의 코드는 기본적으로 다음 함수와 같다.

fun readInt(): Int? {
  val tmp = readLine()
  
  return if (tmp != null) tmp.toInt() else null
}

즉, 안전한 호출 연산자는 수신 객체(왼쪽 피연산자)가 널이 아닌 경우 일반적인 함수 호출처럼 작동한다. 하지만 수신 객체가 널이면 안전한 호출 연산자는 호출을 수행하지 않고 그냥 널을 돌려준다. ||&&와 비슷하게 안전한 호출 연산도 지연 연산의 의미를 따른다. 다시 말해 수신 객체가 널이면 안전한 호출 연산자는 함수의 인자를 계산하지 않는다. 우선순위 면에서 ?. 연산자는 일반적인 함수 호출 연산자(.)와 같은 수준이다.

신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.