임도현의 성장
[Kotlin] 코틀린 기본 문법 본문

📚 Kotlin - 변수(Variables)
Kotlin에서 변수를 선언할 때는 var
또는 val
키워드를 사용해야 합니다.
var
: 변경 가능한 변수 (mutable)val
: 변경 불가능한 변수 (immutable)
💡 Kotlin은 타입 추론(Type Inference)을 지원하기 때문에 타입을 명시하지 않아도 컴파일러가 타입을 자동으로 추론합니다.
코틀린 코드
var number1 = 10L // 타입을 명시하지 않아도 Long 타입으로 추론
val number2: Long = 10L // 타입을 명시적으로 선언
var number3: Long? = 1_000L // null이 허용되는 변수는 타입 뒤에 `?`를 붙입니다.
number3 = null // null 할당 가능
var person = Person("임도현") // 객체 생성 시 `new` 키워드를 사용하지 않습니다.
자바 코드
long number1 = 10L;
final long number2 = 10L;
Long number3 = 1_000L;
Person person = new Person("최태현");
❗ 참고사항
- Null 허용:
타입?
형태로 선언하면 해당 변수는null
을 가질 수 있습니다. Kotlin에서는null
가능성과 불가능성을 타입 시스템 수준에서 구분합니다. - new 키워드 생략: Kotlin에서는 객체를 생성할 때
new
키워드를 사용하지 않습니다.
📚 Kotlin - Null 다루기 Safe Call, Elvis 연산자
Kotlin에서는 null 안정성(Null Safety)을 언어 차원에서 지원합니다.
즉, 컴파일 타임에 null 가능성을 체크해주기 때문에 NullPointerException(NPE) 발생 가능성을 크게 줄일 수 있습니다.
💡 Java에서는 런타임까지 가야 NPE가 터지지만, Kotlin은 아예 코드 작성 단계에서 null 여부를 관리합니다.
✏️ 기본 예제
fun main() {
// Kotlin에서는 null이 가능한 타입을 명시적으로 선언해야 합니다
val str: String? = "ABC"
println(str?.length)
// Safe Call (`?.`) : str이 null이 아니면 length 호출, null이면 그냥 null 반환
val str2: String? = "ABC"
println(str2?.length ?: 0)
// Elvis 연산자 (`?:`) : 앞이 null이면 뒤에 지정한 기본값(0)을 반환
}
✏️ 다양한 Null 처리 방식 예제 함수들
fun startWithA1(str: String?): Boolean {
// null이면 예외를 던짐
return str?.startsWith("A") ?: throw IllegalArgumentException("null이 들어왔습니다")
}
fun startsWithA2(str: String?): Boolean? {
// null이면 null 반환
return str?.startsWith("A")
}
fun startsWithA3(str: String?): Boolean {
// null이면 false 반환
return str?.startsWith("A") ?: false
}
fun startWith(str: String?): Boolean {
// 절대 null이 아님을 확신할 때 `!!` 사용 (주의: 런타임 NPE 발생 가능성 있음)
return str!!.startsWith("A")
}
✏️ 자바 코드
public boolean startsWithA1(String str) {
if (str == null) {
throw new IllegalArgumentException("null이 들어왔습니다");
}
return str.startsWith("A");
}
public Boolean startsWithA2(String str) {
if (str == null) {
return null;
}
return str.startsWith("A");
}
public boolean startsWithA3(String str) {
if (str == null) {
return false;
}
return str.startsWith("A");
}
✅ Kotlin으로 변환할 때 장점
- 코드가 훨씬 짧고 읽기 쉽다
→ if문으로 null 체크하는 코드가 사라지고?.
,?:
같은 표현식으로 깔끔하게 작성 가능 - Null 안전성이 강화된다
→ 컴파일 단계에서 null 가능성을 체크해주기 때문에 런타임 에러를 줄일 수 있다 - 표현이 의도에 더 직관적이다
→!!
,?.
,?:
를 통해 개발자의 의도를 코드에 명확하게 드러낼 수 있다 - Elvis 연산자(
?:
) 덕분에 기본값 처리도 쉬워진다
🏷️ 요약
?.
(Safe Call) : null이 아닐 때만 메서드 호출?:
(Elvis 연산자) : null일 때 기본값을 반환!!
(Not-Null 단정) : 무조건 null이 아님을 보장 (주의해서 사용!)- Kotlin은 NullPointerException을 예방하기 위한 다양한 안전장치를 제공한다.
📚 Kotlin - 3가지 타입
Kotlin의 특이한 3가지 타입 Any - Unit - Nothing
1️⃣ Any
- Kotlin의 모든 타입의 최상위 타입입니다. (
Java
의Object
와 비슷) Any
타입에는equals()
,hashCode()
,toString()
메서드가 기본적으로 정의되어 있습니다.- 기본적으로
null
을 포함할 수 없습니다.
→null
을 허용하려면Any?
로 선언해야 합니다.
예시
fun printAgeIfPerson(obj: Any) {
if (obj is Person) { // obj가 Person 타입이라면
val person = obj as Person // 명시적 타입 캐스팅 obj에 Person객체가 들어감
println(person.age)
}
// 또는 스마트 캐스트로 더 간단하게 작성 가능
if (obj is Person) {
println(obj.age)
}
}
fun printAgeIfPerson2(obj: Any?) {
val person = obj as? Person // 안전한 캐스팅 (null 가능) Person객체가 null이면 null반환
println(person?.age)
}
💬 스마트 캐스트
if (obj is Person)
과 같이 타입 체크를 하면 Kotlin이 자동으로 타입 캐스팅을 해줍니다.as?
를 사용하면 타입이 다르거나 null이어도 예외 없이null
을 반환합니다.
2️⃣ Unit
- Kotlin에서
Unit
은 Java의void
와 비슷한 역할을 합니다. - 하지만 Java의
void
는 타입이 아예 없지만, Kotlin의Unit
은 진짜 존재하는 타입입니다. - 함수가 아무 값도 반환하지 않을 때 반환 타입으로 사용합니다.
Unit
은 단 하나의 인스턴스만 존재합니다 (object
처럼).
예시
fun printHello(): Unit { // Unit은 반환 타입을 적지 않으면 자동으로 Unit이 들어감
println("Hello, Kotlin!")
}
fun printHello() { // : Unit 생략 가능
println("Hello, Kotlin!")
}
// Unit을 타입 인자로 사용할 수도 있음
val func: () -> Unit = { println("Lambda function!") }
💬 함수형 프로그래밍에서 Unit의 의미
→ 단 하나의 값만 갖는 타입을 의미합니다. (void
와는 개념이 다름)
3️⃣ Nothing
Nothing
은 정상적으로 값을 반환하지 않는 함수를 표현할 때 사용합니다.- 예외를 던지는 함수나 무한 루프를 도는 함수가 여기에 해당합니다.
Nothing
은 어떤 값도 가질 수 없으며, 모든 타입의 하위 타입입니다.
예시
fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}
fun infiniteLoop(): Nothing {
while (true) {
// 무한 루프
}
}
💬 Nothing은 언제 사용할까?
- 함수가 절대 정상 종료되지 않을 때
- 코드를 더 명확하게 표현하고 싶을 때
(예: 무조건 예외를 발생시키는 유틸 함수)
✅ 요약
타입 | 설명 |
---|---|
Any |
모든 타입의 최상위 타입. Object 처럼 동작하지만 null을 포함하지 않음 (Any? 필요) |
Unit |
반환값이 없는 함수에서 사용. 실제 존재하는 타입 (단 하나의 인스턴스) |
Nothing |
정상 종료되지 않는 함수에서 사용. 예외 발생 또는 무한 루프 등에 사용 |
📚 Kotlin - 연산자 정리
Kotlin은 기본적인 연산자 사용법이 Java와 매우 유사합니다.
하지만, 객체에 대해서도 연산자 오버로딩(Operator Overloading) 을 지원해서 더욱 자연스럽게 사용할 수 있습니다.
1️⃣ 기본 연산자
- 단항 연산자 (
+
,-
,++
,--
,!
) - 산술 연산자 (
+
,-
,*
,/
,%
) - 산술 대입 연산자 (
+=
,-=
,*=
,/=
,%=
) - 비교 연산자 (
>
,<
,>=
,<=
,==
,!=
)
✅ 모두 Java와 사용법이 동일합니다!
2️⃣ 비교 연산자와 compareTo
Kotlin에서는 객체끼리 비교할 때 비교 연산자(>
, <
, >=
, <=
)를 사용할 수 있습니다.
- 비교 연산자를 사용하면 자동으로
compareTo
메서드를 호출합니다. compareTo
는 Kotlin에서 Comparable 인터페이스를 구현하면 됩니다. (Java와 비슷)
예제
fun main() {
val money1 = JavaMoney(2_000L)
val money2 = JavaMoney(1_000L)
// 객체 비교: 자동으로 compareTo() 호출
if (money1 > money2) {
println("money1이 money2보다 큽니다.")
}
}
JavaMoney 클래스 (Java)
public class JavaMoney implements Comparable<JavaMoney> {
private final long amount;
public JavaMoney(long amount) {
this.amount = amount;
}
public JavaMoney plus(JavaMoney other) {
return new JavaMoney(this.amount + other.amount);
}
@Override
public int compareTo(JavaMoney o) {
return Long.compare(this.amount, o.amount);
}
// equals, hashCode, toString 생략
}
💬 비교 연산자를 객체에도 사용할 수 있다는 것!
money1 > money2
→ 내부적으로money1.compareTo(money2) > 0
호출
3️⃣ 동일성(===)과 동등성(==)
Kotlin에서는 ==
와 ===
가 구분되어 있습니다.
연산자 | 의미 | Java 대응 |
---|---|---|
== |
동등성 (equals 호출) | equals() |
=== |
동일성 (참조 비교) | == (주소값 비교) |
예제
fun main() {
val money3 = JavaMoney(1_000L)
val money4 = money3
val money5 = JavaMoney(1_000L)
println(money3 === money4) // true (같은 객체)
println(money3 == money5) // true (값이 같음, equals 호출)
}
💬 Kotlin에서
==
을 사용하면 자동으로equals()
를 호출합니다.
반면에===
은 참조(주소)를 비교합니다.
4️⃣ 연산자 오버로딩 (+)
Kotlin에서는 연산자 오버로딩을 통해, 객체끼리 +
, -
같은 연산자를 직접 사용할 수 있습니다.
- 객체에
plus
함수를 정의하면+
연산자를 사용할 수 있습니다.
예제
fun main() {
val money1 = JavaMoney(2_000L)
val money2 = JavaMoney(1_000L)
println(money1.plus(money2)) // 일반 호출
println(money1 + money2) // 연산자 호출 (plus 자동 연결)
}
✅ 요약
구분 | 설명 |
---|---|
기본 연산자 | Java와 사용법 동일 (+ , - , * , / , % ) |
객체 비교 | 비교 연산자 사용 시 compareTo 자동 호출 |
동일성/동등성 | === (동일성, 주소 비교), == (동등성, equals 호출) |
연산자 오버로딩 | plus , minus 등의 메서드를 통해 + , - 연산 가능 |
📌 정리
코틀린에서는
- 객체끼리도 자연스럽게
>
,<
같은 비교 연산 가능 ==
를 쓰면 자동으로 equals() 호출+
연산자도 오버로딩해서 객체끼리 덧셈 지원 가능
덕분에 더 직관적이고 간결한 코드 작성이 가능합니다! 🚀
📚 Kotlin - if문
, when문
정리
Kotlin은 Java와 비교해서 제어문(if
, when
)을 훨씬 간결하고 표현력 있게 사용할 수 있습니다.
특히 Kotlin에서는 if문과 when문이 "Expression(표현식)" 이라는 점이 큰 특징입니다.
1️⃣ Kotlin의 if문
- Kotlin의
if문
은 Java와 문법이 거의 동일합니다. - if문 자체가 Expression이다.
- 값처럼 사용할 수 있어서 삼항 연산자(조건 ? A : B) 가 따로 존재하지 않는다!
✅ Kotlin if문 예시
fun getPassOrFail(score: Int): String {
return if (score >= 50) {
"P"
} else {
"F"
}
}
if
블록이 끝나면 그 결과가 반환되어 바로return
이 가능!
✅ Kotlin 다중 조건 if문 예시
fun getGrade(score: Int): String {
return if (score >= 90) {
"A"
} else if (score >= 80) {
"B"
} else if (score >= 70) {
"C"
} else {
"D"
}
}
2️⃣ Kotlin의 when문
- Java의
switch문
을 Kotlin에서는when문
으로 대체합니다. when문
역시 Expression입니다! (결과를 반환 가능)when
은 값 뿐만 아니라 조건식도 받을 수 있다.
✅ Kotlin when 기본 사용
fun getGradeWithSwitch(score: Int): String {
return when (score / 10) {
in 9..10 -> "A" // // 90 ~ 99 까지이면 A출력
in 8..9 -> "B"
in 7..8 -> "C"
else -> "D"
}
}
✅ Kotlin when 타입 체크 사용
fun startWithA(obj: Any): Boolean {
return when (obj) {
is String -> obj.startsWith("A") // // obj가 String 이면 startsWith 검사 아니면 false 반환
else -> false
}
}
💬
is
키워드를 통해 타입 체크도 자연스럽게 가능!
3️⃣ Java vs Kotlin 비교
🔥 Java 코드 (if문)
private void judgeNumber2(int number) {
if (number == 0) {
System.out.println("주어진 숫자는 0입니다");
return;
}
if (number % 2 == 0) {
System.out.println("주어진 숫자는 짝수입니다");
return;
}
System.out.println("주어지는 숫자는 홀수입니다");
}
🔥 Kotlin 코드 (when문)
fun judgeNumber2(number: Int) {
when {
number == 0 -> println("주어진 숫자는 0입니다.")
number % 2 == 0 -> println("주어진 숫자는 짝수입니다.")
else -> println("주어지는 숫자는 홀수입니다.")
}
}
💬 Kotlin은 when 블록을 이용해 여러 조건을 자연스럽게 분기할 수 있다.
따로return
을 안 써도, 순차적으로 평가되어 필요한 블록만 실행!
✅ 요약
구분 | Kotlin 특징 |
---|---|
if문 | Expression(값처럼 사용 가능) |
삼항 연산자 | 존재하지 않음 (if로 대체) |
when문 | switch문을 대체, 더 강력한 기능 |
when문 특징 | 값뿐만 아니라, 타입 체크, 조건식까지 사용 가능 |
다중 조건 | when으로 깔끔하게 분기 가능 |
📌 정리
- Kotlin의
if문
,when문
은 값을 반환하는 Expression이다! - 삼항 연산자 없이 if를 값처럼 사용할 수 있다.
- when문은 switch보다 더 강력하며, 타입 체크나 범위 조건까지 지원한다.
- Java에 비해 코드가 훨씬 간결하고 명확해진다.
Kotlin은 "모든 것이 Expression"이라는 설계 철학 덕분에, 더 깔끔하고 함수형 스타일 코드를 작성할 수 있습니다! 🚀
📚 Kotlin - 반복문 (for문, for-each문, while문) 정리
Kotlin은 반복문을 Java보다 더 간결하고 직관적으로 표현할 수 있습니다.
특히 in
키워드와 등차수열(range) 을 이용해 편리하게 사용할 수 있어요.
1️⃣ Kotlin의 for-each문
- Java에서는
:
을 사용하지만, Kotlin에서는in
키워드를 사용합니다.
✅ Kotlin for-each문 예시
fun main() {
val numbers = listOf(1L, 2L, 3L)
for (number in numbers) {
println(number)
}
}
💬
in
을 통해 컬렉션의 요소를 순회합니다.
2️⃣ Kotlin의 전통적인 for문
- Kotlin은 전통적인
for문
대신 등차수열(Range) 을 사용합니다. ..
연산자로 범위를 생성합니다.
✅ 오름차순 반복 (1부터 3까지)
for (i in 1..3) {
println(i)
}
1..3
: 1부터 3까지 포함 (inclusive)
✅ 내림차순 반복 (3부터 1까지)
for (i in 3 downTo 1) {
println(i)
}
downTo
키워드를 사용하면 역방향으로 순회합니다.
✅ step을 사용한 반복 (2칸씩 이동)
for (i in 1..5 step 2) {
println(i)
}
step
키워드로 증가 폭을 설정할 수 있습니다.
3️⃣ while문, do-while문
while
,do-while
문법은 Java와 완전히 동일합니다.
✅ while문 예시
var i = 1
while (i <= 3) {
println(i)
i++
}
✅ do-while문 예시
var j = 1
do {
println(j)
j++
} while (j <= 3)
💬
do-while
은 조건과 상관없이 최소 1회는 실행됩니다.
✅ 요약
구분 | Kotlin 특징 |
---|---|
for-each문 | in 키워드를 사용 |
전통적인 for문 | 1..10 등차수열로 범위를 표현 |
내림차순 반복 | downTo 사용 |
증가 폭 조정 | step 사용 |
while문, do-while문 | Java와 동일 |
📌 정리
- Kotlin은 반복문에서 범위(Range) 개념을 자연스럽게 지원한다.
for
루프가 훨씬 간결해지고 가독성이 좋아진다.- while, do-while은 Java 문법을 그대로 사용 가능하다.
Kotlin의 반복문은 코드량을 줄이고 더 읽기 쉽고 명확한 코드를 만드는 데 큰 도움이 됩니다! 🚀
📚 Kotlin - try-catch 예외처리 정리
Kotlin에서도 try-catch-finally
구문은 Java와 거의 비슷합니다.
하지만 Kotlin만의 특별한 차이점들이 존재합니다.
1️⃣ Kotlin의 try-catch 문법
- 기본적인 문법 구조는 Java와 동일합니다.
catch
블록은 여러 개 작성할 수 있습니다.finally
블록도 지원합니다.
try {
// 예외가 발생할 수 있는 코드
} catch (e: ExceptionType) {
// 예외 처리
} finally {
// 항상 실행되는 블록
}
2️⃣ Kotlin의 try-catch는 Expression
- Kotlin에서는
try-catch
자체가 Expression입니다. - 즉, 값을 반환할 수 있으며 바로
return
하거나, 변수에 할당할 수 있습니다.
✅ 예시 1 : return에 사용하는 경우
fun parseIntOrThrow(str: String): Int {
try {
return str.toInt()
} catch (e: NumberFormatException) {
throw IllegalArgumentException("주어진 ${str}은 숫자가 아닙니다.")
}
}
✅ 예시 2 : 값으로 사용하는 경우
fun parseIntOrThrowV2(str: String): Int? {
return try {
str.toInt()
} catch (e: NumberFormatException) {
null
}
}
💬
try-catch
결과 자체를 반환하거나, 변수에 바로 할당할 수 있다!
3️⃣ Kotlin의 예외는 모두 Unchecked Exception
- Kotlin에서는 모든 예외가 Unchecked Exception입니다.
- 즉, 명시적으로 throws 선언을 할 필요가 없습니다.
- Java처럼
throws IOException
같은 예외 선언을 요구하지 않습니다.
fun readFile() {
// IOException이 발생할 수 있어도 throws 작성 불필요
}
4️⃣ Kotlin의 try-with-resources
- Java에서는 try-with-resources를 위해
try(resource)
문법을 사용했지만, - Kotlin에서는
use
확장 함수를 사용하여 리소스를 자동으로 닫을 수 있습니다.
✅ Kotlin에서 try-with-resources 스타일
BufferedReader(FileReader("test.txt")).use { reader ->
println(reader.readLine())
}
💬
use
블록이 끝나면 자동으로close()
가 호출됩니다.
✅ 요약
구분 | Kotlin 특징 |
---|---|
try-catch 문법 | Java와 동일 |
try-catch | Expression, 값을 반환할 수 있음 |
예외 타입 | 모두 Unchecked Exception (throws 불필요) |
리소스 관리 | use 확장 함수로 대체 (try-with-resources) |
📌 정리
- Kotlin에서는
try-catch
문을 값처럼 사용할 수 있다는 점이 큰 차이입니다. - Checked Exception이 없기 때문에, 코드를 훨씬 깔끔하게 작성할 수 있습니다.
- 자원 관리를
use
를 통해 훨씬 자연스럽게 처리할 수 있습니다.
Kotlin의 예외처리는 Java보다 간결하고 유연하게 동작합니다! 🚀
📚 Kotlin - 함수 다루기 정리
Kotlin에서는 함수 선언과 사용법이 Java와 많이 다릅니다.
간결함과 표현력을 강화한 Kotlin 함수 문법을 정리합니다!
1️⃣ 함수 선언 문법
fun
키워드를 사용해 함수를 선언합니다.- 반환 타입은
:
뒤에 명시합니다. - Block 대신
=
로 단일 표현식을 바로 반환할 수 있습니다.
// 일반 함수 선언
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}
// 한 줄로 간결하게
fun max2(a: Int, b: Int): Int = if (a > b) a else b
💬 함수가 "하나의 값"을 반환할 때는
{}
블록 없이=
를 사용합니다!
2️⃣ 기본값(Default Parameter)
- 함수 파라미터에 기본값을 설정할 수 있습니다.
- 호출 시 해당 값을 생략하면 기본값이 자동으로 사용됩니다.
fun repeat(str: String, num: Int = 3, useNewLine: Boolean = true) {
for (i in 1..num) {
if (useNewLine) {
println(str)
} else {
print(str)
}
}
}
// 기본값을 사용한 호출
repeat("Hello World") // num, useNewLine은 설정한 기본값이 들어감
// 기본값 일부 수정 (Named Argument)
repeat("Hello World", useNewLine = false)
💬 기본값이 있는 파라미터는 생략 가능하며, 특정 파라미터만 지정해서 호출할 수도 있습니다!
3️⃣ Named Argument (이름 있는 인자)
- Kotlin에서는 호출 시 인자의 이름을 직접 지정할 수 있습니다.
fun printNameAndGender(name: String, gender: String) {
println(name)
println(gender)
}
// 이름을 명시하여 호출
printNameAndGender(name = "임도현", gender = "MALE")
💬 매개변수가 많거나, 가독성을 높이고 싶을 때 유용합니다!
4️⃣ 가변인자 (Vararg)
- 여러 개의 값을 받는 가변 인자를 선언할 수 있습니다.
- Kotlin에서는
vararg
키워드를 사용합니다. - 배열을 넘길 때는
*
스프레드 연산자를 붙여야 합니다.
fun printAll(vararg strings: String) {
for (str in strings) {
println(str)
}
}
// 직접 여러 인자 전달
printAll("A", "B", "C")
// 배열을 전달할 때는 *을 사용
val array = arrayOf("A", "B", "C")
printAll(*array)
fun printAll(vararg strings: String) {
for(str in strings) {
println(str)
}
}
자바 코드
public static void printAll(String... strings) {
for (String str : strings) {
System.out.println(str);
}
}
💬 Java의
String... strings
와 동일한 개념입니다. Kotlin은vararg
+*
로 처리합니다!
✅ 요약
항목 | Kotlin 특징 |
---|---|
함수 선언 | fun 키워드 사용 |
단일 표현식 반환 | = 키워드로 가능 |
기본값 파라미터 | 기본값을 선언 가능 |
Named Argument | 호출 시 파라미터 이름 지정 가능 |
가변 인자 | vararg 사용, 배열은 * 붙여야 함 |
📌 마무리
- Kotlin의 함수는 짧고 명확하게 작성할 수 있습니다.
- 표현식 기반이라 더욱 강력한 문법을 제공합니다.
- 기본값, 이름있는 호출, 가변인자 등을 통해 함수 호출이 매우 유연해집니다.
Kotlin 함수 문법을 잘 활용하면 코드가 훨씬 간결하고 가독성 좋게 변합니다! 🚀