Nullable
타입은 수행할 수 있는 연산이 많이 제한되기는 하지만 널 값과 비교할 수 있다는 장점이 있다.
이게 왜 장점일까?
Nullable
이 아닌 경우 널 값에 의해 오류가 나더라도 그냥 일반 오류 메세지를 띄우기 때문에 개발자 입장에서는 무엇이 문제인지 알기 힘들다. 그러나 Nullable
의 경우 명확히 NPE
을 발생시키기 때문에 널에 의한 오류임을 바로 알 수 있게 된다.
그리고 컴파일러는 이를 기억해서 non null
임이 확실한 영역에서는 non null
값처럼 사용할 수 있도록 한다.
!!
가 이름이 널 아님 단언이라고 해서 무조건 NPE
를 피할 수 있는 것은 아니다.
널 아님 단언을 사용하더라도 값이 널일때는
NPE
를 던질 수 있다. 따라서!!
의 활용은 신중해야 한다.
예를 들어 어떤 함수에서 값이 널인지 검사를 한 후에 명확히 non null
인게 결정되면 나중에 호출된 함수 안에서 이 값을 안전하게 사용할 수 있다는 보증으로 !!
를 써주는 식이다. 이렇게 하게 되면 호출된 함수가 굳이 널 검사를 수행하지 않도록 해주어 더 효율적으로 코드를 쓸 수 있다.
스코프 함수는 특정 객체의 컨텍스트 내에서 특정 동작 (프로퍼티 초기화, 활용 등)을 실행하기 위한 목적만을 가진 함수다.
이 스코프 내에서에서는 객체의 이름을 통해 일일이 참조할 필요 없이 객체를 접근하고 핸들링할 수 있어 편리하다는 장점이 있다.
코틀린이 제공하는 스코프 함수는 총 5가지로, apply
, run
, with
, alse
, let
으로 이루어져 있다.
(출처: https://medium.com/@fatihcoskun/kotlin-scoping-functions-apply-vs-with-let-also-run-816e4efb75f5)
수신 객체를 접근할 때 it
을 사용할 수 있도록 하는 스코프 함수의 일종이다.
it
을 사용해야 하는 이유는 무엇일까?해당 클래스 밖의 main()
스코프 내에 인스턴스 프로퍼티와 이름이 같은 변수가 있는 경우 상위 스코프인 main()
스코프의 동명의 변수를 참조하게 된다. 실제로 개발을 하다보면 변수 명을 짓는 게 여간 일이 아니므로... 이와 같은 혼란이 생길 수도 있다.
바로 이러한 혼란을 방지하기 위해 it
이라는 키워드가 필요한 것이다. it
키워드에 참조 연산자를 통해 프로퍼티 및 함수를 접근하면 해당 스코프 내에서 안전하게 참조가 가능해진다.
null
이 아닌 경우에 코드를 실행해야 하는 경우Nullable
객체를 다른 타입의 변수로 변환해야 하는 경우어떤 메서드를 호출하기 전에 수신 객체 역할을 하는 변수가 널이 될 수 없다고 보장하는 대신 직접 변수에 대해 메서드를 호출해도 확장 함수인 메서드가 알아서 널을 처리해준다.
즉, 메서드 호출 전에 그 변수가 non null
이라고 보장해봤자 아무 의미 없고, 확장 함수인 메서드가 알아서 널 값에 대한 체크를 한다는 것이다.
그러나 자바의 경우 애초에 확장을 정의할 수 없기에 널이 될 수 있는 값에 대해 확장 함수를 호출할 수 없다. 따라서 자바의 경우 수신 객체의 타입은 항상 non null
타입이고, 메서드 안의 this
는 해당 수신 객체를 가리키므로 역시 항상 non null
타입이다.
하지만 코틀린의 경우 nullable
을 수신 객체로 하여 확장 함수를 정의할 수 있고, 이 경우 수신 객체를 가리키는 this
역시 nullable
이 될 수 있다.
결국 null
값을 다룰 수 있다는 점에서 nullable
타입 확장은 강력한 기능이라고 할 수 있다.
내가 아무리 운전을 조심히 한다고 하더라도 남이 와서 들이받으면 결론적으로는 사고가 나게 난다.
"읽기 전용 컬렉션이 스레드 안전을 보장하는 것은 아니다." 라는 말은 위 한 문장으로 설명이 가능하다.
내가 읽기 전용 컬렉션으로 어떤 데이터에 접근하고 있다고 하더라도 다른 곳에서 변경 가능한 컬렉션으로 접근을 하고 있다면 해당 데이터가 변경되어 의도와 다르게 잘못된 값을 읽어올 수도 있는 것이다.
따라서 읽기 전용 컬렉션을 이용한다고 하더라도 항상 스레드 안전한 것은 아니다.
함수의 시그니처는 일반적으로 함수의 원형에 명시되는 매개변수 리스트를 가리킨다. 만약 두 함수가 매개변수의 개수와 타입이 모두 같다면 두 함수의 시그니처는 같다고 할 수 있다.
시그니처는 다음을 포함할 수 있다. (언어마다 조금씩 다르다.)
간단하게 생각해서 그냥 함수의 맨 윗줄이라고 생각하면 된다.