[Kotlin] - 코틀린에서 변수를 다루는 방법

자바 개발자를 위한 코틀린 입문을 공부하며 작성한 글입니다.
혼자 공부하고 정리한 내용이며, 틀린 부분은 지적해주시면 감사드리겠습니다 😀

var VS val

모든 변수는 우선 val로 만들고, 꼭 필요한 경우 var로 변경한다.

long number1 = 10L;
final long number2 = 10L;

longfinal long의 차이는 가변 / 불변의 차이를 나타낸다.

구분 설명
long 처음 값을 할당 받고 나서, 다시 한 번 값을 바꿔줄 수 있다.
final long 한 번 값을 지정해주면 더 이상 바꿀 수 없다.

위 코드를 코틀린으로 변환하면 다음과 같다.

// variable
var number1 = 10L

// value
val number2 = 10L

코틀린에서는 모든 변수에 수정 가능 여부를 명시해주어야 하며, 타입은 컴파일러가 추론해주기 때문에 의무적으로 작성하지 않아도 된다.

늦은 초기화

var number1: Long
val number2: Long

// 에러 발생 : Variable 'number1' must be initialized
// print(number1)
// print(number2)

number1 = 5
number2 = 5

print(number1)
print(number2)

varval 모두 값이 초기화되지 않은 상태에서 출력을 하려고 하면 에러가 발생한다. val은 최초 한 번에 한해서 값을 초기화할 수 있다.

초기값을 지정해주지 않을 경우 타입을 무조건 명시해줘야 하며, 값을 초기화한 후 사용해야한다.

Primitive Type

java에는 ReferencePrimitive 타입이 모두 존재한다.

long number1 = 10L
Long number3 = 1_000L;

Effective Java, Item6을 보면 다음과 같은 내용이 존재한다.

연산을 할 때에는, 박싱된 기본 타입보다는 기본 타입을 사용하고, 의도치 않은 오토 박싱이 숨어들지 않도록 주의하자.

private static long sum() {
    Long sum = 0L;
    for (long i = 0; i <= Integer.MAX_VALUE; i++) {
        sum += i;
    } 
    return sum;
}

위 코드의 경우 Long 타입이 long과 연산을 하는 과정에서 박싱과 언박싱이 계속해서 일어나 불필요한 객체가 생성이 되면서 성능이 저하된다.

하지만, 코틀린의 경우 동일하게 사용한다.

var number1 = 10L
var number3 = 1_000L

공식 문서를 보면 다음과 같은 내용이 있는 것을 볼 수 있다.

Some types can have a special internal representation

  • for example, numbers, characters and booleans
  • can be represented as primitive values at runtime
  • but to the user they look like ordinary classes.

코드에서는 평범한 클래스처럼 보이지만, 실행 시에는 코틀린이 알아서 최적화를 해준다.

실제로 작성한 코드를 디컴파일 해보면 다음과 같다.

fun main() {
    var result: Long = 0L

    for (i in 0L .. 10L) {
        result += (i + 1L)
    }

    println(result)
}
public final class KotlinVariableKt {
   public static final void main() {
      long number1 = 0L;
      long result = 0L;
      long i = 0L;

      for(long var6 = 10L; i <= var6; ++i) {
         result += i + 1L;
      }

      System.out.println(result);
   }

   public static void main(String[] var0) {
      main();
   }
}

분명 kotlin에서는 Long 타입으로 작성했지만, 실제 디컴파일된 코드를 보면 primitive long으로 작성된 것을 볼 수 있다.

이처럼 프로그래머가 boxing / unboxing을 고려하지 않아도 되도록 kotlin이 알아서 처리해준다.

nullable

java에서 Reference 타입으로 작성하면 null을 허용할 수 있게 된다.

Long nubmer = null;

하지만 kotlin에서는 ‘null이 들어갈 수 있는’을 아예 다르게 간주한다.

var number = 1_000L
// 에러 발생 : Null can not be a value of a non-null type Long
number = null

기본적으로 모든 변수는 null이 들어갈 수 없게끔 설계되었기 때문에 에러가 발생하는 것이다.

그렇기 때문에 null을 허용할 수 있도록 타입에 ?를 명시해주어야 한다.

var number: Long? = 1_000L
number = null

Instance

java에서 객체를 생성하기 위해서는 아래와 같이 new 키워드를 사용해야 한다.

Person p = new Person("Jwhy")

kotlin의 경우 해당 키워드 없이 바로 사용이 가능하다.

var person = Person("Jwhy")

위와 같이 객체 인스턴스화를 할 때에는 new를 붙이지 않는다.

정리

  • 모든 변수는 var / val을 붙어주어야 한다.
    • var : 변경 가능
    • val : 변경 불가능 (read-only)
  • 타입을 명시하지 않아도, 추론이 가능하다.
  • PrimitiveReference 타입을 구분하지 않아도 된다.
  • null이 들어갈 수 있는 변수는 타입 뒤에 ?를 붙어주어야 한다.
    • 아예 다른 타입으로 간주한다.(Long != Long?)
  • 객체를 인스턴스화 할 때, new를 붙이지 않아야 한다.

태그:

카테고리:

업데이트:

댓글남기기