본문 바로가기
  • Let's study
BackEnd/Kotlin

[Java → Kotlin] 자바 개발자를 위한 코틀린 문법 비교 ③ Kotlin의 주요 문법

by 코딩고수이고파 2026. 10. 7.

지난 글에서는 Java와 Kotlin의 null 처리, 람다 표현식, data class, 확장 함수, 기본 매개변수 등을 비교했다.

이번 글에서는 Java에서 자주 사용하는 Singleton, 문자열 템플릿, 예외 처리, switch문을 Kotlin에서는 어떻게 표현하는지 정리했다.

특히 Kotlin의 object, try 표현식, when은 Java와 비교했을 때 차이가 큰 문법이다.

1. 객체 Singleton

Singleton은 프로그램 전체에서 하나의 인스턴스만 생성되도록 하는 디자인 패턴이다.

Java에서는 일반적으로 private 생성자와 static 필드를 이용해 Singleton을 구현한다.

Kotlin에서는 object 키워드를 사용하면 Singleton 객체를 간단하게 만들 수 있다.

Java

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return INSTANCE;
    }

    public void showMessage() {
        System.out.println("Hello from Singleton!");
    }

    public static void main(String[] args) {
        Singleton.getInstance().showMessage();
    }
}

 

Java에서는 다음과 같은 과정을 직접 구현해야 한다.

  1. 외부에서 생성자를 호출하지 못하도록 private 생성자를 만든다.
  2. 하나의 인스턴스를 static으로 생성한다.
  3. getInstance()를 통해 해당 인스턴스를 반환한다.

Kotlin

Kotlin에서는 object를 사용하면 Singleton 객체를 만들 수 있다.

object Singleton {
    fun showMessage() {
        println("Hello, World!")
    }
}

fun main() {
    val a = Singleton
    val b = Singleton

    println(a == b)
}

 

object Singleton으로 선언한 객체는 하나의 인스턴스만 존재한다.

따라서 a와 b는 같은 객체를 가리키며 결과는 다음과 같다.

true

 

일반적인 class와 비교하면 차이를 확인할 수 있다.

class Test

object Singleton

fun main() {
    val a = Singleton
    val b = Singleton

    println(a == b) // true

    val t1 = Test()
    val t2 = Test()

    println(t1 == t2) // false
}

 

Test()는 호출할 때마다 새로운 객체가 생성되지만, Singleton은 하나의 객체만 사용한다.

즉, Kotlin에서는 Singleton을 구현하기 위해 별도의 static 필드나 getInstance() 메서드를 작성할 필요 없이 object 하나로 Singleton 객체를 선언할 수 있다.

2. 문자열 템플릿

Kotlin에서는 문자열 안에 변수나 표현식을 직접 넣을 수 있다.

이를 문자열 템플릿(String Template)이라고 한다.

Java에서는 문자열을 연결하기 위해 + 연산자를 사용하거나 String.format() 등을 사용할 수 있다.

Java

public class Main {
    public static void main(String[] args) {
        String name = "Alice";
        int age = 25;

        System.out.println(
            "My name is " + name + " and I am " + age + " years old."
        );
    }
}

Kotlin

fun main() {
    val name = "Alice"
    val age = 25

    println("My name is $name and I am $age years old.")
}

 

변수뿐만 아니라 표현식도 ${} 안에 작성할 수 있다.

fun main() {
    val name = "Alice"
    val age = 25

    println("이름은 ${name.length}글자이고, 나이는 ${age + 1}살이다.")
}

 

3. 예외 처리

Java와 Kotlin 모두 try-catch를 사용해 예외를 처리할 수 있다.

하지만 Kotlin은 Java와 달리 checked exception이 없다.

따라서 Java에서 사용하는 throws 선언을 Kotlin에서는 작성하지 않는다.

Java

public class Main {
    public static void main(String[] args) {
        try {
            copy("a.txt", "a_copy.txt");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void copy(
            String source,
            String target
    ) throws IOException {
        Files.copy(
            new File(source).toPath(),
            new File(target).toPath(),
            StandardCopyOption.REPLACE_EXISTING
        );
    }
}

 

Java에서는 IOException이 checked exception이기 때문에 메서드에 throws IOException을 작성해야 한다.

Kotlin

fun main() {
    Files.copy(
        File("a.txt").toPath(),
        File("a_copy.txt").toPath(),
        StandardCopyOption.REPLACE_EXISTING
    )
}

 

Kotlin에는 checked exception이 없기 때문에 throws IOException을 작성하지 않아도 된다.

필요한 경우 try-catch를 사용할 수 있다.

fun main() {
    try {
        Files.copy(
            File("a.txt").toPath(),
            File("a_copy.txt").toPath(),
            StandardCopyOption.REPLACE_EXISTING
        )
    } catch (e: IOException) {
        println("파일 복사에 실패했다.")
    }
}

try도 표현식으로 사용 가능

Kotlin의 try는 표현식으로 사용할 수 있기 때문에 결과를 변수에 대입할 수 있다.

val result = try {
    10 / 2
} catch (e: Exception) {
    0
}

println(result)

 

try 블록의 마지막 값이 결과가 되고, 예외가 발생하면 catch 블록의 값이 결과가 된다.

따라서 Kotlin에서는 try-catch를 단순한 예외 처리뿐만 아니라 값을 만들어내는 표현식으로도 사용할 수 있다.

4. when 문

Java의 switch와 비슷한 역할을 하는 Kotlin의 문법이 when이다.

Kotlin의 when은 Java의 switch보다 다양한 조건을 표현할 수 있으며, 결과를 변수에 바로 대입할 수도 있다.

Java

public class Main {
    public static void main(String[] args) {
        int day = 3;
        String dayName;

        switch (day) {
            case 1:
                dayName = "Monday";
                break;
            case 2:
                dayName = "Tuesday";
                break;
            case 3:
                dayName = "Wednesday";
                break;
            default:
                dayName = "Invalid Day";
        }

        System.out.println("Day: " + dayName);
    }
}

Java 14 이상

Java 14부터는 switch 표현식을 사용할 수 있어 Kotlin의 when과 비슷하게 작성할 수 있다.

public class Main {
    public static void main(String[] args) {
        int day = 3;

        String dayName = switch (day) {
            case 1 -> "Monday";
            case 2 -> "Tuesday";
            case 3 -> "Wednesday";
            default -> "Invalid Day";
        };

        System.out.println("Day: " + dayName);
    }
}

Kotlin

fun main() {
    val day = 3

    val dayName = when (day) {
        1 -> "Monday"
        2 -> "Tuesday"
        3 -> "Wednesday"
        else -> "Invalid Day"
    }

    println("Day: $dayName")
}

Kotlin의 when은 값을 반환할 수 있기 때문에 변수에 바로 대입할 수 있다.

또한 switch와 달리 break를 작성할 필요가 없다.

5. when은 여러 조건을 표현할 수 있다

when은 단순히 하나의 값을 비교하는 용도로만 사용하는 것이 아니다.

조건식을 직접 작성할 수도 있다.

fun main() {
    val score = 85

    val grade = when {
        score >= 90 -> "A"
        score >= 80 -> "B"
        score >= 70 -> "C"
        else -> "F"
    }

    println(grade)
}

Java의 switch가 특정 값이나 패턴을 기준으로 분기하는 데 주로 사용된다면, Kotlin의 when은 조건식 자체를 분기 기준으로 사용할 수 있다는 점이 특징이다.

6. Java와 Kotlin 비교 정리

이번 글에서 다룬 내용을 정리하면 다음과 같다.

기능 Java Kotlin
Singleton static, private 생성자 등 object
문자열 삽입 +, String.format() $변수, ${표현식}
Checked Exception 존재 없음
예외 선언 throws 사용 별도 선언 불필요
예외 처리 try-catch try-catch
예외 처리 결과 반환 별도 처리 try 표현식
switch switch when
분기 결과 대입 Java 14+ switch 표현식 가능 when 표현식

 

댓글