Backend
home
🎯

Kotlin 기본 문법 완전 정복 + 알고리즘 실전 노하우

생성 일시
2026/04/09 10:39
태그
Kotlin
게시일
2026/04/09
최종 편집 일시
2026/04/09 10:39
GitHub 링크

들어가며

Kotlin은 JetBrains가 만든 JVM 기반 언어로, 2017년 Google I/O에서 Android 공식 언어로 채택된 이후 백엔드 서버 개발에서도 빠르게 확산되고 있다. Java와 100% 상호 운용이 가능하면서도, 훨씬 간결하고 표현력 있는 문법을 제공한다.
이 글에서는 Kotlin의 핵심 문법을 실무·알고리즘 관점에서 정리하고, 코딩 테스트에서 바로 쓸 수 있는 노하우를 함께 담았다.

1. 변수 선언: val vs var

val name: String = "Kotlin" // 불변 (Java의 final) var count: Int = 0 // 가변 // 타입 추론: 명시 생략 가능 val pi = 3.14 var score = 100
Kotlin
복사
노하우: 알고리즘 풀이 시 val을 기본으로 쓰고, 값이 바뀌어야 할 때만 var로 변경. 의도하지 않은 값 변경 버그를 컴파일 타임에 잡을 수 있다.

2. Null 안전성 (Null Safety)

Kotlin의 타입 시스템은 null 가능 여부를 타입에 명시한다.
var a: String = "hello" // a = null // 컴파일 에러 var b: String? = "world" b = null // OK // 안전 호출 연산자 ?. val length = b?.length // b가 null이면 null 반환 // 엘비스 연산자 ?: val len = b?.length ?: 0 // null이면 0 반환 // 단언 연산자 !! (null이면 NPE 발생 — 꼭 필요한 경우만) val forced = b!!
Kotlin
복사
노하우: 알고리즘에서 맵 조회 결과에 ?: 0 또는 ?: -1을 붙이는 패턴을 자주 쓴다. map[key] ?: 0으로 기본값을 한 줄에 처리할 수 있다.

3. 함수 선언

// 기본 함수 fun add(a: Int, b: Int): Int { return a + b } // 단일 표현식 함수 fun multiply(a: Int, b: Int) = a * b // 기본값 매개변수 fun greet(name: String, greeting: String = "Hello") = "$greeting, $name!" // 명명된 인수 greet(name = "Kotlin", greeting = "Hi")
Kotlin
복사

4. 컬렉션과 함수형 API

Kotlin 컬렉션은 listOf, mutableListOf, mapOf, setOf 등으로 생성하며, Java Stream 없이도 강력한 함수형 처리가 가능하다.
val numbers = listOf(3, 1, 4, 1, 5, 9, 2, 6) // 필터 + 변환 + 합산 val result = numbers .filter { it > 3 } .map { it * 2 } .sum() // 40 // groupBy: 알고리즘에서 빈도 계산에 유용 val freq = numbers.groupBy { it } // Map<Int, List<Int>> val countMap = numbers.groupingBy { it }.eachCount() // Map<Int, Int> // sorted / sortedBy val sorted = numbers.sortedDescending() val words = listOf("banana", "apple", "cherry") val byLength = words.sortedBy { it.length }
Kotlin
복사
노하우: groupingBy { }.eachCount()는 코딩 테스트에서 빈도수 맵을 한 줄로 만들 때 최고다. Java의 HashMap + getOrDefault 조합보다 훨씬 깔끔하다.

5. 데이터 클래스 (data class)

data class Point(val x: Int, val y: Int) val p1 = Point(1, 2) val p2 = p1.copy(y = 10) // 불변 복사 println(p1 == Point(1, 2)) // true (구조적 동등성) println(p1) // Point(x=1, y=2)
Kotlin
복사
equals(), hashCode(), toString(), copy()가 자동 생성된다.
노하우: 알고리즘에서 좌표, 상태 등을 data class로 정의하면 Set이나 Map의 키로 바로 쓸 수 있다. Java였으면 equals/hashCode를 직접 오버라이드해야 했던 것을 자동 처리한다.
val visited = mutableSetOf<Point>() visited.add(Point(0, 0)) visited.contains(Point(0, 0)) // true
Kotlin
복사

6. 확장 함수 (Extension Function)

기존 클래스를 수정하지 않고 새 함수를 추가하는 Kotlin의 킬러 기능이다.
fun Int.factorial(): Long { var result = 1L for (i in 2..this) result *= i return result } println(10.factorial()) // 3628800 // 알고리즘: IntArray에 swap 추가 fun IntArray.swap(i: Int, j: Int) { val tmp = this[i]; this[i] = this[j]; this[j] = tmp } val arr = intArrayOf(3, 1, 2) arr.swap(0, 2) // [2, 1, 3]
Kotlin
복사

7. when 표현식

Java switch의 강화판. 값, 범위, 타입 체크까지 처리한다.
fun grade(score: Int): String = when { score >= 90 -> "A" score >= 80 -> "B" score >= 70 -> "C" else -> "F" } // 타입 체크 fun describe(obj: Any): String = when (obj) { is Int -> "정수: $obj" is String -> "문자열 길이: ${obj.length}" is List<*> -> "리스트 크기: ${obj.size}" else -> "알 수 없음" }
Kotlin
복사

8. 구조 분해 (Destructuring)

val (x, y) = Point(3, 7) // 맵 순회 val map = mapOf("a" to 1, "b" to 2) for ((key, value) in map) { println("$key -> $value") } // 인덱스와 값 동시 접근 val list = listOf("x", "y", "z") for ((index, value) in list.withIndex()) { println("$index: $value") }
Kotlin
복사
노하우: withIndex()는 알고리즘에서 인덱스가 필요한 순회 시 Java의 for (int i = 0; ...) 루프를 대체한다.

9. 알고리즘 실전 패턴 모음

BFS 탬플릿

import java.util.LinkedList fun bfs(graph: Array<IntArray>, start: Int): IntArray { val dist = IntArray(graph.size) { -1 } val queue = LinkedList<Int>() dist[start] = 0 queue.add(start) while (queue.isNotEmpty()) { val cur = queue.poll() for (next in graph[cur]) { if (dist[next] == -1) { dist[next] = dist[cur] + 1 queue.add(next) } } } return dist }
Kotlin
복사

우선순위 큐 (최소 힙)

import java.util.PriorityQueue // 기본: 오름차순 val minHeap = PriorityQueue<Int>() // 내림차순 (최대 힙) val maxHeap = PriorityQueue<Int>(compareByDescending { it }) // 커스텀 정렬: (거리, 노드) val dijkstra = PriorityQueue<Pair<Int, Int>>(compareBy { it.first }) dijkstra.add(Pair(0, start))
Kotlin
복사

2D 배열 초기화

// 크기 n×m, 0으로 초기화 val dp = Array(n) { IntArray(m) { 0 } } // 특정 값으로 초기화 val inf = Array(n) { IntArray(m) { Int.MAX_VALUE / 2 } }
Kotlin
복사

입출력 빠르게 처리하기

import java.io.BufferedReader import java.io.InputStreamReader import java.util.StringTokenizer fun main() { val br = BufferedReader(InputStreamReader(System.`in`)) val sb = StringBuilder() val (n, m) = br.readLine().split(" ").map { it.toInt() } repeat(n) { val st = StringTokenizer(br.readLine()) val a = st.nextToken().toInt() val b = st.nextToken().toInt() sb.appendLine(a + b) } print(sb) }
Kotlin
복사
노하우: println() 반복 호출은 느리다. StringBuilder에 결과를 모아 마지막에 한 번 print(sb)로 출력하는 습관을 들이자. 입력은 BufferedReader + StringTokenizerreadLine().split() 조합보다 빠르다.

10. Java와 Kotlin 문법 비교 요약

기능
Java
Kotlin
불변 변수
final int x = 1
val x = 1
Null 체크
if (s != null)
s?.length ?: 0
데이터 객체
@Data (Lombok)
data class
문자열 보간
"Hello " + name
"Hello $name"
타입 체크
instanceof
is
삼항 연산자
a > b ? a : b
if (a > b) a else b
반복 범위
for (int i=0; i<n; i++)
for (i in 0 until n)

마무리

Kotlin은 문법 자체가 알고리즘 풀이에 유리하게 설계되어 있다. val/var 구분, Null 안전성, 강력한 컬렉션 API, data class의 자동 구현 등이 모두 버그를 줄이고 코드를 짧게 만들어준다.
처음엔 Java 문법에 Kotlin 특성을 하나씩 얹는 방식으로 익히고, 익숙해지면 함수형 API와 확장 함수를 적극 활용해보자. 같은 로직을 Java와 Kotlin으로 번갈아 짜보는 것도 빠른 학습법이다.

참고 문서