Theme:

자바를 쓰다가 코틀린을 처음 접하면 "이게 같은 JVM 위에서 돌아간다고?" 싶을 정도로 문법이 간결하다. 세미콜론도 없고, getter/setter도 없고, null 처리까지 언어 차원에서 해준다. 면접에서 "코틀린 써봤냐"는 질문이 늘고 있어서, 자바 개발자 관점에서 코틀린의 첫 단추를 정리해봤다.

val과 var — 변수 선언의 기본

코틀린에서 변수를 선언하는 방법은 딱 두 가지다.

  • val — 재할당 불가 (자바의 final과 비슷)
  • var — 재할당 가능
KOTLIN
val name = "코틀린"    // 재할당 불가
var count = 0          // 재할당 가능

// name = "자바"       // 컴파일 에러!
count = 1              // OK

면접에서 자주 나오는 포인트

"val은 불변인가요?" 라는 질문에 바로 "네"라고 답하면 감점이다. val은 재할당이 불가능할 뿐, 객체 내부의 상태는 변할 수 있다.

KOTLIN
val list = mutableListOf(1, 2, 3)
list.add(4)           // OK — 리스트 내부 상태 변경
// list = mutableListOf()  // 컴파일 에러 — 재할당 불가

자바의 final 변수와 정확히 같은 개념이라고 설명하면 면접관이 좋아한다.

타입 추론 — 타입을 안 써도 되는 이유

코틀린은 컴파일러가 초기화 값을 보고 타입을 알아서 결정한다. 이걸 **타입 추론(Type Inference)**이라고 한다.

KOTLIN
val message = "Hello"          // String으로 추론
val number = 42                // Int로 추론
val pi = 3.14                  // Double로 추론

명시적으로 타입을 적어도 된다.

KOTLIN
val message: String = "Hello"
val number: Int = 42

타입 추론이 안 되는 경우

초기화 없이 선언만 하면 타입을 반드시 명시해야 한다.

KOTLIN
val name: String    // 나중에 초기화할 예정
// val name          // 컴파일 에러 — 타입을 알 수 없음

공부하다 보니 여기서 많이 헷갈렸는데, 코틀린은 정적 타이핑 언어다. 타입을 안 쓴다고 동적 타이핑이 아니라, 컴파일 타임에 타입이 확정된다.

Nullable 타입 — 물음표 하나의 차이

코틀린에서 가장 중요한 특징 중 하나다. 기본적으로 모든 타입은 null을 허용하지 않는다.

KOTLIN
var name: String = "코틀린"
// name = null                 // 컴파일 에러!

var nullableName: String? = "코틀린"
nullableName = null            // OK

타입 뒤에 ?를 붙이면 Nullable 타입이 된다. 이 간단한 규칙 하나로 NPE(NullPointerException)를 컴파일 타임에 잡아낸다.

KOTLIN
fun getLength(text: String?): Int {
    // return text.length      // 컴파일 에러 — null일 수 있음
    return text?.length ?: 0   // 안전 호출 + 엘비스 연산자
}

Nullable에 대한 더 자세한 내용은 별도 글에서 다루겠다.

String Template — 문자열 조합의 혁명

자바에서 문자열을 조합하려면 + 연산이나 String.format()을 썼는데, 코틀린은 $ 하나로 해결된다.

KOTLIN
val name = "코틀린"
val version = 2.0

// 변수 직접 삽입
println("언어: $name")                    // 언어: 코틀린

// 표현식 삽입
println("버전: ${version + 0.1}")         // 버전: 2.1

// 여러 줄 문자열
val json = """
    {
        "name": "$name",
        "version": $version
    }
""".trimIndent()

자바와 비교

JAVA
// 자바
String result = "이름: " + name + ", 버전: " + version;
String result2 = String.format("이름: %s, 버전: %.1f", name, version);
KOTLIN
// 코틀린
val result = "이름: $name, 버전: $version"

면접에서 이 포인트를 물어보더라고요 — "가독성과 생산성" 측면에서 답하면 된다.

when 표현식 — switch의 완전한 상위 호환

자바의 switch는 제약이 많았는데, 코틀린의 when은 훨씬 강력하다.

기본 사용법

KOTLIN
val grade = 'A'

val result = when (grade) {
    'A' -> "우수"
    'B' -> "보통"
    'C' -> "미흡"
    else -> "알 수 없음"
}

when의 강력한 기능들

KOTLIN
// 여러 값 매칭
when (x) {
    0, 1 -> println("0 또는 1")
    else -> println("기타")
}

// 범위 검사
when (score) {
    in 90..100 -> "A"
    in 80..89 -> "B"
    in 70..79 -> "C"
    else -> "F"
}

// 타입 검사
when (obj) {
    is String -> println("문자열 길이: ${obj.length}")  // 스마트 캐스트
    is Int -> println("정수 값: $obj")
    else -> println("알 수 없는 타입")
}

// 인자 없는 when (if-else 대체)
when {
    temperature > 30 -> println("더움")
    temperature > 20 -> println("적당")
    else -> println("추움")
}

자바 switch와의 차이점

특징Java switchKotlin when
Fall-through있음 (break 필요)없음
표현식 사용Java 14부터처음부터
타입 검사Java 17부터처음부터
범위 검사불가in 연산자
인자 없는 형태불가가능

자바와의 100% 호환

코틀린의 가장 큰 장점 중 하나는 자바와 완벽하게 호환된다는 점이다. 같은 JVM 위에서 돌아가기 때문에 가능한 일이다.

코틀린에서 자바 코드 호출

KOTLIN
// 자바 라이브러리를 그대로 사용
import java.util.ArrayList
import java.time.LocalDateTime

val list = ArrayList<String>()
list.add("코틀린에서 자바 컬렉션 사용")

val now = LocalDateTime.now()

자바에서 코틀린 코드 호출

KOTLIN
// 코틀린 파일: Utils.kt
fun greet(name: String): String {
    return "안녕, $name!"
}
JAVA
// 자바에서 호출
String result = UtilsKt.greet("자바");

코틀린 최상위 함수는 파일명Kt 클래스의 정적 메서드로 컴파일된다. @JvmStatic, @JvmOverloads 같은 어노테이션으로 자바 호출을 더 자연스럽게 만들 수 있다.

점진적 마이그레이션이 가능하다

PLAINTEXT
기존 자바 프로젝트
├── src/main/java/      ← 기존 자바 코드 유지
│   └── UserService.java
├── src/main/kotlin/    ← 새 코드는 코틀린으로
│   └── OrderService.kt

면접에서 "자바 프로젝트를 코틀린으로 전환한 경험이 있냐"는 질문이 나오면, 이 점진적 마이그레이션 전략을 설명하면 된다. 한 번에 전부 바꾸는 게 아니라, 새로운 코드부터 코틀린으로 작성하고 기존 자바 코드와 공존시키는 방식이다.

자바 개발자가 주의할 점

코틀린으로 넘어올 때 자주 실수하는 부분을 정리했다.

1. 세미콜론이 없다

KOTLIN
val name = "코틀린"    // 세미콜론 불필요

2. new 키워드가 없다

KOTLIN
val list = ArrayList<String>()   // new 없이 생성
val user = User("심정훈", 28)     // new 없이 생성

3. 기본 가시성이 public이다

KOTLIN
class User(val name: String)     // public이 기본
// 자바는 package-private가 기본

4. checked exception이 없다

KOTLIN
// 코틀린은 checked exception을 강제하지 않음
fun readFile(path: String): String {
    return File(path).readText()  // throws 선언 불필요
}

정리

코틀린은 자바의 장점을 유지하면서 단점을 개선한 언어다. 면접에서 핵심을 정리하면 이렇다.

  • val/var: val은 재할당 불가(≠ 불변), var는 재할당 가능
  • 타입 추론: 컴파일 타임에 타입이 결정되는 정적 타이핑
  • Nullable: ? 하나로 NPE를 컴파일 타임에 방지
  • String Template: $${}로 문자열 조합
  • when: fall-through 없는 강력한 패턴 매칭
  • 자바 호환: 같은 프로젝트에서 자바와 코틀린 공존 가능

자바를 이미 알고 있다면, 코틀린은 "더 적게 쓰고 더 안전한 코드"를 만드는 도구라고 생각하면 된다. 자바와 100% 호환되니까 부담 없이 시작해보자.

댓글 로딩 중...