diff --git a/keyword/chapter04/img.png b/keyword/chapter04/img.png
new file mode 100644
index 0000000..ab4b9f7
Binary files /dev/null and b/keyword/chapter04/img.png differ
diff --git a/keyword/chapter04/img_1.png b/keyword/chapter04/img_1.png
new file mode 100644
index 0000000..8847a6e
Binary files /dev/null and b/keyword/chapter04/img_1.png differ
diff --git a/keyword/chapter04/img_2.png b/keyword/chapter04/img_2.png
new file mode 100644
index 0000000..d2337e6
Binary files /dev/null and b/keyword/chapter04/img_2.png differ
diff --git a/keyword/chapter04/img_3.png b/keyword/chapter04/img_3.png
new file mode 100644
index 0000000..75342f0
Binary files /dev/null and b/keyword/chapter04/img_3.png differ
diff --git a/keyword/chapter04/img_4.png b/keyword/chapter04/img_4.png
new file mode 100644
index 0000000..75342f0
Binary files /dev/null and b/keyword/chapter04/img_4.png differ
diff --git a/keyword/chapter04/keyword.md b/keyword/chapter04/keyword.md
new file mode 100644
index 0000000..21e42c3
--- /dev/null
+++ b/keyword/chapter04/keyword.md
@@ -0,0 +1,322 @@
+## 1. DI
+
+개발 상황에서 객체들은 서로 **의존**되어있을 수밖에 없다.
+
+### 그럼 DI란 무엇인가?
+
+### DI : Depedency Injection. (의존관계 주입)
+
+외부로부터 **의존성을 주입**하는 것을 말한다.
+여기서 **의존성**이란? `의존대상 B가 변하면, 그것이 A에 영향을 미친다.`
+
+우리가 의존 관계를 공부하다 보면, **강한 결합**과 **약한 결합**에 대해 접하게 된다.
+이것들은 **유지보수성**에 직결되는데 어떻게 직결되는 것일까?
+
+### 강한 결합이란?
+
+어떠한 객체가 다른 객체에 강한 의존성을 가지고 있음을 의미한다.
+아래 예시로 이해해보자.
+
+```java
+public class Person {
+ private Chicken chicken;
+
+ public Person(){
+ this.chicken = new Chicken();
+ }
+
+ public void startEat() {
+ chicken.eat();
+ }
+}
+
+public class Chicken {
+ public void eat() {
+ System.out.println("치킨을 먹는다.");
+ }
+}
+```
+
+Person 클래스의 멤버 변수 타입으로 Chicken 클래스가 존재한다.
+이때,
+1. Chicken 클래스가 없으면 Person 클래스를 정의할 수 없으며
+2. Chicken 클래스를 Pizza 클래스로 바꾸게 되면 Person 클래스의 코드 대부분을 수정해야 한다.
+
+`즉, Person 클래스가 Chicken 클래스에 의존한다!`
+
+이는 유지보수 면에서 좋지 않다.
+
+### 그럼 약한 결합이란?
+
+**인터페이스**를 사용하는 것이다.
+
+```java
+public interface Food {
+ void eat();
+}
+
+public class Chicken implements Food {
+ @java.lang.Override
+ public void eat() {
+ System.out.println("치킨을 먹는다.");
+ }
+}
+
+public class Pizza implements Food {
+ @java.lang.Override
+ public void eat() {
+ System.out.println("피자를 먹는다.");
+ }
+}
+
+public class Person {
+ private Food food;
+
+ public Person(Food food){
+ this.food = food;
+ }
+
+ public void startEat(){
+ food.eat();
+ }
+}
+```
+
+이처럼 Food 인터페이스를 사용하면, Chicken과 Pizza object를 모두 Food 타입에 대입할 수 있다.
+즉, Person 클래스 내부적으로 코드의 변경이 일어날 필요가 없다.
+이는 유지보수 면에서 매우 좋다.
+
+### 그럼 도대체 DI는 어떻게 구현되나?
+
+1. 생성자 주입 ******권장
+```java
+@Service
+public class UMC7thMember {
+ private final UMCRepository umcRepository;
+
+ @Autowired
+ public UMC7thMember(final UMCRepository umcRepository){
+ this.umcRepository = umcRepository;
+ }
+}
+```
+
+**객체가 생성될 때 필요한 의존성을 설정**하는 방식이다.
+이는 **객체의 불변성을 보장**해주기에 생성자 주입이 권장되는 이유이다.
+
+
+2. setter 주입
+
+```java
+@Service
+public class UMC7thMember {
+ private final UMCRepository umcRepository;
+
+ @Autowired
+ public setUMC7thMember(final UMCRepository umcRepository){
+ this.umcRepository = umcRepository;
+ }
+}
+```
+
+**생성자를 통해 의존성을 설정**하는 방식이다.
+이는 런타임에 의존성을 주입하기 때문에, 의존성이 없더라도 객체 생성이 가능하다.
+그러나 의존성을 주입받지 않은 상태에서 작동할 수 있으므로, **NullPointException 에러**가 발생할 수 있다.
+
+
+3. 필드 주입
+
+```java
+@Service
+public class UMC7thMember {
+ @Autowired
+ private final UMCRepository umcRepository;
+}
+```
+
+**필드에 직접 의존성을 설정**하는 방식이다.
+이것 역시 런타임에 의존성을 주입하기 때문에, 의존성이 없더라도 객체 생성이 가능하다.
+코드는 깔끔하지만, **명시적으로 드러나는 의존성이 없기에 의존성 구조를 이해하기 어렵다.**
+
+
+
+
+## 2. loC
+
+아래 예시는 일반적으로 자바에서 객체를 생성하는 방식이다.
+```java
+UMC7thMember umc7thMember = new UMC7thMember();
+```
+즉, 객체를 생성하고 사용하는 작업을 개발자가 직접 제어하는 것이다.
+
+### 개발자가 직접 객체를 생성하지 않고, 객체의 생성 및 관리를 외부에 위임한다면?
+
+이것이 바로 IoC, 제어의 역전이다.
+
+### IoC : Inversion of Control. (제어의 역전)
+
+사용할 객체를 직접 생성하지 않고, 객체의 생성과 관리를 **외부에 위임**하는 것이다.
+여기서 **외부**란? **"스프링 컨테이너"** 를 말한다.
+이렇게 객체의 관리를 컨테이너에 맡겨 제어권이 넘어간 것을 **제어의 역전**이라고 부른다.
+
+### 그렇다면 왜 IoC를 사용할까?
+
+1. 객체 간 결합도를 낮춘다.
+2. 유연한 코드 작성이 가능하다.
+3. 가독성이 좋다.
+4. 코드의 중복을 방지한다.
+5. 유지보수가 용이하다.
+
+
+#### IoC를 통해 DI와 AOP가 가능해지고, 우리는 비즈니스 로직에만 집중할 수 있다.
+#### 이러한 IoC를 통해서 달성할 수 있는 것이 바로 POJO이다.
+
+### POJO란 무엇일까?
+
+### POJO : Plain Old Java Object. (순수한 오래된 자바 객체)
+
+**객체 지향적인 원리에 충실**하면서 **환경과 기술에 종속되지 않고**, **필요에 따라 재활용**될 수 있도록 설계된 객체이다.
+이를 이용하여 프로그래밍 코드를 작성하는 것이 **POJO 프로그래밍**이다.
+
+### POJO 프로그래밍이라고 하기 위해 지켜야하는 규칙
+
+1. Java나 Java의 스펙에 정의된 것 이외에는 다른 기술이나 규약에 얽매이지 않아야 한다.
+2. 특정 환경에 종속적이지 않아야 한다. 즉, 독립적이어야 한다는 소리이다.
+
+### POJO 프로그래밍을 해야하는 이유가 있을까?
+
+1. 특정 환경이나 기술에 종속적이지 않으면 재사용이 가능하고 확장 가능한 유연한 코드 작성이 가능하다.
+2. 코드가 간결해지며 디버깅에도 유리하다.
+3. 객체지향적인 설계를 제한없이 적용할 수 있다.
+
+
+
+
+
+
+## 3. 프레임워크와 API의 차이
+
+### 프레임워크란 무엇일까?
+
+**어떠한 목적을 쉽게 달성할 수 있도록 해당 목적과 관련된 코드의 뼈대를 미리 만들어둔 것**과 같다.
+우리는 프레임워크에 의존하여 개발하고, 프레임워크가 정의한 규칙을 준수해야 한다.
+즉, **프레임이라는 뼈대 위에서 프로그램을 개발**하는 것이다.
+
+### API란 무엇일까?
+
+### API : Application Programming Interface
+
+**2개 이상의 소프트웨어 컴포넌트 사이에서 상호작용할 수 있도록 정의된 인터페이스**를 말한다.
+즉, 응용 프로그램을 만드는데 필요한 **연결 장치 또는 매개체**라고 생각하면 된다.
+API가 필요한 이유는? 개발을 할 때 모든 것을 혼자 개발할 수는 없기 때문에.
+
+### 프레임워크 vs API
+
+한마디로 정의해보자면,
+
+### 프레임워크는 프레임워크가 나를 호출하는 방식이고,
+### API는 내가 API를 호출하는 방식이다!
+
+
+
+
+## 4. AOP
+
+### AOP : Aspect Oriented Programming (관점 지향 프로그래밍)
+
+부가 기능을 핵심 기능에서 분리해 한 곳으로 관리하도록 하고, 이 부가 기능을 어디에 적용할지 선택하는 기능을 합한 하나의 모듈이다.
+즉, 흩어진 관심사를 Aspect로 모듈화하고 핵심적인 비즈니스 로직에서 분리하여 재사용하겠다는 것이 AOP의 취지이다.
+
+### AOP 용어 정리
+
+![img_2.png](img_2.png)
+![img_4.png](img_4.png)
+
+### AOP의 적용 방식
+
+- 컴파일 시점
+- 클래스 로딩 시점
+- 런타임 시점 (프록시 사용)
+
+컴파일 시점과 클래스 로딩 시점에는 AspectJ 프레임워크를 직접 사용해야 해서 번거롭다.
+따라서, 주로 런타임 시점 적용 방식을 사용하는 스프링 AOP를 사용한다.
+
+스프링 AOP를 적용하기 위해서는 @Aspect 애노테이션을 작성해야 한다.
+아래 예시를 참고하자.
+```java
+@Aspect
+public class LogTraceAspect {
+ @Around("execution(* hello.proxy.app..*(..))")
+ public Object execute(ProceedingJoinPoint joinPoint) {
+ ...
+ }
+}
+```
+
+** 스프링 AOP 적용 시에는 private, final 메소드는 AOP 적용이 불가하다. **
+
+
+
+
+## 5. 서블릿
+
+### Servlet
+
+웹 애플리케이션에서 **클라이언트의 요청을 처리하고, 그에 대한 응답을 생성**하는 중요한 구성 요소이다.
+즉, **HTTP 요청을 처리**하는 역할을 한다.
+
+아래 사진을 통해 서블릿에 대해 자세히 알아보자.
+![img_1.png](img_1.png)
+
+1. 클라이언트가 URL을 입력하면 HTTP Request가 Servlet Container로 전송한다.
+2. 전송받은 Servlet Container는 HttpServletRequest, HttpServletResponse 객체를 생성한다.
+3. web.xml을 기반으로 사용자가 요청한 URL이 어느 Servlet에 대한 요청인지 찾는다.
+4. 해당 Servlet에서 service() 메소드를 호출하고, 클라이언트의 GET, POST 여부에 따라 doGet() 또는 doPost()를 호출한다.
+5. 이 메소드들은 동적 페이지를 생성한 후, HttpServletResponse 객체에 응답을 보낸다.
+6. 응답이 끝나면 HttpServletRequest, HttpServletResponse는 소멸시킨다.
+
+### 그럼 여기서 Servlet Container는 무엇인가?
+
+Servlet을 관리해주는 컨테이너이다.
+이는 클라이언트의 요청을 받아주고 응답할 수 있도록 웹 서버와 소켓으로 통신한다.
+
+#### 추가적인 역할
+
+1. Servlet 생명주기 관리
+2. 멀티스레드 지원 및 관리
+3. 선언적인 보안 관리
+
+### Servlet 중 가장 중요한 것은?
+
+### DispatcherServlet.
+
+모든 HTTP protocol로 들어오는 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 front controller이다.
+
+#### 장점
+
+과거에는 모든 Servlet을 URL 매핑을 위해 web.xml에 모두 등록해주어야 했지만, DispatcherServlet이 해당 애플리케이션에 들어오는 모든 요청을 핸들링해주고 공통 작업을 처리하면서 상당히 편리하게 이용 가능해졌다.
+즉, 우리는 컨트롤러를 구현해두기만 하면 DispatcherServlet이 알아서 적합한 컨트롤러로 위임을 해주는 구조이다.
+
+#### 동작 과정
+
+아래 코드를 참고하며 살펴보자.
+```java
+@Controller
+public class MyController {
+ @GetMapping("/umc")
+ public String hello(Model model){
+ model.addAttribute("message", "UMC Spring Fighting!");
+ return "greeting";
+ }
+}
+```
+
+1. 클라이언트가 '/umc' URL로 Http Request가 들어오면, 이는 DispatcherServlet으로 전달된다.
+2. DispatcherServlet은 해당 요청을 처리할 수 있는 적합한 controller를 찾는다. >> **Handler Mapping**
+3. controller는 요청 처리를 위해 hello() 메소드를 호출하고, 맞는 비즈니스 로직을 실행한 후 결과를 반환한다.
+4. 이 결과는 **ViewResolver**를 통해 적절한 View로 렌더링하고, Http Response로 HTML이나 JSON의 형태로 전달된다.
+
+
+
+
+
diff --git a/keyword/chapter05/img.png b/keyword/chapter05/img.png
new file mode 100644
index 0000000..bb71d7f
Binary files /dev/null and b/keyword/chapter05/img.png differ
diff --git a/keyword/chapter05/keyword.md b/keyword/chapter05/keyword.md
new file mode 100644
index 0000000..d79104d
--- /dev/null
+++ b/keyword/chapter05/keyword.md
@@ -0,0 +1,211 @@
+## 1. Domain
+
+**해결하고자 하는 문제의 영역**을 도메인이라고 한다.
+쉽게, **요구사항이나 문제 영역** 등을 예시로 들 수 있다.
+도메인은 주로 애플리케이션의 핵심 비즈니스 로직이나 데이터를 표현하는 객체들을 의미하며, '도메인 객체' 또는 '도메인 모델'이라고도 불린다.
+
+### 도메인 객체의 특징
+
+1. 비즈니스 로직을 캡슐화한다.
+2. 상태(변수)와 동작(메서드)을 함께 가진다.
+3. 데이터베이스의 테이블과 매핑되어 ORM 프레임워크를 통해 데이터를 저장하거나 불러올 수 있다.
+이는 엔티티로 정의되어 데이터베이스와 직접 연동이 가능하다.
+
+### 도메인 객체와 관련된 개념
+
+1. **entity** : 고유한 식별자를 갖는 도메인 객체이다. 보통 데이터베이스의 테이블에 매핑된다.
+2. **value object** : 고유 식별자가 필요하지 않고, 다른 객체에 포함되는 데이터 객체이다.
+3. **aggregate** : 비즈니스적으로 밀접하게 관련된 entity와 value의 모음이다.
+
+그렇다면, **웹 애플리케이션 계층 구조에서의 domain**은 무엇일까?
+
+![img.png](img.png)
+
+**Domain** : 엔티티 선언을 통해 DB에 저장되는 객체들을 구현한다.
+즉, 테이블의 각 column들이 하나의 도메인이라고 볼 수 있다.
+
+예시 코드를 봐보자.
+
+```java
+public class Member {
+ private Long id;
+ private String name;
+
+ public Long getId() {
+ return id;
+ }
+
+ pbulic void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
+```
+
+
+
+
+## 2. 양방향 매핑
+
+테이블 간의 연관 관계 매핑에는 단방향 매핑과 양방향 매핑이 있다.
+양방향 매핑을 공부하기 전에 단방향 매핑에 대해 간단히 짚고 넘어가자.
+
+### 단방향 매핑이란?
+
+**연관 관계 주인에게만 연관 관계를 주입**하는 것이다.
+그렇다면 여기서 연관 관계 주인이란 무엇일까?
+
+### 연관 관계 주인
+
+실제 데이터베이스에서 외래키를 가지는 엔티티, 즉 테이블을 의미한다.
+
+### 연관 관계 주인 설정은 어떻게?
+
+<단방향 매핑의 경우>
+- **1:N**의 경우 : N에 해당하는 테이블이 외래키를 가지며 N에 해당하는 엔티티를 주인으로 설정한다.
+- **1:1**의 경우 : 둘 중 하나만 외래키를 가지면 되기에 원하는 엔티티를 주인으로 설정한다.
+
+이때, N:1에서 N에 해당하는 엔티티가 1에 해당하는 엔티티와 연관 관계를 매핑할 때 사용하는 어노테이션은 무엇일까?
+
+### @ManyToOne과 실제 데이터베이스에서 해당 외래키의 이름을 설정하는 @JoinColumn.
+
+
+
+그렇다면 이제 양방향 매핑에 대해 알아보자.
+
+### 양방향 매핑이란?
+
+**연관 관계 주인이 아닌 엔티티에게도 연관 관계를 주입**하는 것이다.
+
+<양방향 매핑의 경우>
+- **1:N**의 경우 : 1에 해당하는 엔티티에게 설정한다.
+
+이때 사용하는 어노테이션은
+
+### @OneToMany(mappedBy=" ", -) 이다.
+
+이는 1에 해당하는 엔티티가 N에 해당하는 엔티티와 관계가 있음을 명시한다.
+N에 해당하는 엔티티에서 ManyToOne이 설정된 멤버변수를 mappedBy한다.
+
+### 양방향 매핑의 장점은 뭘까?
+
+- 양방향 매핑으로 인한 객체 그래프 탐색이 프로그래밍을 굉장히 편리하게 해준다.
+- cascade의 설정이 가능하다.
+
+### cascade란?
+
+**참조 대상인 테이블의 칼럼이 삭제될 때 같이 삭제되거나 변경이 될 때 같이 변경이 되는 기능**이다.
+이는 JPA에서 연관관계의 주인이 아닌, 참조의 대상이 되는 엔티티에 설정하여 사용 가능하다.
+> 즉, 단방향 매핑 만으로는 cascade 설정을 하는 것에 문제가 있다는 것이다.
+
+단, 양방향 매핑을 할 경우 연관 관계 편의 메서드가 필요하다.
+
+### 연관 관계 편의 메서드란?
+
+연관 관계를 설정하는 메서드이다.
+예시로 이해해보자.
+
+```java
+// 일반적인 코드
+member.setTeam(team);
+team.getMembers().add(member);
+
+// 연관 관계 편의 메서드를 사용한 코드
+public void setTeam(Team team){
+ this.team = team;
+ team.getMembers().add(this);
+}
+```
+
+양방향 매핑에서는 따로따로 사용하다가 한 줄을 넣지 않아 둘 중 하나만 호출이 되어 양방향이 깨지는 상황을 대비하여 두 코드를 하나의 것처럼 사용하는 것이 안전하다.
+
+### 양방향 매핑의 문제점
+
+1. **순환 참조 문제**
+- 양방향 매핑은 순환 구조를 만들어, 객체가 서로를 참조하는 무한 루프에 빠질 수 있다.
+- 이로 인해 예외가 발생할 수 있으며, 이 문제를 방지하려면 별도의 로직이나 설정이 필요하다.
+2. **데이터 일관성 문제**
+- 양방향 매핑은 양쪽의 데이터가 항상 일치해야 한다.
+- 한 쪽의 엔티티에서 수정하면 다른 쪽에서도 동일한 변경이 이루어져야 하므로, 이를 위한 추가적인 코드가 필요하다.
+- 이 과정을 처리하지 않는다면 데이터 불일치가 발생할 수 있다.
+
+
+
+
+## 3. N + 1 문제
+
+ORM 기술에서 특정 객체를 대상으로 수행한 쿼리가 해당 객체가 가지고 있는 **연관관계 또한 조회하게 되면서 N번의 추가적인 쿼리가 발생**하는 문제를 말한다.
+
+### 왜 발생할까?
+
+**관계형 데이터베이스와 객체지향 언어간의 패러다임 차이**로 인해 발생한다.
+객체는 연관관계를 통해 레퍼런스를 가지고 있으면 언제든지 메모리 내에서 Random Access를 통해 연관 객체에 접근할 수 있지만, RDB의 경우 Select 쿼리를 통해서만 조회할 수 있기 때문.
+
+### N+1 문제를 Eager Loading으로 해결할 수 있을까?
+
+부분적으로 해결해줄 수는 있겠지만, **권장하지 않는다.**
+그럼 여기서 말하는 Eager Loading은 뭘까?
+
+### Eager Loading
+
+**연관된 entity 객체를 한 번에 조회하도록 하는 기능**이다.
+이를 사용한다면, 어떤 entity 연관 관계 범위까지 join 쿼리로 조회해올지 예상하기 어려워 필요없는 데이터까지 로딩하여 비효율적일 수 있다.
+
+그럼 N+1 문제를 해결하기 위한 방법에는 뭐가 있을까?
+
+### Fetch Join + Lazy Loading
+
+Root entity에 대해서 조회할 때 Lazy Loading으로 설정되어 있는 연관 관계를 join 쿼리를 발생시켜 한 번에 조회할 수 있는 기능이다.
+
+#### Fetch Join vs 일반 Join
+
+Fetch Join은 ORM에서의 사용을 전제로 DB Schema를 entity로 자동 변환 해주고 영속성 컨텍스트에 영속화해준다.
+
+- **Fetch Join으로 조회** : 연관 관계는 영속성 컨텍스트 1차캐시에 저장되어 다시 entity 그래프를 탐색하더라도 조회 쿼리가 수행되지 않는다.
+- **일반 Join으로 조회** : 단순히 데이터를 조회하는 개념으로 영속성 컨텍스트나 entity와는 무관하다.
+
+따라서, Fetch Join을 활용하면 ORM 활용이 가능하여 RDB와의 패러다임 차이를 줄일 수 있다.
+
+#### Collection 연관 관계 Fetch Join 시 주의사항
+
+Collection에 대해서 Fetch Join을 할 경우, 1:N 관계이기에 1쪽의 데이터는 중복된 상태로 조회된다.
+이를 방지하려면? distinct 절을 활용해야한다. >> 중복되는 entity 제거 가능.
+
+### Lazy Loading
+
+**데이터가 실제로 필요할 때까지 로드하지 않고 대기하는 기법**이다.
+즉, 객체나 리소스를 미리 로드하지 않고, 사용자가 요청하거나 액세스할 때 로드하는 방식이다.
+> 데이터베이스에서 관련 entity를 가져올 때, 연관된 모든 데이터를 처음부터 다 가져오는 대신 실제로 접근할 때까지 대기.
+
+#### 장점
+
+1. 사용하지 않는 데이터를 메모리에 로드하지 않으므로, 메모리를 절약할 수 있다.
+2. 필요한 데이터만 가져오므로, 초기 응답 시간이 줄어들 수 있다.
+3. 트랜잭션 처리 시간을 최적화할 수 있다.
+
+#### 단점
+
+1. Lazy Loading을 부적절하게 사용하면 N+1 문제가 발생할 수 있다.
+2. 코드가 복잡해질 수 있으며, 어느 시점에 데이터가 로드되는지 예측하기 어렵다.
+3. 트랜잭션 경계를 벗어나 데이터를 로드하려고 하면 오류가 발생할 수 있다.
+
+### default_batch_fetch_size, @BatchSize
+
+이러한 Lazy Loading 시 프록시 객체를 조회할 때 where in 절로 묶어서 한 번에 조회할 수 있게 해주는 옵션이다.
+yml에 전역 옵션으로 적용할 수도 있으며, @BatchSize를 통해 연관 관계 BatchSize를 다르게 적용할 수도 있다.
+
+### Fetch Join vs BatchSize
+
+Collection Fetch Join 시 paging 문제나 1개까지만 Fetch Join을 할 수 있다는 한계들을 BatchSize는 해결할 수 있다.
+
+### 만약, 많은 컬럼 중 특정 컬럼만 조회해야 하는 경우나 커버링 인덱스를 활용하고 싶은 경우 데이터 전송량을 줄이고 싶다면?
+
+일반 Join을 하고 Projection하여 Dto로 변환하여 조회하는 방법이 있다.
+이 방식을 사용하는 쿼리는 DAO를 분리하는 것이 좋다.
\ No newline at end of file
diff --git a/keyword/chapter06/keyword.md b/keyword/chapter06/keyword.md
new file mode 100644
index 0000000..e69de29
diff --git a/mission/chapter04/img.png b/mission/chapter04/img.png
new file mode 100644
index 0000000..a320a6b
Binary files /dev/null and b/mission/chapter04/img.png differ
diff --git a/mission/chapter04/mission.md b/mission/chapter04/mission.md
new file mode 100644
index 0000000..70cd622
--- /dev/null
+++ b/mission/chapter04/mission.md
@@ -0,0 +1,199 @@
+## 1. 함수형 인터페이스
+
+**함수를 위한 인터페이스**로, 이 인터페이스를 구현한 클래스는 **하나의 함수처럼 동작**하게 된다.
+이는 static 메소드와 default 메소드가 아닌 추상 메소드를 딱 하나만 가져야 한다.
+함수형 인터페이스는 아래와 같이 사용할 수 있다.
+
+```java
+@FunctionalInterface
+public interface Function{
+
+}
+```
+
+이 경우는 T라는 타입을 입력 받아 R이라는 타입을 출력한다.
+즉, `Function`의 경우에는 String을 입력 받아 Integer를 출력한다고 볼 수 있다.
+
+### 함수형 인터페이스 종류
+
+| 함수형 인터페이스 이름 | 설명 | 추상 메소드 |
+|:---------------------:|:------------------------------:|:-------------------:|
+| Function | 타입 T를 받아 타입 R을 반환 | R apply(T t) |
+| Consumer | 타입 T를 받아 소비 | void accept(T t) |
+| Supplier | 타입 T를 반환 | T get() |
+| Predicate | 타입 T를 받아 boolean을 반환 | boolean test(T t) |
+| BiFunction | 타입 T, U를 받아 타입 R을 반환 | R apply(T t, U u) |
+| UnaryOperator | 타입 T를 받아 타입 T를 반환 | - |
+| BinaryOperator | 동일한 타입의 입력값 두 개를 받아 동일 타입 반환 | - |
+
+크게 4개만 살펴보자.
+
+#### Function
+
+주로 T 타입의 객체를 받아 다른 형태 R로 변환하는데 사용된다.
+이 메소드를 호출할 때 생성자 참조 방식을 이용해서 정수 값을 문자열로 변환하고 변환된 문자열을 출력한다.
+```java
+public static void print(Function function, int value) {
+ System.out.println(function.apply(value));
+}
+
+// 메소드 호출
+print(Object::toString, 5);
+// 출력 : 5
+```
+
+#### Consumer
+
+한 개의 입력을 받아서 결과를 반환하지 않는 함수를 정의한다.
+주로 입력값을 이용한 연산이나 출력 등의 동작에 사용된다.
+```java
+public static void printList(Consumer consumer, List list) {
+ for (String item : list) {
+ consumer.accept(item);
+ }
+}
+
+// 메소드 호출
+printList(System.out::println, Arrays.asList("Apple", "Banana", "Cherry"));
+// 출력:
+// Apple
+// Banana
+// Cherry
+```
+
+#### Supplier
+
+입력 없이 결과를 반환하는 함수를 정의한다.
+주로 파라미터 없이 특정 결과를 생성하는데 사용된다.
+```java
+public static void print(Supplier supplier) {
+ System.out.println(supplier.get());
+}
+
+// 메소드 호출
+print(() -> "안녕하세요!");
+// 출력: 안녕하세요!
+```
+
+위의 경우, 람다식을 이용해 문자열을 출력한다.
+
+#### Predicate
+
+한 개의 입력을 받아서 boolean 결과를 반환하는 함수를 정의한다.
+주로 객체를 조건에 따른 필터링이 필요할 때 사용된다.
+```java
+public static void print(Predicate predicate, int value) {
+ if (predicate.test(value)) {
+ System.out.println(value);
+ }
+}
+
+// 메서드 호출
+print(x -> x > 5, 10);
+// 출력: 10
+```
+위의 경우 역시, 람다식을 이용해 조건을 만족하면 value 값이 출력된다.
+
+> AOP처럼 공통적인 기능을 한 곳에서 관리하고, 핵심 기능만을 분리할 수는 없는지 생각하다가,
**함수형 인터페이스를 사용해 함수로 추상화하여 재사용가능한 코드를 만들 수 있다!**
+
+### 문제풀이
+
+```java
+import java.util.function.Function;
+
+// Function 인터페이스를 상속받은 클래스
+class ExFunction implements Function {
+ @Override
+ public String apply(Integer integer) {
+ return String.valueOf(integer);
+ }
+}
+
+public class Main {
+ public static void main(String[] args) {
+ // 1. 익명클래스 정의
+ Function function1 = new Function() {
+ @Override
+ public String apply(Integer integer) {
+ return String.valueOf(integer);
+ }
+ };
+ System.out.println(function1.apply(111)); // 출력: "111"
+
+ // 2. 클래스 파일을 만들어 상속받아서 정의
+ ExFunction function2 = new ExFunction();
+ System.out.println(function2.apply(222)); // 출력: "222"
+
+ // 3. 람다식으로 정의
+ Function function3 = integer -> String.valueOf(integer);
+ System.out.println(function3.apply(333)); // 출력: "333"
+
+ // 4. 메서드 참조로 정의
+ Function function4 = String::valueOf;
+ System.out.println(function4.apply(444)); // 출력: "444"
+ }
+}
+```
+
+### 질문
+
+Q. 람다식을 사용해서 함수형 인터페이스를 어떻게 간결하게 표현하고 람다식을 사용했을 때의 장점은 무엇이 있나요?
+
+A. 익명 클래스를 사용한 경우를 예로 들면, 전통적인 방법인 오버라이드를 할 필요 없이 `integer -> String.valueOf(integer)`를 통해 간결하게 나타낼 수 있습니다.
+
또한, 불필요한 클래스 정의와 메소드 오버라이드를 생략할 수 있어서 코드가 간결해지고 가독성이 올라갑니다.
+
+
+
+
+## 2. stream api
+
+데이터를 추상화하고, 처리하는데 자주 사용되는 함수들을 정의한다.
+여기서 **데이터를 추상화**한다는 것은? **데이터의 종류에 상관없이 같은 방식으로 데이터를 처리**할 수 있음을 의미한다.
+
+#### 특징
+
+1. 원본의 데이터를 변경하지 않는다.
+2. Stream은 일회용이기 때문에 한 번 사용이 끝나면 재사용이 불가능하다.
+3. 내부 반복으로 작업을 처리한다. 따라서 코드가 간결해진다.
+
+#### 과정
+![img.png](img.png)
+1. Stream 생성
+2. 중간 연산
+3. 최종 연산
+
+#### 장점
+
+- 훨씬 간결해지고 명료해져서 소스코드의 가독성이 좋아진다.
+- 코드를 직접 개발한 개발자가 아니어도 코드의 구조를 한눈에 알아보기 쉬워 유지보수 및 인수인계 시에도 어려움없이 작업이 가능하다.
+- 병렬처리를 지원하기에 대량의 데이터를 빠르고 쉽게 처리할 수 있다.
+
+### 문제풀이
+
+```java
+import java.util.Arrays;
+
+public class ExStream {
+ public static void main(String[] args) {
+ int[] arr = {1,2,3,4,5,6,7,8,9,10};
+ int[] doubledArr = Arrays.stream(arr)
+ .map(x->x*2)
+ .toArray();
+
+ System.out.println("원본 배열 : " + Arrays.toString(arr));
+ System.out.println("2배 배열 : " + Arrays.toString(doubledArr));
+
+ String[] evenArr = Arrays.stream(arr)
+ .filter(x->x%2==0)
+ .map(x->x + "is even number")
+ .toArray(String[]::new);
+
+ System.out.println("짝수 배열 : " + Arrays.toString(evenArr));
+ }
+}
+```
+
+### 질문
+
+Q. 스트림의 요소들을 변환하거나 필터링하는 등의 중간 연산은 그때 그떄 실행되는가?
+A. 아니다. 중간 연산은 실행되고 있지 않다가 최종 연산을 만나게 되면, 그때 중간 연산이 실제로 수행된다.
\ No newline at end of file