2025-02-22T01:33:42
This commit is contained in:
12
app.sh
Executable file
12
app.sh
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
gitup)
|
||||||
|
echo "Pushing to git"
|
||||||
|
git add -A
|
||||||
|
git commit -m $(date "+%Y-%m-%dT%H:%M:%S")
|
||||||
|
git push origin
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
code .
|
||||||
|
esac
|
||||||
118
docs/02_기본 문법.md
Normal file
118
docs/02_기본 문법.md
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
# **코틀린 vs 자바: 기본 문법 비교**
|
||||||
|
|
||||||
|
코틀린은 자바 개발자가 배우기 쉬운 언어이지만, 몇 가지 중요한 문법적 차이가 있다. 이 글에서는 **변수 선언**, **null 안정성**, **타입 추론**을 중심으로 코틀린과 자바의 차이점을 비교해보겠다.
|
||||||
|
|
||||||
|
## **1. 변수 선언: `val`과 `var`**
|
||||||
|
|
||||||
|
자바에서 변수를 선언할 때는 반드시 데이터 타입을 명시해야 한다.
|
||||||
|
|
||||||
|
### **자바의 변수 선언**
|
||||||
|
```java
|
||||||
|
int x = 10; // 변경 가능한 변수
|
||||||
|
final int y = 20; // 변경 불가능한 변수 (상수)
|
||||||
|
```
|
||||||
|
|
||||||
|
코틀린에서는 `var`와 `val` 키워드를 사용하여 변수를 선언한다.
|
||||||
|
|
||||||
|
- `var` → **변경 가능**(mutable) 변수
|
||||||
|
- `val` → **변경 불가능**(immutable) 변수 (자바의 `final`과 유사)
|
||||||
|
|
||||||
|
### **코틀린의 변수 선언**
|
||||||
|
```kotlin
|
||||||
|
var x = 10 // 변경 가능
|
||||||
|
val y = 20 // 변경 불가능 (한 번만 할당 가능)
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약**
|
||||||
|
> - 코틀린에서는 **데이터 타입을 생략**할 수 있다. (타입 추론 덕분)
|
||||||
|
> - `val`은 `final`과 유사하지만, **런타임 상수는 아님**. (즉, `val` 변수는 런타임에서 초기화 가능)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **2. 널 안정성 (Null Safety)**
|
||||||
|
|
||||||
|
자바에서는 `null` 값이 있을 경우 `NullPointerException(NPE)`이 발생할 수 있다.
|
||||||
|
|
||||||
|
### **자바의 null 처리**
|
||||||
|
```java
|
||||||
|
String name = null; // 컴파일러가 오류를 발생시키지 않음
|
||||||
|
System.out.println(name.length()); // NullPointerException 발생 가능
|
||||||
|
```
|
||||||
|
|
||||||
|
코틀린에서는 **기본적으로 모든 변수는 null을 허용하지 않는다.** 만약 null을 허용하려면 `?`를 붙여야 한다.
|
||||||
|
|
||||||
|
### **코틀린의 null 처리**
|
||||||
|
```kotlin
|
||||||
|
var name: String = "Kotlin" // null 허용 X
|
||||||
|
// name = null // 컴파일 오류 발생
|
||||||
|
|
||||||
|
var nullableName: String? = "Kotlin" // null 허용 O
|
||||||
|
nullableName = null // 가능
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **안전한 null 처리 방법**
|
||||||
|
1. **안전 호출 연산자 (`?.`)**
|
||||||
|
```kotlin
|
||||||
|
println(nullableName?.length) // null이면 null 반환, 아니면 length 값 반환
|
||||||
|
```
|
||||||
|
2. **엘비스 연산자 (`?:`)**
|
||||||
|
```kotlin
|
||||||
|
val length = nullableName?.length ?: 0 // null이면 기본값(0) 반환
|
||||||
|
```
|
||||||
|
3. **강제 호출 연산자 (`!!`)**
|
||||||
|
```kotlin
|
||||||
|
println(nullableName!!.length) // null이면 강제 NPE 발생
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약**
|
||||||
|
> - 코틀린은 기본적으로 모든 변수에 대해 null을 허용하지 않음.
|
||||||
|
> - `?`를 붙이면 null 허용 변수로 선언 가능.
|
||||||
|
> - 안전한 호출 (`?.`), 기본값 제공 (`?:`), 강제 호출 (`!!`) 등의 문법을 제공.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **3. 타입 추론 (Type Inference)**
|
||||||
|
|
||||||
|
자바에서는 변수 선언 시 반드시 타입을 명시해야 한다.
|
||||||
|
|
||||||
|
### **자바의 타입 선언**
|
||||||
|
```java
|
||||||
|
String message = "Hello, Java!";
|
||||||
|
int number = 42;
|
||||||
|
```
|
||||||
|
|
||||||
|
코틀린에서는 타입을 **컴파일러가 자동으로 추론**하므로, 명시적으로 쓸 필요가 없다.
|
||||||
|
|
||||||
|
### **코틀린의 타입 추론**
|
||||||
|
```kotlin
|
||||||
|
val message = "Hello, Kotlin!" // String으로 추론
|
||||||
|
var number = 42 // Int로 추론
|
||||||
|
```
|
||||||
|
|
||||||
|
하지만 타입을 명확하게 하고 싶다면 명시적으로 적을 수도 있다.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val message: String = "Hello, Kotlin!"
|
||||||
|
var number: Int = 42
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약**
|
||||||
|
> - 코틀린은 **타입을 생략 가능**(컴파일러가 추론).
|
||||||
|
> - 하지만 필요하면 타입을 명시할 수도 있음.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **정리: 자바 vs 코틀린 비교**
|
||||||
|
|
||||||
|
| 기능 | 자바 | 코틀린 |
|
||||||
|
|------|------|--------|
|
||||||
|
| **변수 선언** | `int x = 10;`<br>`final int y = 20;` | `var x = 10`<br>`val y = 20` |
|
||||||
|
| **null 안정성** | `String name = null;` (가능하지만 NPE 위험) | `var name: String? = null` (null 허용 여부를 명확히 지정) |
|
||||||
|
| **안전한 null 처리** | `if (name != null) { name.length(); }` | `name?.length ?: 0` |
|
||||||
|
| **타입 추론** | `String message = "Hello";` | `val message = "Hello"` (타입 생략 가능) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
코틀린은 **더 간결하고 안전한 코드**를 작성할 수 있도록 설계된 언어다. 자바 개발자가 코틀린을 배우면 **불필요한 코드가 줄어들고**, **NPE 걱정 없이 더 안전한 프로그래밍**이 가능해진다.
|
||||||
|
|
||||||
|
다음에는 어떤 코틀린 개념을 비교해볼까?
|
||||||
193
docs/03_함수형 프로그래밍.md
Normal file
193
docs/03_함수형 프로그래밍.md
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
# **코틀린 vs 자바: 함수형 프로그래밍 차이점**
|
||||||
|
|
||||||
|
코틀린은 **객체지향 프로그래밍(OOP)과 함수형 프로그래밍(FP)을 모두 지원**하는 하이브리드 언어다. 반면, 자바는 원래 객체지향 언어였지만, 자바 8 이후로 람다 표현식과 스트림 API를 도입하면서 함수형 스타일을 부분적으로 지원하게 되었다.
|
||||||
|
|
||||||
|
이 글에서는 **함수형 프로그래밍의 핵심 개념**인 **고차 함수, 람다 표현식, 확장 함수, 불변성** 등을 자바와 코틀린을 비교하며 설명하겠다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **1. 함수형 프로그래밍이란?**
|
||||||
|
함수형 프로그래밍(FP, Functional Programming)은 **순수 함수**와 **불변성(immutability)**을 중심으로 하는 프로그래밍 패러다임이다. 핵심 원칙은 다음과 같다.
|
||||||
|
|
||||||
|
- **순수 함수 (Pure Function):** 같은 입력에 대해 항상 같은 출력을 반환하며, 외부 상태를 변경하지 않는다.
|
||||||
|
- **불변성 (Immutability):** 데이터를 변경하지 않고 새로운 값을 반환하는 방식으로 동작한다.
|
||||||
|
- **고차 함수 (Higher-Order Function):** 함수를 인자로 받거나 반환하는 함수.
|
||||||
|
- **람다 표현식 (Lambda Expression):** 간결한 익명 함수 표현.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **2. 함수 선언 방식 차이**
|
||||||
|
|
||||||
|
### **자바의 함수 선언 (객체지향 스타일)**
|
||||||
|
```java
|
||||||
|
public class Calculator {
|
||||||
|
public static int add(int a, int b) {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```java
|
||||||
|
int result = Calculator.add(3, 5);
|
||||||
|
```
|
||||||
|
|
||||||
|
### **코틀린의 함수 선언 (함수형 스타일 지원)**
|
||||||
|
```kotlin
|
||||||
|
fun add(a: Int, b: Int): Int {
|
||||||
|
return a + b
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```kotlin
|
||||||
|
val result = add(3, 5)
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - 코틀린에서는 클래스 없이 **함수를 직접 정의 가능**(파일 수준 함수).
|
||||||
|
> - `fun` 키워드를 사용하며 **반환 타입을 `:`로 지정**.
|
||||||
|
> - 한 줄짜리 함수는 `{}` 없이 `=`로 간결하게 표현 가능.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
fun add(a: Int, b: Int) = a + b
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **3. 람다 표현식 (Lambda Expression)**
|
||||||
|
|
||||||
|
람다 표현식은 **익명 함수(Anonymous Function)**의 한 형태로, 간결한 함수형 코드를 작성하는 데 사용된다.
|
||||||
|
|
||||||
|
### **자바의 람다 표현식 (Java 8 이상)**
|
||||||
|
```java
|
||||||
|
// 두 수를 더하는 람다 함수
|
||||||
|
BiFunction<Integer, Integer, Integer> sum = (a, b) -> a + b;
|
||||||
|
System.out.println(sum.apply(5, 3)); // 출력: 8
|
||||||
|
```
|
||||||
|
> 자바에서는 `BiFunction<T, U, R>` 같은 **함수형 인터페이스**를 사용해야 람다를 활용할 수 있다.
|
||||||
|
|
||||||
|
### **코틀린의 람다 표현식**
|
||||||
|
```kotlin
|
||||||
|
// 두 수를 더하는 람다 함수
|
||||||
|
val sum: (Int, Int) -> Int = { a, b -> a + b }
|
||||||
|
println(sum(5, 3)) // 출력: 8
|
||||||
|
```
|
||||||
|
> 코틀린은 별도의 함수형 인터페이스 없이 **람다 표현식을 바로 변수에 할당 가능**.
|
||||||
|
|
||||||
|
#### **더 간결한 표현**
|
||||||
|
코틀린에서는 **타입 추론**이 가능하므로, 타입을 생략할 수도 있다.
|
||||||
|
```kotlin
|
||||||
|
val sum = { a: Int, b: Int -> a + b }
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - 자바는 람다를 사용하려면 `BiFunction<>` 같은 **함수형 인터페이스**가 필요.
|
||||||
|
> - 코틀린은 **별도의 인터페이스 없이 람다를 변수에 직접 할당 가능**.
|
||||||
|
> - `{ 파라미터 -> 함수 본문 }` 형태로 사용.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **4. 고차 함수 (Higher-Order Function)**
|
||||||
|
|
||||||
|
고차 함수는 **다른 함수를 인자로 받거나 반환하는 함수**를 의미한다.
|
||||||
|
|
||||||
|
### **자바에서 고차 함수 구현 (익명 클래스 사용)**
|
||||||
|
자바에서는 **람다 도입 전**에는 익명 클래스를 활용해야 했다.
|
||||||
|
```java
|
||||||
|
public interface MathOperation {
|
||||||
|
int operate(int a, int b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 고차 함수
|
||||||
|
public static int executeOperation(int x, int y, MathOperation operation) {
|
||||||
|
return operation.operate(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 사용 예시
|
||||||
|
int result = executeOperation(5, 3, new MathOperation() {
|
||||||
|
@Override
|
||||||
|
public int operate(int a, int b) {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
자바 8 이후에는 람다 표현식 덕분에 훨씬 간결해졌다.
|
||||||
|
```java
|
||||||
|
int result = executeOperation(5, 3, (a, b) -> a + b);
|
||||||
|
```
|
||||||
|
|
||||||
|
### **코틀린에서 고차 함수 구현**
|
||||||
|
코틀린에서는 **함수를 직접 타입으로 선언 가능**.
|
||||||
|
```kotlin
|
||||||
|
fun executeOperation(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
|
||||||
|
return operation(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 사용 예시
|
||||||
|
val result = executeOperation(5, 3) { x, y -> x + y }
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - 자바에서는 **인터페이스를 먼저 정의해야 하지만**, 코틀린에서는 **함수를 직접 타입으로 선언 가능**.
|
||||||
|
> - 코틀린의 람다는 **더 간결한 문법 제공**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **5. 확장 함수 (Extension Function)**
|
||||||
|
|
||||||
|
자바에서는 기존 클래스를 확장하려면 **상속(Inheritance)이나 유틸리티 클래스**를 사용해야 한다.
|
||||||
|
|
||||||
|
### **자바의 유틸리티 메서드 방식**
|
||||||
|
```java
|
||||||
|
public class StringUtils {
|
||||||
|
public static String greet(String name) {
|
||||||
|
return "Hello, " + name + "!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println(StringUtils.greet("Java"));
|
||||||
|
```
|
||||||
|
|
||||||
|
### **코틀린의 확장 함수**
|
||||||
|
코틀린에서는 **기존 클래스에 새로운 메서드를 추가하는 것처럼 확장 가능**.
|
||||||
|
```kotlin
|
||||||
|
fun String.greet(): String {
|
||||||
|
return "Hello, $this!"
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Kotlin".greet()) // 출력: Hello, Kotlin!
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - 자바에서는 **유틸리티 클래스의 정적 메서드**를 사용해야 함.
|
||||||
|
> - 코틀린에서는 **클래스를 수정하지 않고도 확장 함수로 기능 추가 가능**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **6. 불변성과 컬렉션 처리**
|
||||||
|
|
||||||
|
### **자바의 불변 컬렉션**
|
||||||
|
```java
|
||||||
|
List<String> names = List.of("Alice", "Bob"); // 변경 불가능한 리스트 (Java 9+)
|
||||||
|
```
|
||||||
|
|
||||||
|
### **코틀린의 불변 컬렉션**
|
||||||
|
```kotlin
|
||||||
|
val names = listOf("Alice", "Bob") // 변경 불가능한 리스트
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - 코틀린은 `listOf()`, `setOf()` 등을 통해 불변 컬렉션을 쉽게 생성 가능.
|
||||||
|
> - 자바 8까지는 `Collections.unmodifiableList()`를 사용해야 했음.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **정리: 자바 vs 코틀린 함수형 프로그래밍**
|
||||||
|
|
||||||
|
| 기능 | 자바 | 코틀린 |
|
||||||
|
|------|------|--------|
|
||||||
|
| 람다 표현식 | `(a, b) -> a + b` (`BiFunction` 필요) | `{ a, b -> a + b }` (함수형 타입 지원) |
|
||||||
|
| 고차 함수 | 함수형 인터페이스 필요 | 함수 타입 `(Int, Int) -> Int` 직접 사용 가능 |
|
||||||
|
| 확장 함수 | 유틸리티 메서드 필요 | `fun String.greet() = "Hello, $this"` |
|
||||||
|
| 불변 컬렉션 | `List.of()` (Java 9+) | `listOf()` |
|
||||||
|
|
||||||
|
코틀린은 자바보다 함수형 프로그래밍을 **더 자연스럽고 간결하게 지원**한다.
|
||||||
|
|
||||||
|
다음에는 어떤 개념을 비교해볼까?
|
||||||
231
docs/04_OOP.md
Normal file
231
docs/04_OOP.md
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
# **코틀린 vs 자바: 객체지향 프로그래밍(OOP) 비교**
|
||||||
|
|
||||||
|
코틀린과 자바는 둘 다 객체지향 프로그래밍(OOP)을 지원하는 언어지만, 코틀린은 더 간결하고 유연한 문법을 제공한다.
|
||||||
|
이번 글에서는 **클래스 선언, 생성자, 상속, 접근 제어자, 데이터 클래스, 객체 선언** 등을 중심으로 자바와 코틀린의 차이점을 비교하겠다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **1. 클래스 선언 방식 차이**
|
||||||
|
|
||||||
|
자바에서는 클래스를 선언할 때 `class` 키워드를 사용하고, **필드와 생성자를 분리**해서 작성하는 것이 일반적이다.
|
||||||
|
|
||||||
|
### **자바의 클래스 선언**
|
||||||
|
```java
|
||||||
|
public class Person {
|
||||||
|
private String name;
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public Person(String name, int age) {
|
||||||
|
this.name = name;
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() { return name; }
|
||||||
|
public int getAge() { return age; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### **코틀린의 클래스 선언**
|
||||||
|
코틀린에서는 **주 생성자(Primary Constructor)**를 **클래스 헤더에 직접 정의**할 수 있다.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
class Person(val name: String, val age: Int)
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - **자바:** 필드, 생성자, 게터를 따로 작성해야 함.
|
||||||
|
> - **코틀린:** `val` 또는 `var`을 사용하면 **자동으로 필드와 게터 생성**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **2. 생성자 (Constructors)**
|
||||||
|
|
||||||
|
자바에서는 **기본 생성자**와 **매개변수가 있는 생성자**를 따로 정의해야 한다.
|
||||||
|
|
||||||
|
### **자바의 생성자 오버로딩**
|
||||||
|
```java
|
||||||
|
public class Car {
|
||||||
|
private String model;
|
||||||
|
|
||||||
|
public Car() {
|
||||||
|
this.model = "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Car(String model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
코틀린에서는 **기본값을 지정**할 수 있어 생성자 오버로딩을 줄일 수 있다.
|
||||||
|
|
||||||
|
### **코틀린의 기본값 제공 방식**
|
||||||
|
```kotlin
|
||||||
|
class Car(val model: String = "Unknown")
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - 자바는 **생성자 오버로딩**이 필요하지만,
|
||||||
|
> - 코틀린은 **기본값을 제공하면 생성자 하나로 해결 가능**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **3. 상속 (Inheritance)과 `open` 키워드**
|
||||||
|
|
||||||
|
자바에서 클래스를 상속하려면 `extends` 키워드를 사용하고, **메서드 오버라이딩 시 `@Override`를 명시**해야 한다.
|
||||||
|
|
||||||
|
### **자바의 상속**
|
||||||
|
```java
|
||||||
|
public class Animal {
|
||||||
|
public void makeSound() {
|
||||||
|
System.out.println("Some sound");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Dog extends Animal {
|
||||||
|
@Override
|
||||||
|
public void makeSound() {
|
||||||
|
System.out.println("Bark!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
코틀린에서는 클래스가 **기본적으로 `final`이므로 상속을 허용하려면 `open` 키워드를 붙여야 한다**.
|
||||||
|
|
||||||
|
### **코틀린의 상속**
|
||||||
|
```kotlin
|
||||||
|
open class Animal {
|
||||||
|
open fun makeSound() {
|
||||||
|
println("Some sound")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Dog : Animal() {
|
||||||
|
override fun makeSound() {
|
||||||
|
println("Bark!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - **자바:** 모든 클래스가 기본적으로 **상속 가능**(`final`이 아님).
|
||||||
|
> - **코틀린:** 모든 클래스가 기본적으로 **`final`이며, 상속하려면 `open`을 붙여야 함**.
|
||||||
|
> - **오버라이딩 시 자바는 `@Override` 사용**, 코틀린은 **`override` 키워드 필수**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **4. 접근 제어자 (Access Modifiers)**
|
||||||
|
|
||||||
|
자바와 코틀린 모두 **`public`, `protected`, `private`** 접근 제어자를 제공하지만,
|
||||||
|
코틀린에는 **추가로 `internal`이 있다**.
|
||||||
|
|
||||||
|
| 접근 제어자 | 자바 | 코틀린 |
|
||||||
|
|------------|------|--------|
|
||||||
|
| `public` | 모든 곳에서 접근 가능 | 동일 |
|
||||||
|
| `protected` | 같은 패키지 + 하위 클래스에서 접근 가능 | 하위 클래스에서만 접근 가능 (패키지 무관) |
|
||||||
|
| `private` | 같은 클래스 내에서만 접근 가능 | 동일 |
|
||||||
|
| `default` (생략 시) | 같은 패키지 내에서 접근 가능 | `internal` (같은 모듈 내에서 접근 가능) |
|
||||||
|
|
||||||
|
### **코틀린의 `internal` 키워드**
|
||||||
|
```kotlin
|
||||||
|
internal class InternalClass {
|
||||||
|
fun greet() = "Hello"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> - `internal`은 **같은 모듈 내에서만 접근 가능**(자바에는 해당 없음).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **5. 데이터 클래스 (Data Class)**
|
||||||
|
|
||||||
|
자바에서는 **`equals()`, `hashCode()`, `toString()` 메서드를 직접 구현**해야 한다.
|
||||||
|
|
||||||
|
### **자바의 데이터 클래스를 수동 구현**
|
||||||
|
```java
|
||||||
|
public class User {
|
||||||
|
private String name;
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public User(String name, int age) {
|
||||||
|
this.name = name;
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) return true;
|
||||||
|
if (obj == null || getClass() != obj.getClass()) return false;
|
||||||
|
User user = (User) obj;
|
||||||
|
return age == user.age && Objects.equals(name, user.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(name, age);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{name='" + name + "', age=" + age + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
코틀린에서는 **`data` 키워드를 추가하는 것만으로 자동 생성**된다.
|
||||||
|
|
||||||
|
### **코틀린의 데이터 클래스**
|
||||||
|
```kotlin
|
||||||
|
data class User(val name: String, val age: Int)
|
||||||
|
```
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - 자바에서는 `equals()`, `hashCode()`, `toString()`을 직접 작성해야 함.
|
||||||
|
> - 코틀린에서는 `data class`만 선언하면 자동 생성됨.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **6. 싱글턴 (Singleton) 객체 선언**
|
||||||
|
|
||||||
|
자바에서 싱글턴 패턴을 구현하려면 **`static` 키워드를 사용하거나, `enum`을 활용**해야 한다.
|
||||||
|
|
||||||
|
### **자바의 싱글턴 패턴**
|
||||||
|
```java
|
||||||
|
public class Singleton {
|
||||||
|
private static final Singleton INSTANCE = new Singleton();
|
||||||
|
|
||||||
|
private Singleton() {}
|
||||||
|
|
||||||
|
public static Singleton getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
코틀린에서는 **`object` 키워드를 사용하면 자동으로 싱글턴이 된다**.
|
||||||
|
|
||||||
|
### **코틀린의 싱글턴**
|
||||||
|
```kotlin
|
||||||
|
object Singleton {
|
||||||
|
fun greet() = "Hello"
|
||||||
|
}
|
||||||
|
|
||||||
|
println(Singleton.greet()) // Hello
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - 자바는 **싱글턴을 만들기 위해 보일러플레이트 코드 필요**.
|
||||||
|
> - 코틀린은 `object`를 사용하면 자동으로 싱글턴 객체 생성됨.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **정리: 자바 vs 코틀린 OOP 차이점**
|
||||||
|
|
||||||
|
| 기능 | 자바 | 코틀린 |
|
||||||
|
|------|------|--------|
|
||||||
|
| **클래스 선언** | 필드 + 생성자 + 게터 필요 | `class Person(val name: String)` |
|
||||||
|
| **생성자 오버로딩** | 여러 개의 생성자 정의 필요 | 기본값 사용 가능 |
|
||||||
|
| **상속** | 기본적으로 가능 (`final`을 붙여야 제한) | 기본적으로 `final`, `open`을 붙여야 상속 가능 |
|
||||||
|
| **데이터 클래스** | `equals()`, `hashCode()`, `toString()` 직접 구현 | `data class`로 자동 생성 |
|
||||||
|
| **싱글턴 패턴** | `static` 필드 사용 | `object` 키워드 사용 |
|
||||||
|
| **`protected` 접근 제어자** | 같은 패키지 + 하위 클래스 접근 가능 | 오직 하위 클래스만 접근 가능 |
|
||||||
|
|
||||||
|
코틀린은 **객체지향 프로그래밍을 더 간결하고 효율적으로 작성할 수 있도록 개선**된 언어다.
|
||||||
|
다음에는 어떤 개념을 비교해볼까?
|
||||||
183
docs/05_컬렉션.md
Normal file
183
docs/05_컬렉션.md
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
# **코틀린 컬렉션과 스트림 API vs 자바 스트림 API**
|
||||||
|
|
||||||
|
코틀린은 자바와 마찬가지로 **리스트(List), 세트(Set), 맵(Map)** 등의 컬렉션을 제공한다. 하지만 자바와는 다르게, **컬렉션을 더욱 간결하게 다룰 수 있는 함수형 API**를 기본 제공하며, 대부분의 연산을 **람다식과 메서드 체이닝**을 통해 쉽게 수행할 수 있다.
|
||||||
|
|
||||||
|
이번 글에서는 **코틀린의 컬렉션 사용법과 자바 스트림 API와의 차이점**을 비교해보겠다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **1. 코틀린 컬렉션 기본 개념**
|
||||||
|
|
||||||
|
### **1.1. 불변(Immutable) vs 가변(Mutable) 컬렉션**
|
||||||
|
|
||||||
|
코틀린의 컬렉션은 **불변형(`listOf`, `setOf`, `mapOf`)**과 **가변형(`mutableListOf`, `mutableSetOf`, `mutableMapOf`)**으로 나뉜다.
|
||||||
|
자바에서는 `Collections.unmodifiableList()` 등을 사용해야 하지만, 코틀린에서는 기본적으로 **불변 컬렉션을 사용하도록 유도**한다.
|
||||||
|
|
||||||
|
#### **자바의 리스트 선언**
|
||||||
|
```java
|
||||||
|
List<String> immutableList = List.of("A", "B", "C"); // Java 9+
|
||||||
|
List<String> mutableList = new ArrayList<>();
|
||||||
|
mutableList.add("A");
|
||||||
|
mutableList.add("B");
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **코틀린의 리스트 선언**
|
||||||
|
```kotlin
|
||||||
|
val immutableList = listOf("A", "B", "C") // 불변 리스트
|
||||||
|
val mutableList = mutableListOf("A", "B") // 가변 리스트
|
||||||
|
mutableList.add("C")
|
||||||
|
```
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - **자바**: `List.of()`(불변) vs `ArrayList<>()`(가변)
|
||||||
|
> - **코틀린**: `listOf()`(불변) vs `mutableListOf()`(가변)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **2. 코틀린 컬렉션 사용 예제**
|
||||||
|
|
||||||
|
### **2.1. 리스트(List)**
|
||||||
|
```kotlin
|
||||||
|
val numbers = listOf(1, 2, 3, 4, 5)
|
||||||
|
println(numbers[0]) // 1
|
||||||
|
println(numbers.size) // 5
|
||||||
|
```
|
||||||
|
가변 리스트:
|
||||||
|
```kotlin
|
||||||
|
val mutableNumbers = mutableListOf(1, 2, 3)
|
||||||
|
mutableNumbers.add(4)
|
||||||
|
println(mutableNumbers) // [1, 2, 3, 4]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **2.2. 집합(Set)**
|
||||||
|
```kotlin
|
||||||
|
val names = setOf("Alice", "Bob", "Charlie")
|
||||||
|
println(names.contains("Alice")) // true
|
||||||
|
```
|
||||||
|
가변 집합:
|
||||||
|
```kotlin
|
||||||
|
val mutableNames = mutableSetOf("Alice", "Bob")
|
||||||
|
mutableNames.add("Charlie")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **2.3. 맵(Map)**
|
||||||
|
```kotlin
|
||||||
|
val userMap = mapOf("Alice" to 25, "Bob" to 30)
|
||||||
|
println(userMap["Alice"]) // 25
|
||||||
|
```
|
||||||
|
가변 맵:
|
||||||
|
```kotlin
|
||||||
|
val mutableUserMap = mutableMapOf("Alice" to 25)
|
||||||
|
mutableUserMap["Bob"] = 30
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **3. 코틀린의 스트림 API vs 자바의 스트림 API**
|
||||||
|
|
||||||
|
자바에서는 컬렉션을 처리할 때 **스트림 API(`Stream`)**를 사용해야 하지만,
|
||||||
|
코틀린은 **컬렉션 자체가 스트림 API처럼 동작**한다.
|
||||||
|
|
||||||
|
### **3.1. 자바 스트림 예제**
|
||||||
|
```java
|
||||||
|
List<String> names = List.of("Alice", "Bob", "Charlie");
|
||||||
|
List<String> filteredNames = names.stream()
|
||||||
|
.filter(name -> name.startsWith("A"))
|
||||||
|
.map(String::toUpperCase)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
System.out.println(filteredNames); // [ALICE]
|
||||||
|
```
|
||||||
|
> **자바의 특징:**
|
||||||
|
> - `.stream()`을 호출해야 함
|
||||||
|
> - `.collect(Collectors.toList())`를 사용해야 리스트 반환
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **3.2. 코틀린 컬렉션 API 예제**
|
||||||
|
```kotlin
|
||||||
|
val names = listOf("Alice", "Bob", "Charlie")
|
||||||
|
val filteredNames = names
|
||||||
|
.filter { it.startsWith("A") }
|
||||||
|
.map { it.uppercase() }
|
||||||
|
|
||||||
|
println(filteredNames) // [ALICE]
|
||||||
|
```
|
||||||
|
> **코틀린의 특징:**
|
||||||
|
> - `stream()` 없이 컬렉션 자체에서 메서드 체이닝 가능
|
||||||
|
> - `collect()` 없이 리스트 반환
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **3.3. 숫자 리스트 필터링 & 변환**
|
||||||
|
#### **자바 (Stream API 사용)**
|
||||||
|
```java
|
||||||
|
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);
|
||||||
|
List<Integer> evenSquares = numbers.stream()
|
||||||
|
.filter(n -> n % 2 == 0)
|
||||||
|
.map(n -> n * n)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
System.out.println(evenSquares); // [4, 16, 36]
|
||||||
|
```
|
||||||
|
#### **코틀린 (컬렉션 API 사용)**
|
||||||
|
```kotlin
|
||||||
|
val numbers = listOf(1, 2, 3, 4, 5, 6)
|
||||||
|
val evenSquares = numbers
|
||||||
|
.filter { it % 2 == 0 }
|
||||||
|
.map { it * it }
|
||||||
|
|
||||||
|
println(evenSquares) // [4, 16, 36]
|
||||||
|
```
|
||||||
|
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - **자바**: `.stream()` 호출 → `filter()`, `map()` → `.collect(Collectors.toList())` 필요
|
||||||
|
> - **코틀린**: 바로 `filter()`, `map()` 사용 가능
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **4. 추가적인 컬렉션 함수들**
|
||||||
|
|
||||||
|
### **4.1. `forEach`**
|
||||||
|
```kotlin
|
||||||
|
val numbers = listOf(1, 2, 3)
|
||||||
|
numbers.forEach { println(it) }
|
||||||
|
```
|
||||||
|
|
||||||
|
### **4.2. `groupBy`**
|
||||||
|
```kotlin
|
||||||
|
val words = listOf("apple", "banana", "avocado", "blueberry")
|
||||||
|
val grouped = words.groupBy { it.first() }
|
||||||
|
println(grouped)
|
||||||
|
// {a=[apple, avocado], b=[banana, blueberry]}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **4.3. `associateBy` (키 매핑)**
|
||||||
|
```kotlin
|
||||||
|
data class Person(val name: String, val age: Int)
|
||||||
|
|
||||||
|
val people = listOf(Person("Alice", 25), Person("Bob", 30))
|
||||||
|
val personMap = people.associateBy { it.name }
|
||||||
|
println(personMap["Alice"]) // Person(name=Alice, age=25)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **5. 정리: 코틀린 vs 자바 스트림 API 차이점**
|
||||||
|
|
||||||
|
| 기능 | 자바 (Stream API) | 코틀린 (컬렉션 API) |
|
||||||
|
|------|----------------|----------------|
|
||||||
|
| 스트림 사용 | `.stream()` 필요 | 컬렉션 자체에서 사용 가능 |
|
||||||
|
| 리스트 반환 | `.collect(Collectors.toList())` 필요 | 자동 반환 |
|
||||||
|
| `filter()` 사용 | `filter(n -> 조건)` | `filter { it 조건 }` |
|
||||||
|
| `map()` 사용 | `map(n -> 변환)` | `map { it 변환 }` |
|
||||||
|
| 그룹핑 | `.collect(Collectors.groupingBy())` | `groupBy { it 기준 }` |
|
||||||
|
| 가변 리스트 | `new ArrayList<>()` | `mutableListOf()` |
|
||||||
|
|
||||||
|
코틀린은 **컬렉션을 더욱 직관적이고 간결하게 다룰 수 있도록 설계**되었다.
|
||||||
|
자바에서 스트림 API를 써야 하는 많은 경우를 **코틀린에서는 기본 컬렉션 함수만으로 해결**할 수 있다.
|
||||||
|
|
||||||
|
> **코틀린으로 스트림 API를 더 쉽게 다룰 수 있다는 점을 기억하자!**
|
||||||
216
docs/06_예외 처리 및 흐름 제어.md
Normal file
216
docs/06_예외 처리 및 흐름 제어.md
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
# **코틀린 vs 자바: 예외 처리와 흐름 제어 차이점**
|
||||||
|
|
||||||
|
코틀린과 자바는 기본적으로 예외 처리(Exception Handling)와 흐름 제어(Control Flow)를 비슷하게 제공하지만,
|
||||||
|
코틀린은 **더 간결한 문법과 강력한 기능**을 제공하여, 예외를 보다 효과적으로 처리하고 흐름 제어를 쉽게 구현할 수 있다.
|
||||||
|
|
||||||
|
이 글에서는 **예외 처리와 흐름 제어**에서 **코틀린과 자바의 차이점**을 비교해 보겠다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **1. 예외 처리 (Exception Handling)**
|
||||||
|
|
||||||
|
자바와 코틀린 모두 **`try-catch-finally`** 블록을 지원하지만,
|
||||||
|
코틀린에서는 **예외가 표현식(Expression)으로 사용 가능**하고, **Checked Exception이 없다**는 차이가 있다.
|
||||||
|
|
||||||
|
### **1.1. 자바의 예외 처리**
|
||||||
|
```java
|
||||||
|
public class JavaExceptionExample {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try {
|
||||||
|
int result = divide(10, 0);
|
||||||
|
System.out.println(result);
|
||||||
|
} catch (ArithmeticException e) {
|
||||||
|
System.out.println("예외 발생: " + e.getMessage());
|
||||||
|
} finally {
|
||||||
|
System.out.println("예외 여부와 관계없이 실행됨");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int divide(int a, int b) throws ArithmeticException {
|
||||||
|
return a / b; // 0으로 나누면 예외 발생
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**출력 결과:**
|
||||||
|
```
|
||||||
|
예외 발생: / by zero
|
||||||
|
예외 여부와 관계없이 실행됨
|
||||||
|
```
|
||||||
|
|
||||||
|
> **자바의 특징:**
|
||||||
|
> - `throws` 키워드를 사용하여 Checked Exception을 선언해야 할 수 있음
|
||||||
|
> - `try-catch-finally` 블록 필요
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **1.2. 코틀린의 예외 처리**
|
||||||
|
```kotlin
|
||||||
|
fun main() {
|
||||||
|
try {
|
||||||
|
val result = divide(10, 0)
|
||||||
|
println(result)
|
||||||
|
} catch (e: ArithmeticException) {
|
||||||
|
println("예외 발생: ${e.message}")
|
||||||
|
} finally {
|
||||||
|
println("예외 여부와 관계없이 실행됨")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun divide(a: Int, b: Int): Int {
|
||||||
|
return a / b // 0으로 나누면 예외 발생
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**출력 결과:**
|
||||||
|
```
|
||||||
|
예외 발생: / by zero
|
||||||
|
예외 여부와 관계없이 실행됨
|
||||||
|
```
|
||||||
|
|
||||||
|
> **코틀린의 특징:**
|
||||||
|
> - `throws` 선언이 필요 없음 (Checked Exception이 없음)
|
||||||
|
> - 예외 처리를 **표현식(Expression)으로 사용할 수 있음**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **1.3. 예외를 반환값으로 사용하는 경우 (코틀린만 가능)**
|
||||||
|
자바에서는 `try-catch` 블록을 표현식으로 사용할 수 없지만,
|
||||||
|
코틀린에서는 **`try` 자체가 값(value)을 반환할 수 있다**.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val result: Int = try {
|
||||||
|
divide(10, 2)
|
||||||
|
} catch (e: ArithmeticException) {
|
||||||
|
-1 // 예외 발생 시 기본값 반환
|
||||||
|
}
|
||||||
|
println(result) // 5
|
||||||
|
```
|
||||||
|
> **코틀린의 특징:**
|
||||||
|
> - `try-catch` 블록을 값처럼 사용 가능
|
||||||
|
> - 예외 발생 시 기본값을 쉽게 설정 가능
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **2. 흐름 제어 (Control Flow) 차이점**
|
||||||
|
|
||||||
|
자바와 코틀린은 기본적인 흐름 제어 구조(`if`, `when`, `for`, `while`)가 유사하지만,
|
||||||
|
코틀린은 **표현식(Expression) 기반으로 설계**되어 보다 간결하게 코드를 작성할 수 있다.
|
||||||
|
|
||||||
|
### **2.1. `if` 문법 차이**
|
||||||
|
#### **자바의 `if-else` (Statement 기반)**
|
||||||
|
```java
|
||||||
|
int number = 10;
|
||||||
|
String result;
|
||||||
|
|
||||||
|
if (number % 2 == 0) {
|
||||||
|
result = "짝수";
|
||||||
|
} else {
|
||||||
|
result = "홀수";
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(result);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **코틀린의 `if-else` (Expression 기반)**
|
||||||
|
```kotlin
|
||||||
|
val number = 10
|
||||||
|
val result = if (number % 2 == 0) "짝수" else "홀수"
|
||||||
|
|
||||||
|
println(result)
|
||||||
|
```
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - 자바는 `if-else`가 **Statement(문장)**
|
||||||
|
> - 코틀린은 `if-else`가 **Expression(값을 반환할 수 있음)**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **2.2. `switch-case` vs `when`**
|
||||||
|
자바에서는 `switch-case` 문을 사용하지만, 코틀린에서는 더 강력한 **`when`**을 제공한다.
|
||||||
|
|
||||||
|
#### **자바의 `switch-case`**
|
||||||
|
```java
|
||||||
|
int number = 2;
|
||||||
|
String result;
|
||||||
|
|
||||||
|
switch (number) {
|
||||||
|
case 1:
|
||||||
|
result = "One";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
result = "Two";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(result);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **코틀린의 `when` (더 강력한 표현 가능)**
|
||||||
|
```kotlin
|
||||||
|
val number = 2
|
||||||
|
val result = when (number) {
|
||||||
|
1 -> "One"
|
||||||
|
2 -> "Two"
|
||||||
|
else -> "Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
println(result)
|
||||||
|
```
|
||||||
|
> **코틀린의 특징:**
|
||||||
|
> - `when`은 **Expression**으로 값을 반환 가능
|
||||||
|
> - `break`가 필요 없음
|
||||||
|
> - 복합 조건 사용 가능 (`in`, `is` 활용 가능)
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val result = when (number) {
|
||||||
|
in 1..5 -> "1~5 범위"
|
||||||
|
is Int -> "정수"
|
||||||
|
else -> "알 수 없음"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **2.3. 반복문 차이점**
|
||||||
|
#### **자바의 `for` 반복문**
|
||||||
|
```java
|
||||||
|
List<String> names = List.of("Alice", "Bob", "Charlie");
|
||||||
|
|
||||||
|
for (String name : names) {
|
||||||
|
System.out.println(name);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
#### **코틀린의 `for` 반복문**
|
||||||
|
```kotlin
|
||||||
|
val names = listOf("Alice", "Bob", "Charlie")
|
||||||
|
|
||||||
|
for (name in names) {
|
||||||
|
println(name)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> **차이점 요약:**
|
||||||
|
> - 코틀린은 **`for (element in collection)`** 형식을 사용
|
||||||
|
> - **인덱스가 필요하면 `withIndex()` 활용 가능**
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
for ((index, name) in names.withIndex()) {
|
||||||
|
println("$index: $name")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **3. 결론: 코틀린이 더 간결하고 유연하다**
|
||||||
|
|
||||||
|
| 기능 | 자바 | 코틀린 |
|
||||||
|
|------|------|------|
|
||||||
|
| 예외 처리 | Checked Exception 있음 | Checked Exception 없음 |
|
||||||
|
| `try-catch` | Statement (값 반환 불가) | Expression (값 반환 가능) |
|
||||||
|
| `if-else` | Statement | Expression |
|
||||||
|
| `switch-case` | `break` 필요 | `when`으로 더 강력하게 가능 |
|
||||||
|
| `for` 반복문 | `for (item : collection)` | `for (item in collection)` |
|
||||||
|
| `for` 인덱스 | `for (int i = 0; i < list.size(); i++)` | `for ((index, item) in list.withIndex())` |
|
||||||
|
|
||||||
|
코틀린은 **표현식 기반**으로 설계되어 불필요한 문법을 줄이고 **더 간결한 코드**를 작성할 수 있다.
|
||||||
|
특히 예외 처리에서 Checked Exception이 없고, `when`과 `try-catch`를 표현식으로 사용할 수 있어
|
||||||
|
**보다 유연하고 직관적인 코드 작성이 가능**하다. 🚀
|
||||||
223
docs/07_코루틴.md
Normal file
223
docs/07_코루틴.md
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
# **코틀린의 코루틴과 비동기 프로그래밍**
|
||||||
|
|
||||||
|
코틀린은 **코루틴(Coroutines)** 을 통해 **비동기(Asynchronous) 프로그래밍**을 쉽고 직관적으로 구현할 수 있다.
|
||||||
|
코루틴은 **스레드보다 가볍고 효율적**이며, **콜백 지옥을 피할 수 있는 강력한 기능**을 제공한다.
|
||||||
|
|
||||||
|
이 글에서는 **코루틴의 개념과 주요 기능**을 설명하고,
|
||||||
|
**비동기 프로그래밍을 구현하는 예제**를 함께 살펴보겠다. 🚀
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **1. 비동기 프로그래밍이란?**
|
||||||
|
비동기 프로그래밍은 **작업이 완료될 때까지 기다리지 않고 다음 코드를 실행하는 방식**이다.
|
||||||
|
즉, **시간이 오래 걸리는 작업(예: 네트워크 요청, 파일 I/O 등)** 도 프로그램이 멈추지 않고 실행된다.
|
||||||
|
|
||||||
|
### **1.1. 전통적인 방식 (콜백 지옥)**
|
||||||
|
자바에서는 비동기 작업을 콜백(callback) 방식으로 처리해야 한다.
|
||||||
|
콜백이 중첩되면 **콜백 지옥(Callback Hell)** 이 발생할 수 있다.
|
||||||
|
|
||||||
|
#### **자바의 콜백 예제**
|
||||||
|
```java
|
||||||
|
void fetchData(Callback callback) {
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000); // 2초 대기 (네트워크 요청 가정)
|
||||||
|
callback.onSuccess("데이터를 가져왔습니다!");
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
callback.onError(e);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
void onSuccess(String data);
|
||||||
|
void onError(Exception e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
fetchData(new Callback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(String data) {
|
||||||
|
System.out.println(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception e) {
|
||||||
|
System.out.println("에러 발생: " + e.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> - `fetchData()` 가 비동기적으로 데이터를 가져오지만, **콜백을 계속 중첩해서 작성해야 한다.**
|
||||||
|
> - 코드가 복잡해지고 가독성이 나빠지는 문제가 있다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **2. 코루틴이란?**
|
||||||
|
**코루틴(Coroutines)** 은 **비동기 프로그래밍을 간결하고 가독성 높게** 구현할 수 있도록 도와준다.
|
||||||
|
코루틴을 사용하면 **콜백 없이도 순차적인 코드 스타일**로 **비동기 작업**을 작성할 수 있다.
|
||||||
|
|
||||||
|
> **코루틴의 특징:**
|
||||||
|
> - **스레드보다 가벼움** (필요할 때만 실행되고, 자동으로 일시 중단됨)
|
||||||
|
> - **순차적 스타일로 작성 가능** (콜백 없이 비동기 코드 작성 가능)
|
||||||
|
> - **비동기 코드가 직관적이고 읽기 쉬움**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **3. 코틀린에서 코루틴 사용하기**
|
||||||
|
### **3.1. 기본적인 코루틴 사용**
|
||||||
|
```kotlin
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
fun main() = runBlocking { // 코루틴 블록 시작
|
||||||
|
launch {
|
||||||
|
delay(1000L) // 1초 대기
|
||||||
|
println("코루틴 실행!")
|
||||||
|
}
|
||||||
|
println("메인 함수 실행")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**출력 결과:**
|
||||||
|
```
|
||||||
|
메인 함수 실행
|
||||||
|
코루틴 실행!
|
||||||
|
```
|
||||||
|
|
||||||
|
> - `runBlocking {}`: 메인 함수에서 코루틴을 실행하는 블록
|
||||||
|
> - `launch {}`: 새로운 코루틴을 실행
|
||||||
|
> - `delay(1000L)`: 1초 동안 비동기 대기 (스레드 차단 없이 실행 가능)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **4. 코루틴 빌더 (`launch` vs `async`)**
|
||||||
|
코루틴을 실행할 때는 **`launch`** 와 **`async`** 를 사용할 수 있다.
|
||||||
|
|
||||||
|
| 빌더 | 반환값 | 특징 |
|
||||||
|
|------|------|------|
|
||||||
|
| `launch` | 없음 (`Job` 반환) | 단순히 코루틴을 실행 |
|
||||||
|
| `async` | `Deferred<T>` 반환 | 결과 값을 반환하는 비동기 작업 |
|
||||||
|
|
||||||
|
### **4.1. `launch` 사용 예시 (결과 값 없음)**
|
||||||
|
```kotlin
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
fun main() = runBlocking {
|
||||||
|
launch {
|
||||||
|
delay(1000L)
|
||||||
|
println("launch: 비동기 작업 완료!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> - `launch {}` 는 단순히 비동기 작업을 실행하고, 결과를 반환하지 않음.
|
||||||
|
> - `Job` 객체를 반환하지만, 보통 `join()`을 호출하지 않는 이상 결과를 기다리지 않음.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **4.2. `async` 사용 예시 (결과 값 반환)**
|
||||||
|
```kotlin
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
fun main() = runBlocking {
|
||||||
|
val result = async {
|
||||||
|
delay(1000L)
|
||||||
|
"async: 비동기 작업 완료!"
|
||||||
|
}
|
||||||
|
println(result.await()) // 결과 값을 기다림
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> - `async {}` 는 **결과 값을 반환하는 비동기 작업**을 실행.
|
||||||
|
> - `await()` 을 호출해야 실제 값을 가져올 수 있음.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **5. 여러 개의 비동기 작업 실행 (`async` 활용)**
|
||||||
|
비동기 작업을 병렬로 실행하려면 **`async {}` 를 여러 개 실행**하면 된다.
|
||||||
|
```kotlin
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
fun main() = runBlocking {
|
||||||
|
val time = measureTimeMillis {
|
||||||
|
val job1 = async { fetchData(1) }
|
||||||
|
val job2 = async { fetchData(2) }
|
||||||
|
println(job1.await())
|
||||||
|
println(job2.await())
|
||||||
|
}
|
||||||
|
println("총 실행 시간: $time ms")
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun fetchData(id: Int): String {
|
||||||
|
delay(1000L) // 네트워크 요청 시뮬레이션
|
||||||
|
return "데이터 $id 가져옴"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**출력 결과:**
|
||||||
|
```
|
||||||
|
데이터 1 가져옴
|
||||||
|
데이터 2 가져옴
|
||||||
|
총 실행 시간: 1003 ms
|
||||||
|
```
|
||||||
|
> - `async {}` 로 실행된 두 개의 코루틴이 **병렬로 실행됨**.
|
||||||
|
> - `await()` 를 호출하면 해당 코루틴이 완료될 때까지 기다림.
|
||||||
|
> - 실행 시간은 1초 내외 (동시 실행되었기 때문).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **6. `suspend` 함수 사용하기**
|
||||||
|
코루틴에서 비동기 함수를 만들려면 **`suspend` 키워드**를 사용해야 한다.
|
||||||
|
```kotlin
|
||||||
|
suspend fun fetchData(): String {
|
||||||
|
delay(1000L) // 1초 대기
|
||||||
|
return "데이터 가져옴"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() = runBlocking {
|
||||||
|
val data = fetchData()
|
||||||
|
println(data)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> - `suspend` 함수는 **코루틴 내에서만 실행 가능**
|
||||||
|
> - `delay()` 같은 비동기 함수 호출 가능
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **7. 예외 처리 (`try-catch` 활용)**
|
||||||
|
코루틴에서도 **예외 처리를 `try-catch` 로 할 수 있음**.
|
||||||
|
```kotlin
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
fun main() = runBlocking {
|
||||||
|
try {
|
||||||
|
val result = async { errorTask() }.await()
|
||||||
|
println(result)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println("예외 발생: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun errorTask(): String {
|
||||||
|
delay(500L)
|
||||||
|
throw RuntimeException("오류 발생!")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**출력 결과:**
|
||||||
|
```
|
||||||
|
예외 발생: 오류 발생!
|
||||||
|
```
|
||||||
|
> - `try-catch` 를 사용하면 **비동기 코드에서도 예외를 안전하게 처리 가능**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **8. 정리**
|
||||||
|
| 기능 | 자바 | 코틀린 |
|
||||||
|
|------|------|------|
|
||||||
|
| 비동기 실행 | 콜백 기반 | 코루틴 기반 (`launch`, `async`) |
|
||||||
|
| 가독성 | 콜백 중첩 발생 | 순차적 코드 스타일 |
|
||||||
|
| 예외 처리 | 예외 전달 어려움 | `try-catch` 사용 가능 |
|
||||||
|
| 실행 효율 | 스레드 사용 | 가벼운 코루틴 사용 |
|
||||||
|
|
||||||
|
> **코루틴을 사용하면:**
|
||||||
|
> ✅ **비동기 코드가 더 간결하고 직관적**
|
||||||
|
> ✅ **콜백 지옥 없이 순차적 스타일로 작성 가능**
|
||||||
|
> ✅ **스레드보다 가볍고 효율적**
|
||||||
|
|
||||||
|
코틀린에서 **비동기 프로그래밍을 쉽게 구현하려면 코루틴을 적극 활용하자!** 🚀
|
||||||
220
docs/08_특수 기능.md
Normal file
220
docs/08_특수 기능.md
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
# **코틀린의 특수 기능과 주요 키워드**
|
||||||
|
|
||||||
|
코틀린은 **개발 생산성을 높이는 다양한 특수 기능**을 제공한다.
|
||||||
|
이 글에서는 **코틀린의 고급 기능**을 **사용 예시와 함께** 설명하겠다. 🚀
|
||||||
|
|
||||||
|
### ✨ **소개할 내용**
|
||||||
|
1. **`inline` 함수**
|
||||||
|
2. **`reified` 키워드**
|
||||||
|
3. **제너릭(Generic)**
|
||||||
|
4. **위임(Delegation) 패턴과 `by` 키워드**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **1. `inline` 함수: 함수 호출 비용 줄이기**
|
||||||
|
코틀린의 `inline` 함수는 **함수 호출 오버헤드를 줄이기 위해 사용**된다.
|
||||||
|
|
||||||
|
### **1.1. 기본적인 `inline` 함수 예제**
|
||||||
|
```kotlin
|
||||||
|
inline fun execute(block: () -> Unit) {
|
||||||
|
println("실행 시작")
|
||||||
|
block()
|
||||||
|
println("실행 종료")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
execute {
|
||||||
|
println("실제 로직 실행")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**출력 결과:**
|
||||||
|
```
|
||||||
|
실행 시작
|
||||||
|
실제 로직 실행
|
||||||
|
실행 종료
|
||||||
|
```
|
||||||
|
> - **함수 호출이 사라지고 코드가 그대로 복사됨 (인라이닝)**
|
||||||
|
> - **람다를 인자로 받을 때 유용**
|
||||||
|
> - 단점: **코드 크기가 증가할 수 있음 (작은 함수에만 사용)**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **2. `reified` 키워드: 실행 시점에서 타입 유지**
|
||||||
|
코틀린에서는 **제너릭 타입 정보가 실행 시점에 사라지는 문제(type erasure)가 있음**.
|
||||||
|
하지만 `reified` 키워드를 사용하면 **실행 시점에서도 타입을 유지할 수 있음**.
|
||||||
|
|
||||||
|
### **2.1. `reified` 없이 제너릭 타입 확인 불가**
|
||||||
|
```kotlin
|
||||||
|
fun <T> getClassName(): String {
|
||||||
|
return T::class.simpleName // 오류 발생!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
println(getClassName<String>())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> - 오류 발생! **제너릭 타입은 실행 시점에서 사라지기 때문**.
|
||||||
|
|
||||||
|
### **2.2. `reified` 키워드 사용하여 해결**
|
||||||
|
```kotlin
|
||||||
|
inline fun <reified T> getClassName(): String {
|
||||||
|
return T::class.simpleName ?: "알 수 없음"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
println(getClassName<String>()) // "String"
|
||||||
|
println(getClassName<Int>()) // "Int"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> - **`reified`를 사용하면 실행 시점에서도 제너릭 타입을 알 수 있음**
|
||||||
|
> - 주의: **`inline` 함수에서만 `reified` 사용 가능**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **3. 제너릭(Generic): 타입을 유연하게 만들기**
|
||||||
|
제너릭을 사용하면 **코드의 재사용성을 높이고, 타입 안정성을 유지할 수 있음**.
|
||||||
|
|
||||||
|
### **3.1. 기본적인 제너릭 사용**
|
||||||
|
```kotlin
|
||||||
|
class Box<T>(val value: T) {
|
||||||
|
fun get(): T = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val intBox = Box(123)
|
||||||
|
val strBox = Box("Hello")
|
||||||
|
|
||||||
|
println(intBox.get()) // 123
|
||||||
|
println(strBox.get()) // Hello
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> - `T`를 사용하여 **어떤 타입이든 저장할 수 있는 클래스**를 정의
|
||||||
|
|
||||||
|
### **3.2. 제너릭 함수 사용**
|
||||||
|
```kotlin
|
||||||
|
fun <T> printItem(item: T) {
|
||||||
|
println("아이템: $item")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
printItem(42) // 아이템: 42
|
||||||
|
printItem("코틀린") // 아이템: 코틀린
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> - **함수에도 제너릭 적용 가능**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **4. 위임(Delegation) 패턴과 `by` 키워드**
|
||||||
|
코틀린의 `by` 키워드는 **객체의 기능을 다른 객체에 위임할 때 사용**된다.
|
||||||
|
이를 통해 **불필요한 코드 중복을 방지**할 수 있다.
|
||||||
|
|
||||||
|
### **4.1. 인터페이스를 이용한 기본 위임 패턴**
|
||||||
|
```kotlin
|
||||||
|
interface Printer {
|
||||||
|
fun printMessage()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConsolePrinter : Printer {
|
||||||
|
override fun printMessage() {
|
||||||
|
println("콘솔에 출력")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SmartPrinter(private val printer: Printer) : Printer {
|
||||||
|
override fun printMessage() {
|
||||||
|
println("스마트 프린터 작동 중...")
|
||||||
|
printer.printMessage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val printer = SmartPrinter(ConsolePrinter())
|
||||||
|
printer.printMessage()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**출력 결과:**
|
||||||
|
```
|
||||||
|
스마트 프린터 작동 중...
|
||||||
|
콘솔에 출력
|
||||||
|
```
|
||||||
|
> - `SmartPrinter`가 `ConsolePrinter`의 기능을 **위임(Delegation)**
|
||||||
|
|
||||||
|
### **4.2. `by` 키워드를 사용한 간결한 위임 패턴**
|
||||||
|
```kotlin
|
||||||
|
class SmartPrinter2(private val printer: Printer) : Printer by printer
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val printer = SmartPrinter2(ConsolePrinter())
|
||||||
|
printer.printMessage() // "콘솔에 출력"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> - `by printer` 를 사용하면 **위임을 자동으로 처리**
|
||||||
|
> - 코드가 훨씬 간결해짐
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **5. `by lazy`를 활용한 지연 초기화**
|
||||||
|
`by lazy`를 사용하면 **객체를 필요할 때만 초기화**할 수 있다.
|
||||||
|
```kotlin
|
||||||
|
class Example {
|
||||||
|
val lazyValue: String by lazy {
|
||||||
|
println("초기화 중...")
|
||||||
|
"Hello, Kotlin!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val example = Example()
|
||||||
|
println("객체 생성 완료")
|
||||||
|
println(example.lazyValue) // 여기서 초기화 발생
|
||||||
|
println(example.lazyValue) // 이미 초기화됨, 출력만 함
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**출력 결과:**
|
||||||
|
```
|
||||||
|
객체 생성 완료
|
||||||
|
초기화 중...
|
||||||
|
Hello, Kotlin!
|
||||||
|
Hello, Kotlin!
|
||||||
|
```
|
||||||
|
> - `by lazy`는 **최초 접근 시점에만 실행됨**
|
||||||
|
> - 이후에는 **이미 생성된 값을 사용**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **6. `object` 키워드: 싱글톤 객체**
|
||||||
|
코틀린에서 싱글톤 객체를 만들 때 **`object` 키워드**를 사용한다.
|
||||||
|
```kotlin
|
||||||
|
object Singleton {
|
||||||
|
fun showMessage() {
|
||||||
|
println("싱글톤 객체 실행!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
Singleton.showMessage()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**출력 결과:**
|
||||||
|
```
|
||||||
|
싱글톤 객체 실행!
|
||||||
|
```
|
||||||
|
> - **별도의 인스턴스 생성 없이** `Singleton.showMessage()` 사용 가능
|
||||||
|
> - **앱 설정, 네트워크 요청 관리 등에 유용**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **🔹 정리: 코틀린의 특수 기능 요약**
|
||||||
|
| 기능 | 설명 | 사용 예시 |
|
||||||
|
|------|------|------|
|
||||||
|
| `inline` 함수 | 함수 호출을 줄이고 성능 향상 | `inline fun execute(block: () -> Unit) {}` |
|
||||||
|
| `reified` | 실행 시점에서도 제너릭 타입 유지 | `inline fun <reified T> getType() = T::class.simpleName` |
|
||||||
|
| 제너릭 | 코드의 재사용성과 타입 안정성 유지 | `class Box<T>(val value: T)` |
|
||||||
|
| Delegation | 클래스 기능을 다른 객체에 위임 | `class PrinterImpl : Printer by ConsolePrinter()` |
|
||||||
|
| `by lazy` | 지연 초기화 | `val name: String by lazy { "코틀린" }` |
|
||||||
|
| `object` | 싱글톤 객체 | `object Singleton {}` |
|
||||||
|
|
||||||
|
코틀린의 강력한 기능들을 활용하면 **코드를 더 간결하고 효율적으로 작성**할 수 있다.
|
||||||
|
이제 **직접 사용해보면서** 익숙해지자! 🚀
|
||||||
55
docs/README.md
Normal file
55
docs/README.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
### **코틀린 원포인트 레슨: 자바 개발자를 위한 빠른 학습서**
|
||||||
|
#### **목차**
|
||||||
|
|
||||||
|
#### **1. 코틀린 시작하기**
|
||||||
|
1.1 코틀린의 특징과 철학
|
||||||
|
1.2 자바 코드와의 상호운용성
|
||||||
|
1.3 코틀린 개발 환경 설정 (IntelliJ, Gradle, Maven)
|
||||||
|
|
||||||
|
#### **2. 기본 문법과 차이점**
|
||||||
|
2.1 변수 선언: `val`과 `var`
|
||||||
|
2.2 null 안전성: `?` 연산자와 `!!` 연산자
|
||||||
|
2.3 타입 추론과 `is` 연산자
|
||||||
|
|
||||||
|
#### **3. 함수형 프로그래밍 요소**
|
||||||
|
3.1 함수 선언 방식 (`fun` 키워드)
|
||||||
|
3.2 고차 함수와 람다 표현식
|
||||||
|
3.3 확장 함수와 확장 프로퍼티
|
||||||
|
|
||||||
|
#### **4. 객체지향 프로그래밍 차이점**
|
||||||
|
4.1 클래스와 생성자 (기본, 보조 생성자)
|
||||||
|
4.2 데이터 클래스와 자바의 `record` 비교
|
||||||
|
4.3 객체 선언 (`object`)과 싱글턴 패턴
|
||||||
|
4.4 `sealed class`와 `enum class`
|
||||||
|
|
||||||
|
#### **5. 코틀린 컬렉션과 스트림 API**
|
||||||
|
5.1 리스트, 맵, 셋 사용법
|
||||||
|
5.2 `filter`, `map`, `reduce` 활용법
|
||||||
|
5.3 자바 스트림 API와 비교
|
||||||
|
|
||||||
|
#### **6. 예외 처리와 흐름 제어**
|
||||||
|
6.1 `try-catch`와 `check` 키워드
|
||||||
|
6.2 `when` 표현식과 자바의 `switch` 비교
|
||||||
|
|
||||||
|
#### **7. 코루틴과 비동기 프로그래밍**
|
||||||
|
7.1 `suspend` 함수와 `async/await`
|
||||||
|
7.2 `launch`, `runBlocking`, `withContext` 개념
|
||||||
|
|
||||||
|
#### **8. 코틀린의 특수 기능**
|
||||||
|
8.1 `inline` 함수와 `crossinline`, `noinline`
|
||||||
|
8.2 `reified` 키워드와 제네릭
|
||||||
|
8.3 `delegation` 패턴과 `by` 키워드
|
||||||
|
|
||||||
|
#### **9. 코틀린을 활용한 실제 개발**
|
||||||
|
9.1 Spring Boot에서 코틀린 활용하기
|
||||||
|
9.2 Android 개발에서 코틀린 적용하기
|
||||||
|
9.3 Kotlin DSL과 Gradle 설정
|
||||||
|
|
||||||
|
#### **10. 자바에서 코틀린으로 마이그레이션**
|
||||||
|
10.1 코틀린으로 코드 변환 (IntelliJ 기능 활용)
|
||||||
|
10.2 자바-코틀린 혼용 프로젝트 관리
|
||||||
|
10.3 코틀린 도입 시 고려할 점
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
이 책의 핵심은 자바 개발자가 코틀린을 빠르게 이해하고 실무에서 바로 활용할 수 있도록 짧고 명확한 레슨으로 구성하는 것입니다. 추가하고 싶은 내용이 있으면 말해줘!
|
||||||
Reference in New Issue
Block a user