해당 포스팅은 인프런에서 제공하는 최태현 님의 '자바 개발자를 위한 코틀린 입문'을 수강한 후 정리한 글입니다. 유료 강의를 정리한 내용이기에 제공되는 예제나 몇몇 내용들은 제외하였고, 정리한 내용을 바탕으로 글 작성자인 저의 언어로 다시 작성한 글이기에 서술이 부족하거나 잘못된 내용이 있을 수 있습니다. 그렇기에 해당 글은 개념에 대한 참고 정도만 해주시고, 강의를 통해 학습하시기를 추천합니다.
코틀린은 모든 변수에 수정 가능 여부를 명시해주어야 한다. val
키워드는 불변이나, 컬렉션에는 element
를 추가할 수 있다.
var num1 = 10L // var : 가변
val num2 = 10L // val : 불변
또한 타입을 명시적으로 선언하지 않아도 타입을 추론하며, 명시적으로 선언해줄 수도 있다.
var num1: Long = 10L
val num2: Long = 10L
모든 변수는 우선 불변인 val
로 선언하고 필요할 경우에만 var
로 변경하는 것이 좋다.
코틀린에서 변수는 기본적으로 null이 허용되지 않으며 nullable 변수를 생성하기 위해서는 타입?
과 같이 명시적으로 선언해줘야 한다.
var num: Long?
또한 객체를 인스턴스화 할 때 new
를 붙이지 않는다.
val obj = Object("New Object");
코틀린에서는 기본 자료형과 참조 자료형의 구분이 감춰져있다. 일반적으로는 자료형의 구별 없이 사용할 수 있으며, null이 허용된다면 참조형, 아니라면 기본형으로 선언된다. 즉 boxing/unboxing을 고려하지 않아도 되도록 코틀린이 처리 해준다.
코틀린은 null이 가능한 타입을 완전히 다르게 취급하며, 한 번 null check를 하면 컴파일러가 non-null임을 알 수 없다.(특히 Java의 코드를 사용하는 플랫폼 타입일 경우) 따라서 이를 위한 기능을 제공한다.
안전한 호출은 체인(chain)할 때 ?.
를 사용하여 null이 아니면 해당 체인의 연산을 실행하고, null이면 실행하지 않는다. nullable 타입일 경우 안전한 호출을 통해서만 실행이 가능하다.
val str: String? = "ABC"
str.length // str이 nullable이기 때문에 실행 불가능
str?.length
엘비스 연산자는 ?:
를 사용하여 앞의 연산 결과가 null이면 뒤의 내용을 호출해준다.
str?.length ?: 0 // str.length의 값이 null일 경우 0 실행
엘비스 연산은 early return에도 사용할 수 있다.
fun calculate(number: Long?): Long {
number ?: return 0
... null이 아닐 경우 로직
}
nullable 타입이지만 null이 될 수 없는 경우 !!
를 사용할 수 있다.
fun startsWithA(str: String?): Boolean {
return str!!.startsWith("A")
}
코틀린은 선언된 기본값을 보고 타입을 추론하지만 타입간의 변환은 언제나 명시적으로 이루어져야 한다.
val num1 = 4
val num2: Long = num1 // Type mismatch
val num2: Long = num1.toLong() // 명시적 형변환 필요
Java에서의 instanceof
에 해당하는 키워드로 is
키워드가 있으며, 일반 타입은as
를 통해 형변환이 가능하다.(기본 타입도 가능)
fun printAgeIfPerson(obj: Any) {
if (obj is Person) {
// is == java: instance of
// val person = obj as Person
// as = java: (Object) obj, 생략 가능
println(obj.age)
}
}
또한 nullable 변수에 대해 적절한 처리가 필요하다.
val num1: Int? = 3
val num2: Long = num1?.toLong() ?: 0L
fun printAgeIfPersonNullable(obj: Any?) {
val person: Person? = obj as? Person
// as? : obj가 해당 타입이면 형변환, null이거나 해당 타입이 아니면 null을 반환
println(person?.age)
}
Java의 Object 처럼 모든 객체의 최상위 타입으로, 모든 기본 자료형의 최상위 타입 또한 Any이다. Any 자체로는 null을 포함할 수 없으며, Any?
를 통해 포함시킬 수 있다. 기본적으로 equals
, hashCode
, toString
이 존재한다.
Java의 void와 동일한 역할이지만, void와는 다르게 Unit 그 자체를 타입 인자로 사용 가능하다.
함수가 정상적으로 끝나지 않았다는 사실을 표현하는 역할로, 무조건 예외를 반환하거나 무한 루프 함수 등에 사용된다.
fun fail(message: String): Nothin {
throw IllegalArgumentException(message)
}
코틀린은 문자열의 동적인 가공을 위해 아래와 같이 String interpolation을 지원한다.
val person = Person("test", 100)
println("이름: ${person.name} / 나이: ${person.age}")
${변수}
를 사용하면 해당 변수의 값이 포함되며 $변수
를 사용할 경우 해당 변수명이 포함된다.
또한 """문자열""".trimIndent()
을 통해 편리하게 여러 줄의 문자열을 가공할 수 있게 해준다.
문자열에서 문자를 가져올 때 [index]
를 통해 Java의 배열과 같이 가져올 수 있다.
단항/산술 연산자는 Java와 동일하다. ++
, --
로 단항 연산을 할 수 있으며 +
, -
, *
, /
, %
로 산술 연산을, +=
, -=
, *=
, /=
, %/
로 산술 대입 연산이 가능하다.
비교 연산자 또한 Java와 동일하게 >
, <
, >=
, <=
, ==
으로 할 수 있다. 단, Java와 다르게 객체를 비교할 때 비교 연산자를 사용하면 자동으로 compareTo
를 호출해준다.
두 객체의 값이 같은지 비교하는 동등성 비교에 equals
, 주소가 같은 완전히 동일한 객체인지 비교하는 동일성 비교에 ==
를 사용하는 Java와는 다르게 동등성에 ==
를 사용하여 간접적으로 equals
를 호출하며, 동일성 비교는 ===
을 사용한다.
&&
, ||
, !
을 통해 논리 연산이 가능하며, Java와 같이 Lazy 연산을 수행한다.
이 외에 코틀린에만 존재하는 연산자로는 컬렉션의 범위에 포함되어있는지의 여부를 리턴하는 in
/!in
, a에서 b까지의 범위 객체를 생성하는 a..b
, a[i]
, a[i] = b
로 a에서 특정 index i를 통해 값을 처리할 수 있는 연산자가 존재한다.
코틀린에서는 아래와 같이 객체마다 연산자를 직접 정의할 수 있다.
data class Money(
val amount: Long
) {
operator fun plus(other: Money): Money {
return Money(this.amount + other.amount)
}
}
...
val money1 = Money(1_000L)
val money2 = Money(2_000L)
print(money1 + money2) // Money(3_000L)