코틀린, 자바 와 비교 문법

1. 변수 선언: val vs var

Java에서는 변수의 타입을 먼저 명시했지만, Kotlin은 변수가 ‘변경 가능한지’ 여부를 먼저 결정합니다.

구분 Kotlin Java 설명
변경 불가능 (Immutable) val name: String = "Kotlin" final String name = "Java"; val (value): 한 번 할당되면 재할당 불가. Java의 final과 동일. 가장 기본적으로 사용 권장.
변경 가능 (Mutable) var age: Int = 10 int age = 10; var (variable): 재할당 가능.
타입 추론 val message = "Hello"

var count = 100

(Java 10+)var message = "Hello"; Kotlin은 변수 선언 시 할당되는 값을 보고 타입을 자동으로 추론합니다. 타입을 명시하지 않아도 됩니다.

Kotlin의 장점: val 사용을 기본으로 하여 불변성을 강제하므로, 코드의 안정성이 높아지고 예측 가능해집니다.


2. Null 안전성 (Null Safety)

Java에서 가장 악명 높은 NullPointerException (NPE)을 컴파일 시점에서 원천적으로 방지하는 Kotlin의 핵심 기능입니다.

구분 Kotlin Java 설명
Null 불허 (기본) var a: String = "abc"

a = null // 컴파일 에러!

String a = "abc";

a = null; // 가능

Kotlin의 모든 타입은 기본적으로 null을 허용하지 않습니다.
Null 허용 var b: String? = "abc"

b = null // 가능

String b = "abc"; 타입 뒤에 ? 를 붙여야만 null을 할당할 수 있습니다.
안전한 호출 b?.length if (b != null) { b.length(); } ?. (Safe Call): b가 null이 아니면 length를 호출하고, null이면 null을 반환합니다. NPE가 발생하지 않습니다.
Elvis 연산자 val l = b?.length ?: -1 int l = (b != null) ? b.length() : -1; ?: (Elvis Operator): 왼쪽 표현식이 null이 아니면 그 값을, null이면 오른쪽 값을 반환합니다. 3항 연산자를 대체합니다.
Null 아님 단언 val l = b!!.length (동일한 위험) b.length(); !! (Not-null Assertion): “b는 절대 null이 아니야!”라고 강제하는 연산자. 만약 b가 null이면 NPE가 발생합니다. 사용을 최소화해야 합니다.

Kotlin의 장점: NPE 발생 가능성을 컴파일러가 미리 체크해주므로, 런타임 안정성이 비약적으로 향상됩니다.


3. 함수 선언

더 간결하고 다양한 기능을 제공합니다.

구분 Kotlin Java
기본 함수 fun sum(a: Int, b: Int): Int { return a + b } public int sum(int a, int b) { return a + b; }
표현식 형태 fun sum(a: Int, b: Int) = a + b (해당 없음)
기본 인자 (Default Argument) fun greet(name: String = "Guest") { ... } (메서드 오버로딩 필요)
이름 있는 인자 (Named Argument) sum(b = 2, a = 1) (해당 없음)

Kotlin의 장점: 함수 오버로딩을 줄이고, 인자의 의미를 명확하게 전달할 수 있어 가독성이 높아집니다.


4. 데이터 클래스 (Data Class)

Java에서 Lombok 라이브러리를 써야 했던 getter, setter, equals(), hashCode(), toString()을 자동으로 만들어주는 마법 같은 기능입니다.

Kotlin Java (Lombok 없이)
data class User(val name: String, val age: Int) java<br>public class User {<br> private final String name;<br> private final int age;<br><br> public User(String name, int age) { ... }<br> public String getName() { ... }<br> public int getAge() { ... }<br> @Override public boolean equals(Object o) { ... }<br> @Override public int hashCode() { ... }<br> @Override public String toString() { ... }<br>}<br>

Kotlin의 장점: 단 한 줄로 데이터 모델을 정의할 수 있어, 엄청난 양의 보일러플레이트 코드를 줄여줍니다.


5. 스마트 캐스트 (Smart Casts)

타입을 한번 확인하면, 개발자가 다시 형변환(casting)할 필요 없이 컴파일러가 알아서 타입을 변환해 줍니다.

Kotlin Java
kotlin<br>fun process(obj: Any) {<br> if (obj is String) {<br> // obj는 자동으로 String 타입으로 취급됨<br> println(obj.length)<br> }<br>}<br> java<br>void process(Object obj) {<br> if (obj instanceof String) {<br> // 수동으로 형변환 필요<br> String str = (String) obj;<br> System.out.println(str.length());<br> }<br>}<br>

Kotlin의 장점: 불필요한 형변환 코드를 제거하여 코드를 깔끔하고 안전하게 만듭니다.


6. 확장 함수 (Extension Functions)

기존 클래스의 소스 코드를 수정하지 않고도 새로운 함수를 추가할 수 있는 기능입니다.

예시: String 클래스에 마지막 글자를 가져오는 함수 추가

Kotlin Java
kotlin<br>// String 클래스를 확장<br>fun String.lastChar(): Char = this.get(this.length - 1)<br><br>// 사용<br>val last = "abc".lastChar() // 결과: 'c'<br> java<br>// 별도의 유틸리티 클래스 필요<br>class StringUtils {<br> public static char lastChar(String str) {<br> return str.charAt(str.length() - 1);<br> }<br>}<br><br>// 사용<br>char last = StringUtils.lastChar("abc");<br>

Kotlin의 장점: 마치 원래 그 클래스에 있던 메서드처럼 자연스럽게 사용할 수 있어, 코드 가독성과 재사용성을 높입니다.


그 외 주요 차이점

  • 세미콜론(;): Kotlin에서는 문장 끝에 세미콜론을 붙이지 않아도 됩니다.
  • Checked Exceptions: Kotlin은 Java의 try-catch를 강제하는 Checked Exception을 사용하지 않습니다.
  • 100% 상호운용성: Kotlin 코드에서 Java 클래스를, Java 코드에서 Kotlin 클래스를 아무 제약 없이 호출할 수 있습니다. 기존 Java 프로젝트에 점진적으로 Kotlin을 도입할 수 있는 이유입니다.

이처럼 Kotlin은 Java 개발자들이 겪었던 여러 불편한 점들을 언어 차원에서 해결하여, 더 안전하고, 간결하며, 생산성 높은 코드를 작성할 수 있도록 돕습니다. Java에 익숙하시다면 금방 배우고 그 매력에 빠지실 수 있을 겁니다.