diff --git a/app.sh b/app.sh new file mode 100755 index 0000000..4d805c6 --- /dev/null +++ b/app.sh @@ -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 diff --git a/docs/02_기본 문법.md b/docs/02_기본 문법.md new file mode 100644 index 0000000..edefcf7 --- /dev/null +++ b/docs/02_기본 문법.md @@ -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;`
`final int y = 20;` | `var x = 10`
`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 걱정 없이 더 안전한 프로그래밍**이 가능해진다. + +다음에는 어떤 코틀린 개념을 비교해볼까? \ No newline at end of file diff --git a/docs/03_함수형 프로그래밍.md b/docs/03_함수형 프로그래밍.md new file mode 100644 index 0000000..8ef0fda --- /dev/null +++ b/docs/03_함수형 프로그래밍.md @@ -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 sum = (a, b) -> a + b; +System.out.println(sum.apply(5, 3)); // 출력: 8 +``` +> 자바에서는 `BiFunction` 같은 **함수형 인터페이스**를 사용해야 람다를 활용할 수 있다. + +### **코틀린의 람다 표현식** +```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 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()` | + +코틀린은 자바보다 함수형 프로그래밍을 **더 자연스럽고 간결하게 지원**한다. + +다음에는 어떤 개념을 비교해볼까? \ No newline at end of file diff --git a/docs/04_OOP.md b/docs/04_OOP.md new file mode 100644 index 0000000..8f9e5ea --- /dev/null +++ b/docs/04_OOP.md @@ -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` 접근 제어자** | 같은 패키지 + 하위 클래스 접근 가능 | 오직 하위 클래스만 접근 가능 | + +코틀린은 **객체지향 프로그래밍을 더 간결하고 효율적으로 작성할 수 있도록 개선**된 언어다. +다음에는 어떤 개념을 비교해볼까? \ No newline at end of file diff --git a/docs/05_컬렉션.md b/docs/05_컬렉션.md new file mode 100644 index 0000000..f9f2d49 --- /dev/null +++ b/docs/05_컬렉션.md @@ -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 immutableList = List.of("A", "B", "C"); // Java 9+ +List 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 names = List.of("Alice", "Bob", "Charlie"); +List 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 numbers = List.of(1, 2, 3, 4, 5, 6); +List 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를 더 쉽게 다룰 수 있다는 점을 기억하자!** \ No newline at end of file diff --git a/docs/06_예외 처리 및 흐름 제어.md b/docs/06_예외 처리 및 흐름 제어.md new file mode 100644 index 0000000..bfbbac9 --- /dev/null +++ b/docs/06_예외 처리 및 흐름 제어.md @@ -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 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`를 표현식으로 사용할 수 있어 +**보다 유연하고 직관적인 코드 작성이 가능**하다. 🚀 \ No newline at end of file diff --git a/docs/07_코루틴.md b/docs/07_코루틴.md new file mode 100644 index 0000000..795115d --- /dev/null +++ b/docs/07_코루틴.md @@ -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` 반환 | 결과 값을 반환하는 비동기 작업 | + +### **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` 사용 가능 | +| 실행 효율 | 스레드 사용 | 가벼운 코루틴 사용 | + +> **코루틴을 사용하면:** +> ✅ **비동기 코드가 더 간결하고 직관적** +> ✅ **콜백 지옥 없이 순차적 스타일로 작성 가능** +> ✅ **스레드보다 가볍고 효율적** + +코틀린에서 **비동기 프로그래밍을 쉽게 구현하려면 코루틴을 적극 활용하자!** 🚀 \ No newline at end of file diff --git a/docs/08_특수 기능.md b/docs/08_특수 기능.md new file mode 100644 index 0000000..6fd4d21 --- /dev/null +++ b/docs/08_특수 기능.md @@ -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 getClassName(): String { + return T::class.simpleName // 오류 발생! +} + +fun main() { + println(getClassName()) +} +``` +> - 오류 발생! **제너릭 타입은 실행 시점에서 사라지기 때문**. + +### **2.2. `reified` 키워드 사용하여 해결** +```kotlin +inline fun getClassName(): String { + return T::class.simpleName ?: "알 수 없음" +} + +fun main() { + println(getClassName()) // "String" + println(getClassName()) // "Int" +} +``` +> - **`reified`를 사용하면 실행 시점에서도 제너릭 타입을 알 수 있음** +> - 주의: **`inline` 함수에서만 `reified` 사용 가능** + +--- + +## **3. 제너릭(Generic): 타입을 유연하게 만들기** +제너릭을 사용하면 **코드의 재사용성을 높이고, 타입 안정성을 유지할 수 있음**. + +### **3.1. 기본적인 제너릭 사용** +```kotlin +class Box(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 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 getType() = T::class.simpleName` | +| 제너릭 | 코드의 재사용성과 타입 안정성 유지 | `class Box(val value: T)` | +| Delegation | 클래스 기능을 다른 객체에 위임 | `class PrinterImpl : Printer by ConsolePrinter()` | +| `by lazy` | 지연 초기화 | `val name: String by lazy { "코틀린" }` | +| `object` | 싱글톤 객체 | `object Singleton {}` | + +코틀린의 강력한 기능들을 활용하면 **코드를 더 간결하고 효율적으로 작성**할 수 있다. +이제 **직접 사용해보면서** 익숙해지자! 🚀 \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..66cd266 --- /dev/null +++ b/docs/README.md @@ -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 코틀린 도입 시 고려할 점 + +--- + +이 책의 핵심은 자바 개발자가 코틀린을 빠르게 이해하고 실무에서 바로 활용할 수 있도록 짧고 명확한 레슨으로 구성하는 것입니다. 추가하고 싶은 내용이 있으면 말해줘! \ No newline at end of file