자바(Java) 개발자가 코틀린(Kotlin)으로 전환하거나, 두 언어를 병행해서 사용할 때 반드시 알아야 할 주요 차이점과 실수하기 쉬운 포인트를 상세히 정리했습니다.

실무에서 겪을 수 있는 다양한 사례와 함께, 코틀린의 장점을 최대한 활용하는 방법을 초보자도 이해할 수 있도록 설명합니다.

코틀린 도입 배경과 자바와의 관계

코틀린은 JetBrains에서 개발한 JVM 기반 언어로, 자바와 100% 호환되며 현대적인 문법과 간결함, 안전성을 제공합니다. 자바 개발자라면 기존 자바 코드와 코틀린 코드를 함께 사용할 수 있고, 점진적으로 마이그레이션할 수 있다는 점이 큰 장점입니다. 하지만 자바와 코틀린은 문법적, 철학적으로 여러 차이가 있으므로, 단순히 “자바를 더 짧게 쓸 수 있는 언어”로만 접근하면 예상치 못한 문제에 부딪힐 수 있습니다.

1. Null 안전성(null-safety)과 Nullable 타입

자바에서 가장 흔한 오류 중 하나는 NullPointerException(NPE)입니다. 코틀린은 타입 시스템 차원에서 null을 다루기 때문에, 변수 선언 시 null 허용 여부를 명확히 구분해야 합니다. 예를 들어, var name: String?은 null을 허용하고, var name: String은 null을 허용하지 않습니다. 이로 인해 컴파일 타임에 많은 오류를 사전에 방지할 수 있지만, 자바와 혼용 시에는 플랫폼 타입(Platform Type, String!)이 등장하여 주의가 필요합니다. 자바 코드에서 넘어온 값은 null-safety가 완전히 보장되지 않으므로, 반드시 null 체크를 추가하거나, @NonNull, @Nullable 어노테이션을 활용해야 합니다.

2. 데이터 클래스와 equals/hashCode, toString 자동 생성

코틀린의 data class는 자바의 POJO/VO와 달리, equals, hashCode, toString, copy, componentN 함수 등을 자동으로 생성해줍니다. 자바에서 Lombok을 쓰던 습관으로 코틀린에서도 별도의 어노테이션을 붙이려는 실수를 할 수 있는데, 코틀린에서는 data class만 선언하면 모든 기능이 자동으로 제공됩니다. 다만, 상속이 불가능하고, 모든 주 생성자 파라미터에 val/var가 붙어야 한다는 점에 유의해야 합니다.

3. 함수 선언과 람다식, 고차함수

코틀린은 함수형 프로그래밍을 적극적으로 지원합니다. 람다식 문법이 간결하고, 함수 자체를 변수처럼 전달할 수 있습니다. 자바 8의 람다와는 다르게, 코틀린에서는 trailing lambda, 익명 함수, 고차함수 등 다양한 패턴이 자연스럽게 사용됩니다. 특히 Collection API에서 forEach, map, filter, reduce 등 함수형 스타일을 적극 활용할 수 있습니다. 자바에 익숙한 개발자라면, 코틀린의 람다와 고차함수 문법을 익히는 것이 중요합니다.

4. 프로퍼티(Property)와 Getter/Setter

코틀린에서는 필드와 프로퍼티, getter/setter를 별도로 작성하지 않아도 됩니다. 변수 선언만으로 자동으로 getter/setter가 생성되며, 필요할 경우 커스텀 구현도 가능합니다. 자바처럼 getName()/setName()을 직접 작성할 필요가 없고, 프로퍼티 접근이 자연스럽습니다. 단, 자바와의 상호운용성을 고려할 때는 @JvmField, @JvmName, @JvmStatic 등의 어노테이션을 적절히 활용해야 합니다.

5. 기본값, 명명 인자, 가변 인자

코틀린은 함수 파라미터에 기본값(default value)을 지정할 수 있고, 명명 인자(named argument)로 호출이 가능합니다. 또한, 가변 인자(vararg)도 지원합니다. 자바에서는 오버로딩으로 처리하던 부분을 코틀린에서는 함수 한 개로 간결하게 표현할 수 있습니다. 하지만 자바에서 코틀린 함수를 호출할 때는 명명 인자, 기본값이 적용되지 않으므로, 반드시 오버로딩 함수(@JvmOverloads)를 추가로 생성해야 할 수 있습니다.

6. 클래스 상속, Sealed 클래스, object 선언

코틀린에서는 클래스가 기본적으로 final이므로, 상속을 허용하려면 open 키워드를 붙여야 합니다. 또한, Sealed class(봉인 클래스)는 상태 패턴, 타입 제한 등에 매우 유용하며, enum보다 더 강력한 표현이 가능합니다. 싱글턴 객체는 object 키워드로 간단하게 선언할 수 있습니다. 자바에서의 상속/구현 패턴과 차이가 있으므로, 설계 시 주의가 필요합니다.

7. 스마트 캐스트와 타입 추론

코틀린은 타입 추론(type inference)이 강력하며, 조건문(if, when)에서 자동으로 타입이 변환(smart cast)됩니다. 자바에서는 명시적 캐스팅이 필요하지만, 코틀린은 안전하게 타입을 변환해줍니다. 단, var로 선언된 변수나 커스텀 getter가 있는 경우에는 스마트 캐스트가 적용되지 않을 수 있으니 주의해야 합니다.

8. 예외 처리와 Checked Exception

코틀린은 Checked Exception을 지원하지 않습니다. 즉, 함수 선언 시 throws를 명시하지 않아도 되고, try-catch로 반드시 감쌀 필요도 없습니다. 자바와 혼용 시에는 자바에서 발생하는 Checked Exception을 코틀린에서 제대로 처리하지 못할 수 있으므로, 예외 발생 가능성이 있는 부분은 문서화하거나, 별도의 예외 래핑 처리가 필요합니다.

9. 확장 함수와 확장 프로퍼티

코틀린의 확장 함수(extension function)는 기존 클래스에 새로운 기능을 추가할 수 있게 해줍니다. 자바에서는 불가능한 패턴이므로, 코틀린의 강력한 장점입니다. 예를 들어 String에 새로운 함수를 추가하거나, View에 커스텀 동작을 쉽게 확장할 수 있습니다. 단, 확장 함수는 실제로 클래스 내부를 수정하는 것이 아니라, 정적(static) 함수로 동작하므로, 멤버 변수에는 접근할 수 없습니다.

10. 컬렉션 불변/가변 구분 및 표준 라이브러리

코틀린의 List, Set, Map 등 컬렉션은 불변(immutable)과 가변(mutable)이 명확히 구분됩니다. listOf는 불변 리스트, mutableListOf는 가변 리스트입니다. 자바와 달리, 컬렉션 API가 매우 풍부하고, 함수형 스타일을 적극 지원합니다. 자바에서 넘어온 컬렉션을 사용할 때는 타입 변환과 null-safety에 주의해야 하며, 코틀린 표준 라이브러리를 적극 활용하는 것이 좋습니다.

11. 동시성: 코루틴과 스레드

코틀린은 코루틴(coroutine)이라는 경량 비동기 프로그래밍 모델을 제공합니다. 자바의 Thread, Future, ExecutorService와는 다르게, 코루틴은 코드가 간결하고, 자원 소모가 적으며, 비동기 로직을 동기처럼 작성할 수 있습니다. 코루틴을 처음 접하는 자바 개발자라면, launch, async, suspend, runBlocking 등 코루틴의 기본 개념과 문법을 반드시 익혀야 하며, 코루틴 스코프와 예외 처리, 디스패처(Dispatcher) 사용법도 함께 학습해야 합니다.

12. 어노테이션과 리플렉션, 자바와의 상호운용성

코틀린은 자바와 100% 호환되지만, 어노테이션 처리, 리플렉션, 제네릭 타입 등에서 미묘한 차이가 발생할 수 있습니다. 예를 들어, 코틀린의 제네릭은 JVM 타입 소거(type erasure)와 관련된 이슈가 있을 수 있고, 어노테이션 프로세서(KAPT) 사용법이 다릅니다. 자바 라이브러리를 코틀린에서 쓸 때는 공식 문서와 마이그레이션 가이드를 반드시 참고해야 합니다.

13. 기타 실무에서 자주 겪는 Pitfall

  • 자바에서 코틀린으로 자동 변환 시(IDE 지원) 코드가 완벽하게 변환되지 않을 수 있음
  • lateinit, by lazy 등 코틀린 고유의 초기화 패턴을 잘못 사용할 경우 NPE 발생 가능
  • Companion object, top-level 함수 등 자바에는 없는 개념이 있으므로, 빌드/배포 시 주의
  • 자바 static import와 코틀린 import의 차이
  • 자바에서 코틀린 클래스를 호출할 때, getter/setter, companion object 접근 방식 차이
  • 빌드 도구(Gradle, Maven)에서 코틀린 플러그인, kapt 설정 등 추가 작업 필요

결론 및 마이그레이션 팁

코틀린은 자바 개발자에게 매우 매력적인 언어이지만, 단순히 문법만 익히는 것에 그치지 않고, 코틀린의 철학과 장점을 충분히 이해하는 것이 중요합니다. 특히 Null-safety, 함수형 프로그래밍, 코루틴 등 코틀린 고유의 기능을 적극적으로 활용하면, 더 안전하고 생산적인 코드를 작성할 수 있습니다. 마이그레이션 시에는 점진적으로 도입하고, 자바와의 상호운용성을 항상 고려해야 하며, 공식 문서와 레퍼런스를 자주 참고하는 습관을 들이는 것이 좋습니다.

참고할 만한 레퍼런스

코틀린의 진정한 장점을 누리기 위해서는 자바와의 차이점을 명확히 이해하고, 실무에서 자주 발생하는 이슈를 미리 파악하는 것이 중요합니다. 점진적 도입과 학습을 통해 더 나은 개발 경험을 만들어보세요!