<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yjs_177076.log</title>
        <link>https://velog.io/</link>
        <description>우당탕탕 개발 일기</description>
        <lastBuildDate>Sat, 02 Nov 2024 01:21:39 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yjs_177076.log</title>
            <url>https://velog.velcdn.com/images/yjs_177076/profile/b3d9a780-dde4-452b-a7ee-22bd58a081f0/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yjs_177076.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yjs_177076" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[JDBC, ORM, JPA, Hibernate, Spring Data JPA ]]></title>
            <link>https://velog.io/@yjs_177076/JDBC-ORM-JPA-Hibernate-Spring-Data-JPA</link>
            <guid>https://velog.io/@yjs_177076/JDBC-ORM-JPA-Hibernate-Spring-Data-JPA</guid>
            <pubDate>Sat, 02 Nov 2024 01:21:39 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yjs_177076/post/34fb8462-c0d9-4ea0-a69f-b7b38a4e8fe2/image.png" alt=""></p>
<h2 id="1-jdbc-java-database-connectivity">1. JDBC (Java Database Connectivity)</h2>
<ul>
<li>정의: 자바에서 데이터베이스에 연결하고 SQL 쿼리를 실행하기 위한 저수준 API입니다.</li>
<li>특징:
데이터베이스와의 연결, 쿼리 실행, 결과 처리 등을 수동으로 관리해야 합니다.
SQL을 직접 작성해야 하며, 코드가 길어질 수 있습니다.
성능은 좋지만, 유지보수가 어렵고 코드가 복잡해질 수 있습니다.</li>
</ul>
<h2 id="2-orm-object-relational-mapping">2. ORM (Object-Relational Mapping)</h2>
<ul>
<li>정의: 객체 지향 프로그래밍 언어의 객체와 관계형 데이터베이스의 데이터 간의 매핑을 자동으로 처리하는 기술입니다.</li>
<li>특징:
SQL 쿼리 없이 객체를 데이터베이스에 저장하거나 조회할 수 있도록 해줍니다.
코드의 가독성과 유지보수성을 높입니다.
ORM 구현체를 사용하면 객체와 데이터베이스 간의 변환을 자동으로 처리합니다.</li>
</ul>
<h2 id="3-jpa-java-persistence-api">3. JPA (Java Persistence API)</h2>
<ul>
<li>정의: 자바 EE의 스펙으로, ORM을 구현하기 위한 표준 API입니다.</li>
<li>특징:
데이터베이스와의 상호작용을 추상화하여, 객체를 영속화하는 방법을 정의합니다.
JPA를 사용하면 다양한 ORM 구현체(Hibernate, EclipseLink 등)를 교체할 수 있습니다.
JPA는 데이터베이스 작업을 객체 지향적으로 처리할 수 있도록 돕습니다.</li>
</ul>
<h2 id="4-hibernate">4. Hibernate</h2>
<ul>
<li>정의: JPA의 대표적인 구현체로, 가장 널리 사용되는 ORM 프레임워크입니다.</li>
<li>특징:
JPA의 모든 기능을 제공하며, 추가적인 기능(예: 세션 관리, 캐싱 등)을 갖추고 있습니다.
복잡한 쿼리, 관계 매핑, 트랜잭션 관리 등 다양한 기능을 지원합니다.
Hibernate는 JPA의 표준을 따르기 때문에 JPA로 작성된 코드를 사용할 수 있습니다.</li>
</ul>
<h2 id="5-spring-data-jpa">5. Spring Data JPA</h2>
<ul>
<li>정의: 스프링 프레임워크의 일부로, JPA를 쉽게 사용할 수 있도록 돕는 프로젝트입니다.</li>
<li>특징:
리포지토리 패턴을 사용하여 데이터 액세스를 단순화합니다.
기본 CRUD 메서드 및 쿼리를 자동으로 생성하여 개발자의 작업을 줄여줍니다.
JPA와 Hibernate를 쉽게 통합하여 사용할 수 있으며, 스프링의 다양한 기능(예: 트랜잭션 관리, AOP 등)을 활용할 수 있습니다.
관계 및 차이점
JDBC는 가장 기본적인 데이터베이스 연결 방식으로, ORM이나 JPA와는 독립적인 기술입니다.
ORM은 JDBC와 같은 저수준 API 대신 객체와 데이터베이스의 매핑을 자동으로 처리하는 개념입니다. JPA는 ORM의 표준 API입니다.
JPA는 ORM의 표준을 정의하는 것이고, Hibernate는 JPA의 구체적인 구현체입니다. 따라서 Hibernate는 JPA의 규칙을 따르면서 추가 기능을 제공합니다.
Spring Data JPA는 JPA를 쉽게 사용하기 위한 도구로, JPA/Hibernate와 함께 사용되며 데이터 액세스를 단순화합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[토비의 스프링-IoC, DI,DIP]]></title>
            <link>https://velog.io/@yjs_177076/%ED%86%A0%EB%B9%84%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-IoC-DIDIP</link>
            <guid>https://velog.io/@yjs_177076/%ED%86%A0%EB%B9%84%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-IoC-DIDIP</guid>
            <pubDate>Sat, 12 Oct 2024 00:47:52 GMT</pubDate>
            <description><![CDATA[<p>스프링(Spring) 프레임워크에서 자주 등장하는 개념인 IoC, DI, DIP는 모두 객체지향 설계 및 소프트웨어 개발 원칙과 관련이 있습니다. 각각의 개념을 설명하면서 그 차이점을 알아보겠습니다.</p>
<h3 id="1-ioc-inversion-of-control-제어의-역전">1. IoC (Inversion of Control, 제어의 역전)</h3>
<ul>
<li><strong>개념</strong>: IoC는 객체의 생성, 생명주기 관리, 의존성 주입 등과 같은 작업을 개발자가 아니라 프레임워크나 컨테이너가 대신 담당하는 것을 의미합니다. 즉, 프로그램의 제어 흐름이 사용자가 아닌 외부 프레임워크에 의해 제어된다는 의미입니다.</li>
<li><strong>스프링에서의 역할</strong>: 스프링 프레임워크는 IoC 컨테이너를 사용하여 객체의 생성과 관리를 책임집니다. 개발자는 객체 생성이나 의존성 관리에 신경 쓰지 않고 비즈니스 로직 구현에 집중할 수 있습니다.</li>
</ul>
<h3 id="2-di-dependency-injection-의존성-주입">2. DI (Dependency Injection, 의존성 주입)</h3>
<ul>
<li><strong>개념</strong>: DI는 객체 간의 의존성을 외부에서 주입하는 방식입니다. 즉, 객체가 스스로 의존 객체를 생성하거나 찾는 것이 아니라, 외부에서 필요한 객체를 주입받아 사용하는 방식입니다. 이는 의존성 관리의 한 방식으로, IoC의 한 구현 방법입니다.</li>
<li><strong>스프링에서의 역할</strong>: 스프링은 DI를 통해 객체 간의 의존성을 설정합니다. 이를 통해 코드의 결합도를 낮추고, 유지보수와 테스트가 쉬워집니다. DI 방식에는 크게 <strong>생성자 주입</strong>과 <strong>Setter 주입</strong> 두 가지가 있습니다.</li>
</ul>
<h3 id="3-dip-dependency-inversion-principle-의존성-역전-원칙">3. DIP (Dependency Inversion Principle, 의존성 역전 원칙)</h3>
<ul>
<li><strong>개념</strong>: DIP는 객체지향 설계의 원칙 중 하나로, 고수준 모듈이 저수준 모듈에 의존해서는 안 된다는 원칙입니다. 대신, 두 모듈 모두 추상화(인터페이스나 추상 클래스)에 의존해야 한다고 제안합니다. 이를 통해 고수준 모듈과 저수준 모듈 간의 의존성을 역전시키고, 유연성과 확장성을 높일 수 있습니다.</li>
<li><strong>차이점</strong>: DIP는 객체 지향 설계 원칙에 해당하며, DI는 이를 구현할 수 있는 하나의 방법론으로 볼 수 있습니다. DIP를 따르는 설계를 구현하기 위해 DI가 자주 사용됩니다.</li>
</ul>
<h3 id="정리">정리</h3>
<ul>
<li><strong>IoC</strong>는 제어권을 개발자가 아닌 프레임워크에 넘기는 개념.</li>
<li><strong>DI</strong>는 IoC의 한 구현 방식으로, 객체의 의존성을 외부에서 주입하는 방법.</li>
<li><strong>DIP</strong>는 객체 지향 설계 원칙으로, 고수준 모듈이 저수준 모듈에 의존하지 않도록 설계하는 것.</li>
</ul>
<p>스프링은 <strong>IoC 컨테이너</strong>를 통해 <strong>DI</strong>를 구현하고, 이를 통해 <strong>DIP</strong>와 같은 객체 지향 원칙을 따르는 설계를 유도합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링의 데이터 엑세스]]></title>
            <link>https://velog.io/@yjs_177076/%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%98-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%97%91%EC%84%B8%EC%8A%A4</link>
            <guid>https://velog.io/@yjs_177076/%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%98-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%97%91%EC%84%B8%EC%8A%A4</guid>
            <pubDate>Wed, 14 Feb 2024 06:42:39 GMT</pubDate>
            <description><![CDATA[<h3 id="🤓오늘의-공부-주제-jdbc-jpa-mybatis🤓">🤓오늘의 공부 주제: jdbc, jpa, mybatis🤓</h3>
<h3 id="q-스프링에서-데이터-엑세스는-어떻게-이루어지는가">Q. 스프링에서 데이터 엑세스는 어떻게 이루어지는가?</h3>
<blockquote>
<p>A. 스프링에서의 데이터 액세스는 주로 JDBC, JPA, 그리고 MyBatis를 사용하여 이루어진다.</p>
</blockquote>
<h3 id="q-jdbc는-무엇인가">Q. JDBC는 무엇인가?</h3>
<blockquote>
<p>A. JDBC는 자바에서 데이터베이스와의 연결과 쿼리 실행을 위한 API이다. 이를 사용하면 데이터베이스와 직접적인 연결을 설정하고 SQL 쿼리를 실행할 수 있다. </p>
</blockquote>
<p>JDBC를 사용하면 데이터베이스에 대한 세부적인 제어가 가능하며, 직접 SQL 쿼리를 작성하여 실행할 수 있다. 그러나 JDBC를 사용할 경우에는 보다 많은 코드 작성과 반복적인 작업이 필요할 수 있다.</p>
<h3 id="q-jdbc는-무엇인가-1">Q. JDBC는 무엇인가?</h3>
<blockquote>
<p>A. JDBC(ava Database Connectivity)는 자바에서 데이터베이스와의 연결과 쿼리 실행을 위한 API이다. 이를 사용하면 데이터베이스와 직접적인 연결을 설정하고 SQL 쿼리를 실행할 수 있다. </p>
</blockquote>
<p>JDBC를 사용하면 데이터베이스에 대한 세부적인 제어가 가능하며, 직접 SQL 쿼리를 작성하여 실행할 수 있다. 그러나 JDBC를 사용할 경우에는 보다 많은 코드 작성과 반복적인 작업이 필요할 수 있다.</p>
<h4 id="jdbc를-사용한-데이터베이스-연동">JDBC를 사용한 데이터베이스 연동</h4>
<pre><code class="language-java">import java.sql.*;

public class JdbcExample {
    public static void main(String[] args) {
        try {
            Class.forName(&quot;com.mysql.cj.jdbc.Driver&quot;);
            Connection con = DriverManager.getConnection(
                    &quot;jdbc:mysql://localhost:3306/mydatabase&quot;, &quot;username&quot;, &quot;password&quot;);

            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery(&quot;SELECT * FROM mytable&quot;);

            while (rs.next())
                System.out.println(rs.getInt(1) + &quot;  &quot; + rs.getString(2) + &quot;  &quot; + rs.getString(3));

            con.close();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
</code></pre>
<h3 id="q-jpa란-무엇인가">Q. JPA란 무엇인가?</h3>
<blockquote>
<p>A. JPA(Java Persistence API)는 자바에서 객체와 관계형 데이터베이스 간의 매핑을 지원하는 API이다. 객체지향 프로그래밍에서는 객체를 데이터베이스에 저장하고 검색하는 과정에서 객체와 테이블 간의 매핑이 필요한데, JPA는 이러한 작업을 간편하게 처리할 수 있도록 도와준다. </p>
</blockquote>
<p>JPA를 사용하면 객체와 테이블 간의 매핑을 어노테이션을 통해 설정할 수 있으며, 개발자는 객체를 중심으로 코드를 작성할 수 있다.</p>
<h4 id="jpa를-사용한-데이터베이스-연동">JPA를 사용한 데이터베이스 연동</h4>
<pre><code class="language-java">import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = &quot;mytable&quot;)
public class JpaExample {
    @Id
    private int id;
    private String name;
    private String email;

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(&quot;persistence-unit-name&quot;);
        EntityManager em = emf.createEntityManager();

        Query query = em.createQuery(&quot;SELECT e FROM JpaExample e&quot;);
        List&lt;JpaExample&gt; results = query.getResultList();

        for (JpaExample e : results)
            System.out.println(e.getId() + &quot;  &quot; + e.getName() + &quot;  &quot; + e.getEmail());

        em.close();
        emf.close();
    }

    // Getter and Setter methods
}
</code></pre>
<h3 id="q-mybatis는-무엇인가">Q. MyBatis는 무엇인가?</h3>
<blockquote>
<p>A. MyBatis는 SQL 매핑 프레임워크로, SQL 쿼리와 자바 객체 사이의 매핑을 XML 또는 어노테이션을 통해 설정할 수 있다. </p>
</blockquote>
<p>MyBatis를 사용하면 SQL 쿼리를 직접 작성하고 실행할 수 있으며, 동적 쿼리를 쉽게 처리할 수 있는 장점이 있다. 또한 MyBatis는 JDBC를 사용하고 있기 때문에 JDBC에 비해 더 빠르고 유연한 데이터 액세스가 가능하다. </p>
<h4 id="mybatis를-사용한-데이터베이스-연동">MyBatis를 사용한 데이터베이스 연동</h4>
<pre><code class="language-java">&lt;!-- mybatis-config.xml --&gt;
&lt;configuration&gt;
  &lt;environments default=&quot;development&quot;&gt;
    &lt;environment id=&quot;development&quot;&gt;
      &lt;transactionManager type=&quot;JDBC&quot;/&gt;
      &lt;dataSource type=&quot;POOLED&quot;&gt;
        &lt;property name=&quot;driver&quot; value=&quot;com.mysql.cj.jdbc.Driver&quot;/&gt;
        &lt;property name=&quot;url&quot; value=&quot;jdbc:mysql://localhost:3306/mydatabase&quot;/&gt;
        &lt;property name=&quot;username&quot; value=&quot;username&quot;/&gt;
        &lt;property name=&quot;password&quot; value=&quot;password&quot;/&gt;
      &lt;/dataSource&gt;
    &lt;/environment&gt;
  &lt;/environments&gt;
  &lt;mappers&gt;
    &lt;mapper resource=&quot;com/example/MyMapper.xml&quot;/&gt;
  &lt;/mappers&gt;
&lt;/configuration&gt;</code></pre>
<pre><code class="language-java">// MyMapper.xml
&lt;mapper namespace=&quot;com.example.MyMapper&quot;&gt;
  &lt;select id=&quot;selectUsers&quot; resultType=&quot;User&quot;&gt;
    SELECT * FROM mytable
  &lt;/select&gt;
&lt;/mapper&gt;
</code></pre>
<pre><code class="language-java">// MyMapper.java
package com.example;

import java.util.List;

public interface MyMapper {
    List&lt;User&gt; selectUsers();
}
</code></pre>
<pre><code class="language-java">// MyBatisExample.java
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.*;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

public class MyBatisExample {
    public static void main(String[] args) throws IOException {
        String resource = &quot;mybatis-config.xml&quot;;
        Reader reader = Resources.getResourceAsReader(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[콜백 함수란 무엇인가]]></title>
            <link>https://velog.io/@yjs_177076/%EC%BD%9C%EB%B0%B1-%ED%95%A8%EC%88%98%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@yjs_177076/%EC%BD%9C%EB%B0%B1-%ED%95%A8%EC%88%98%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Thu, 01 Feb 2024 00:58:21 GMT</pubDate>
            <description><![CDATA[<h3 id="🤓오늘의-공부-주제-콜백-함수🤓">🤓오늘의 공부 주제: 콜백 함수🤓</h3>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/8efc4428-fca8-4df0-b9cc-57672fff458a/image.png" alt=""></p>
<h3 id="q-콜백-함수란-무엇인가">Q. 콜백 함수란 무엇인가?</h3>
<blockquote>
<p>A. 자바스크립트의 콜백 함수(callback function)는 다른 함수에 인수로 전달되는 함수. 콜백 함수는 보통 이벤트 핸들러, 비동기 작업의 완료 처리, 타이머 설정 등과 같은 상황에서 사용. 콜백 함수를 사용하면 비동기적으로 실행되는 코드를 효과적으로 처리할 수 있다.</p>
</blockquote>
<h4 id="콜백-함수의-주요-특징">콜백 함수의 주요 특징</h4>
<ul>
<li>함수로서의 전달: 콜백 함수는 다른 함수의 인수로 전달될 수 있다.</li>
<li>비동기적 처리: 콜백 함수는 주로 비동기적으로 실행되는 작업을 처리하는 데 사용. 예를 들어, 파일을 읽거나 저장할 때, 서버와 통신할 때, 타이머를 설정할 때 등 비동기적인 작업이 완료될 때까지 대기할 수 있다.</li>
<li>이벤트 처리: 웹 애플리케이션에서는 이벤트 핸들러로서의 역할을 하는 콜백 함수가 매우 흔함. 사용자의 클릭, 키보드 입력, 마우스 움직임 등의 이벤트가 발생할 때마다 콜백 함수가 호출된다.</li>
</ul>
<pre><code class="language-javascript">// 콜백 함수 예시 1: setTimeout 함수를 사용한 비동기 작업
console.log(&quot;첫 번째&quot;);
setTimeout(function() {
    console.log(&quot;두 번째&quot;);
}, 1000);
console.log(&quot;세 번째&quot;);

// 콜백 함수 예시 2: 배열의 forEach 메서드를 사용하여 각 요소에 대해 콜백 함수 호출
const numbers = [1, 2, 3, 4, 5];
numbers.forEach(function(number) {
    console.log(number);
});

// 콜백 함수 예시 3: 이벤트 핸들러로서의 콜백 함수
const button = document.getElementById(&quot;myButton&quot;);
button.addEventListener(&quot;click&quot;, function() {
    console.log(&quot;버튼이 클릭되었습니다.&quot;);
});
</code></pre>
<h3 id="q-콜백-함수가-왜-필요한가">Q. 콜백 함수가 왜 필요한가?</h3>
<blockquote>
<p>A. 비동기프로그래밍을 위해 사용된다. 자바스크립트는 코드를 위에서 아래로 순차적으로 실행한다. 그러나 순차적 실행이 아닌 콜백을 사용하면 비동기 자바스크립트 코드를 작성할 수 있다. 자바스크립트에서 콜백 함수를 만드는 방법은 어떤 함수의 파라미터로써 함수를 넘기고 어떤 행위나 태스크가 완료된 직후에 콜백 함수를 호출하는 것이다.</p>
</blockquote>
<h4 id="콜백-함수를-지양하는-이유">콜백 함수를 지양하는 이유</h4>
<ul>
<li><p>가독성과 유지보수성의 저하: 콜백 함수를 중첩하게 되면 코드의 가독성이 떨어지고, 이해하기 어려워진다. 또한 콜백 함수 간의 의존성이 높아지기 때문에 코드를 수정하거나 유지보수하기 어려워진다.</p>
</li>
<li><p>에러 처리의 어려움: 콜백 함수를 중첩하게 되면 에러 처리가 번거로워진다. 각 콜백 함수마다 에러 처리를 해주어야 하며, 에러가 발생했을 때 콜백 체인 전체를 중단시키고 처리하기 어렵다.</p>
</li>
<li><p>콜백 지옥: 콜백 함수를 중첩하여 사용하다 보면 콜백 지옥(callback hell)이 발생할 수 있다. 콜백 지옥은 콜백 함수가 중첩되어 가독성이 매우 나쁘고 코드의 복잡성이 높아지는 상황을 말한다.</p>
</li>
</ul>
<h4 id="콜백-함수를-대체하는-방법">콜백 함수를 대체하는 방법</h4>
<ol>
<li>프로미스</li>
<li>async/await</li>
</ol>
<p>이미지 출처 : <a href="https://blog.denilgabani.com/callback-function-event-loop-in-javascript-reactjs-web-development">https://blog.denilgabani.com/callback-function-event-loop-in-javascript-reactjs-web-development</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[제어의 역전과 의존성 주입]]></title>
            <link>https://velog.io/@yjs_177076/%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84%EA%B3%BC-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85</link>
            <guid>https://velog.io/@yjs_177076/%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84%EA%B3%BC-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85</guid>
            <pubDate>Tue, 30 Jan 2024 01:58:56 GMT</pubDate>
            <description><![CDATA[<h3 id="🤓오늘의-공부-주제-제어의-역전과-의존성-주입🤓">🤓오늘의 공부 주제: 제어의 역전과 의존성 주입🤓</h3>
<h3 id="q-제어의-역전이란-무엇인가">Q. 제어의 역전이란 무엇인가?</h3>
<blockquote>
<p>A. Inversion of Control(IoC)이란 제어의 역전으로 프로그램의 제어 흐름을 프레임워크나 컨테이너에게 위임하는 개념. 일반적으로 객체의 생성과 생명주기를 개발자가 관리하는 것이 아니라 프레임워크가 관리하며, 프레임워크가 애플리케이션의 흐름을 제어.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/cf0d59ad-c7c6-4b57-9e98-bf6613e9f715/image.png" alt=""></p>
<p>스프링에서는 객체를 Bean이라고 함. 프로젝트가 실행될때 사용자가 Bean으로 관리하는 객체들의 생성과 소멸에 관련된 작업을 스프링에서 자동적으로 수행해주는데 객체가 생성되는 곳을 Bean 컨테이너라고 부른다.</p>
<h3 id="q-의존성-주입이란-무엇인가">Q. 의존성 주입이란 무엇인가?</h3>
<blockquote>
<p>A. 의존성 주입은 객체 간의 의존 관계를 외부에서 설정하고 관리하는 디자인 패턴. </p>
</blockquote>
<p>일반적으로 클래스가 다른 클래스에 의존하는 경우, 이러한 의존성을 클래스 내부에서 생성하거나 관리하면 결합도가 높아져 유연성이 감소한다. 의존성 주입은 이러한 문제를 해결하기 위해 객체의 의존성을 외부에서 주입한다.</p>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/03532bb0-5b6c-438f-8879-9871591863fe/image.png" alt="">
출처: <a href="https://velog.io/@gillog/Spring-DIDependency-Injection">https://velog.io/@gillog/Spring-DIDependency-Injection</a></p>
<h4 id="의존성-주입-구현-방법">의존성 주입 구현 방법</h4>
<ol>
<li>new 생성자를 활용하여 직접 객체 생성 </li>
<li>외부에서 생성된 객체를 setter를 통해 접근</li>
</ol>
<h4 id="의존성-주입과-제어의-역전의-장점">의존성 주입과 제어의 역전의 장점</h4>
<ul>
<li>유연성: 의존성이 외부에서 주입되기 때문에 클래스 간의 결합도가 낮아져 유연한 구조를 만들 수 있다.</li>
<li>재사용성: 의존성 주입을 통해 독립적인 객체를 만들고 재사용할 수 있다.</li>
<li>테스트 용이성: 의존성을 외부에서 주입하므로 테스트 시에 모의 객체(Mock Object)를 주입하여 테스트하기 쉽다.</li>
</ul>
<pre><code class="language-java">// 서비스 인터페이스
public interface MessageService {
    String getMessage();
}

// 서비스 구현체
public class EmailService implements MessageService {
    @Override
    public String getMessage() {
        return &quot;Email message&quot;;
    }
}

// 클라이언트 클래스
public class MyApplication {
    private MessageService service;

    // 의존성 주입을 통해 MessageService를 주입받음
    public MyApplication(MessageService service) {
        this.service = service;
    }

    public void processMessages() {
        String message = service.getMessage();
        System.out.println(&quot;Message: &quot; + message);
    }
}

// 메인 클래스
public class Main {
    public static void main(String[] args) {
        // 의존성 주입을 통해 EmailService를 MyApplication에 주입
        MessageService service = new EmailService();
        MyApplication app = new MyApplication(service);
        app.processMessages();
    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터베이스 정규화]]></title>
            <link>https://velog.io/@yjs_177076/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%A0%95%EA%B7%9C%ED%99%94</link>
            <guid>https://velog.io/@yjs_177076/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%A0%95%EA%B7%9C%ED%99%94</guid>
            <pubDate>Sat, 27 Jan 2024 11:11:08 GMT</pubDate>
            <description><![CDATA[<h3 id="🤓오늘의-공부-주제-데이터베이스-정규화🤓">🤓오늘의 공부 주제: 데이터베이스 정규화🤓</h3>
<h3 id="q-데이터베이스-정규화란-무엇인가">Q. 데이터베이스 정규화란 무엇인가?</h3>
<blockquote>
<p>A. 데이터베이스 설계에서 중복을 최소화하고 데이터의 무결성을 보장하기 위한 과정</p>
</blockquote>
<p>데이터베이스의 유연성, 성능, 안정성을 향상시킬 수 있다. 주로 테이블을 적절한 형태로 분해하여 중복을 제거하고, 관계를 명확하게 정의하는 작업을 포함한다.</p>
<h4 id="정규화의-단계">정규화의 단계</h4>
<ul>
<li>제 1 정규형 (1NF):</li>
</ul>
<p>각 컬럼이 원자값(Atomic value)을 가지도록 테이블을 구조화. 즉, 테이블의 각 셀에는 하나의 값만 있어야 한다. 이를 위해 중복을 제거하고 별도의 테이블을 생성하거나 관계를 조정한다.</p>
<p>기존 데이터) <img src="https://velog.velcdn.com/images/yjs_177076/post/59920ecb-5182-4e20-b654-9dfcd0797415/image.png" alt="">
제 1 정규화 이후 데이터)<img src="https://velog.velcdn.com/images/yjs_177076/post/215de1d6-caae-4862-9dc9-26254ff4a151/image.png" alt=""></p>
<ul>
<li>제 2 정규형 (2NF):</li>
</ul>
<p>부분 함수 종속을 제거. 기본키가 아닌 속성들이 기본키 전체에 종속되도록 테이블을 재구성. 이를 위해 테이블을 쪼개거나 필요한 경우 외래키를 추가하여 관계를 재정의.</p>
<p>기존 데이터)<img src="https://velog.velcdn.com/images/yjs_177076/post/325a27d4-6b3b-41e8-847a-b790afb68660/image.png" alt=""></p>
<p>제 2 정규화 이후 데이터)<img src="https://velog.velcdn.com/images/yjs_177076/post/8d6fa087-28c0-4da4-914c-614183983ee3/image.png" alt=""></p>
<ul>
<li>제 3 정규형 (3NF):</li>
</ul>
<p>이행적 함수 종속을 제거. 기본키가 아닌 속성 간에 직접적인 종속 관계가 없도록 테이블을 재구성. 이를 위해 중복을 최소화하고 중복된 속성을 별도의 테이블로 이동하여 관계를 재정의.</p>
<p>제 3 정규화 이후 데이터)<img src="https://velog.velcdn.com/images/yjs_177076/post/77f65efe-bcaf-44a5-bb4d-ef8deef4ab0b/image.png" alt=""></p>
<ul>
<li>보이스-코드 정규형 (BCNF):</li>
</ul>
<p>모든 결정자가 후보키이어야 함. 이를 통해 다중 후보키를 가지는 테이블에서 발생할 수 있는 이상현상(Anomaly)을 방지.</p>
<p>이러한 정규화 과정은 데이터베이스의 설계를 개선하고 데이터의 일관성과 무결성을 유지하는 데 중요한 역할을 한다. 그러나 지나치게 정규화된 데이터베이스는 성능 저하와 관리의 어려움을 야기할 수 있으므로 적절한 수준의 정규화가 필요.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Apache kafka vs Redis And Hexagonal Architecture]]></title>
            <link>https://velog.io/@yjs_177076/Apache-kafka-vs-Redis-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%97%A5%EC%82%AC%EA%B3%A0%EB%82%A0-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90</link>
            <guid>https://velog.io/@yjs_177076/Apache-kafka-vs-Redis-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%97%A5%EC%82%AC%EA%B3%A0%EB%82%A0-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90</guid>
            <pubDate>Sat, 20 Jan 2024 09:27:48 GMT</pubDate>
            <description><![CDATA[<h3 id="🤓오늘의-공부-주제-apache-kafka-redis-hexagonal-architecture🤓">🤓오늘의 공부 주제: Apache kafka, Redis, hexagonal architecture🤓</h3>
<h3 id="q-apache-kafka란-무엇인가">Q. Apache kafka란 무엇인가?</h3>
<blockquote>
<p>A. Apache kafka란 웹사이트, 어플리케이션, 센서 등에서 취합한 데이터를 스트림 파이프라인을 통해 실시간으로 관리하고 보내기 위한 분산 스트리밍 플랫폼이다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/fe5de1cb-ebd1-4c61-8a8b-2c0713e8cca1/image.png" alt=""></p>
<p>데이터 생성 어플리케이션과 소비 어플리케이션 간의 중재자 역할로 데이터의 전송 제어, 처리, 관리 역할을 담당한다. 어플리케이션과 서비스간의 비동기 데이터 교환을 용이하게 하고 하루 수 조개의 이벤트 처리를 가능하게 한다. </p>
<h4 id="kafka의-특징">kafka의 특징</h4>
<ol>
<li>여러 전달자가 동시에 메시지 전송 가능. 반대로 여러 소비자가 동시에 메세지 읽기 가능.</li>
<li>전송된 메세지는 일정기간 파일 형태로 저장되어 처리 속도, 장애 복구 가능. 한 노드가 메세지 전송하면 전달자와 소비자를 중재하는 브로커에서 전달자가 전달한 메세지를 브로커의 동작에 영향을 주지 않고 처리 속도 및 장애 복구를 유지하도록 해 일정 기간 동안 파일 형태로 저장.</li>
<li>시스템 트래픽이 높아지면 브로커를 추가해 처리량을 늘릴 수 있음.</li>
<li>처리 속도 저하의 경우 소비자나 생산자를 추가해 처리량을 느릴 수 있음.</li>
<li>컨슈머를 그룹으로 묶어 프로듀서에서 보내는 속도와 읽는 속도의 균형을 맞출 수 있음.</li>
</ol>
<h4 id="활용-기업-및-방안">활용 기업 및 방안</h4>
<p>트위터 - 사용자에게 트윗 보내고 받는 방법에 사용
링크드인 - 이용자의 사이트 활동 데이터 분석
넷플릭스 - 실시간 모니터링 및 이벤트 처리 </p>
<p>💡요약💡
장점: 빠른 속도로 대용량의 데이터 처리 용이. 낮은 지연 시간으로 메세지 빠르게 처리. 시스템 확장 용이. 전달할 메세지를 파일로 저장해 안정성과 신뢰성이 높음.
단점: 모니터링 및 관리 도구가 불편하여 메세지 조정이 필요한 경우 성능이 크게 저하될 수 있음. 클러스터의 대기열 수가 증가하면 상태적으로 느리게 동작하는 경우가 있음.</p>
<h3 id="q-redis란-무엇인가">Q. Redis란 무엇인가?</h3>
<blockquote>
<p>A. Redis란 remote dictionary server의 약자로 인메모리 데이터 저장소. 주로 데이터베이스, 캐싱 및 메세지 브로커의 역할을 수행하는 오픈소스 소프트웨어. </p>
</blockquote>
<h4 id="redis의-특징">Redis의 특징</h4>
<ol>
<li>인메모리 데이터 저장: 매우 빠른 읽기 및 쓰기 속도. 캐싱에 유리</li>
<li>다양한 데이터 구조 지원: 문자열, 해시맵, 리스트, 셋, 정렬된 집합과 같은 다양한 구조 지원하여 용도에 맞게 사용 가능</li>
<li>영속성 지원: 메모리에 데이터를 저장하여 시스템 재시작 후에도 데이터 유지 가능.</li>
<li>pub/sub 메시징 시스템: publish/subscribe 매커니즘을 지원하여 메시지 브로커로 사용 가능. 다수의 클라이언트가 메세지를 발행하고 수신 가능.</li>
</ol>
<p>💡요약💡
장점: 빠른 속도, 단순하고 간결한 인터페이스, 다양한 데이터 구조 지원, 높은 가용성 및 확장성, 오픈소스
단점: 데이터 크기 제한, 영속성 저장하는 부분이 제한적, 단일 스레드 모델, 복잡한 쿼리 지원 부족, 오프라인 백업 어려움, 설정 및 튜닝이 필요</p>
<h3 id="q-kafka와-redis는-어떤-차이가-있는가">Q. kafka와 Redis는 어떤 차이가 있는가?</h3>
<blockquote>
<p>A. redis는 데이터를 실시간으로 저장하고 읽기 위한 인메모리 데이터베이스이며, kafka는 대규모 데이터를 분산 스트리밍 처리를 위한 플랫폼으로 각기 다른 목적과 사용 사례를 가진다.</p>
</blockquote>
<p>Redis는 주로 인메모리 데이터베이스로 사용. 데이터를 메모리에 저장하고, 다양한 데이터 구조를 지원하여 빠른 읽기 및 쓰기 작업에 특화. 주로 캐싱, 세션 저장, 메시지 브로커 등 다양한 용도로 사용. Redis는 데이터를 영속적으로 저장하는 기능도 제공하지만, 주로 인메모리 데이터를 활용한 빠른 데이터 액세스에 중점.
반면, Apache Kafka는 데이터의 실시간 스트리밍을 처리하기 위한 플랫폼. 주로 대량의 데이터를 신속하게 처리하고 여러 시스템 간에 데이터를 실시간으로 전송하는 데 사용. Kafka는 대용량의 데이터를 안정적으로 분산 및 스트리밍 처리할 수 있는 기능을 제공하며, 이벤트 소싱, 로그 집계, 데이터 허브 등 다양한 사용 사례에서 활용. 하지만 Kafka 자체는 데이터를 영속적으로 저장하는 데이터베이스로 사용되는 것이 아니라, 데이터를 안정적으로 전달하고 스트리밍 처리하는 역할.</p>
<ol>
<li>데이터 저장 방식의 차이: redis는 인메모리 방식이므로 메모리에 저장하고 영속적인 데이터 저장 지원. kafka는 대용량 데이터를 디스크에 영속적 저장하고 분산 로그로 활용. </li>
<li>활용 목적과 범위: redis가 캐싱, 세션 저장, 실시간 분석과 같은 인메모리 데이터 스토어인 반면 kafkasms 대규모 데이터 스트리밍 및 이벤트 처리에 사용.</li>
<li>메시징 모델: redis는 pub/sub모델 지원. kafka는 고성능 메시지 큐 및 메시지 브로커로 사용.</li>
<li>저장구조: redis는 주로 키-값 형태로 저장하나 다양한 구조를 지원. kafka는 토픽과 파티션으로 이루어진 로그 기반의 저장 구조.</li>
</ol>
<h3 id="q-hexagonal-architecture란-무엇인가">Q. Hexagonal architecture란 무엇인가?</h3>
<blockquote>
<p>A. Hexagonal architecture란 유연하고 확장 가능한 소프트웨어 디자인을 일컫는다. </p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/8549f345-0a55-41ff-902c-6fd0fcd5b59e/image.png" alt=""></p>
<h4 id="hexagonal-architecture의-특징">Hexagonal architecture의 특징</h4>
<p>주요 목표는 응용 프로그램의 비즈니스 로직을 외부로부터 격리시켜 유연하고 테스트하기 쉬운 구조로 만드는 것이다. 핵심 비즈니스 로직은 중앙의 도메인에 위치하며 입출력 포트와 어뎁터를 통해 외부와 소통한다.</p>
<p>가장 대중적인 아키텍처는 3계층으로 비즈니스 로직, 데이터 엑세스, 프레젠테이션 계층으로 구성. 비즈니스 로직이 서비스 클래스에 있고 리포지토리 인터페이스를 통해서 데이터 엑세스 계층과 소통.</p>
<p>3계층 아키텍처 구현 예시)</p>
<pre><code class="language-java">// UserService.java
public class UserService {
    private UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void createUser(String name, String email) {
        User user = new User(name, email);
        userRepository.save(user);
    }
}

// UserRepository.java
public interface UserRepository {
    void save(User user);
}

// UserRepositoryImpl.java
public class UserRepositoryImpl implements UserRepository {
    public void save(User user) {
        // 데이터베이스에 사용자 저장
    }
}</code></pre>
<p>3계층 아키텍처 Kafka 적용 예시)</p>
<pre><code class="language-java">// KafkaProducer.java
public class KafkaProducer {
    public void send(User user) {
        // 카프카에 사용자 정보 전송
    }
}

// UserService.java
public class UserService {
    private UserRepository userRepository;
    private KafkaProducer kafkaProducer;

    public UserService(UserRepository userRepository, KafkaProducer kafkaProducer) {
        this.userRepository = userRepository;
        this.kafkaProducer = kafkaProducer;
    }

    public void createUser(String name, String email) {
        User user = new User(name, email);
        userRepository.save(user);
        kafkaProducer.send(user);
    }
}</code></pre>
<p>반면, 헥사고날 아키텍쳐에서는 별도의 usecase 인터페이스를 통해서 비즈니스 로직 정의 후 impl클래스로 구현. 레포지토리 어뎁터가 레포지토리 인터페이스를 구현해서 외부와 소통. 따라서 비즈니스 로직과 외부 요소를 격리시켜 유연성과 테스트 용이성을 지원. kafka와 같은 외부 시스템을 연결하면 장점이 돋보이게 됨. 기존 3 tier architecture에서는 service가 kafka에 의존성을 가지지만 hexagonal architecture의 경우 외부 시스템과의 의존성 분리를 통해 시스템 변경 시에도 비즈니스 로직 영향이 최소화 된다.</p>
<p>헥사고날 아키텍쳐 구현 예시)</p>
<pre><code class="language-java">// CreateUserUseCase.java
public interface CreateUserUseCase {
    void createUser(String name, String email);
}

// CreateUserUseCaseImpl.java
public class CreateUserUseCaseImpl implements CreateUserUseCase {
    private UserRepository userRepository;

    public CreateUserUseCaseImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void createUser(String name, String email) {
        User user = new User(name, email);
        userRepository.save(user);
    }
}

// UserRepository.java
public interface UserRepository {
    void save(User user);
}

// UserRepositoryAdapter.java
public class UserRepositoryAdapter implements UserRepository {
    public void save(User user) {
        // 데이터베이스에 사용자 저장
    }
}</code></pre>
<p>헥사고날 아키텍쳐 Kafka 적용 예시)</p>
<pre><code class="language-java">// OutputPort.java
public interface OutputPort {
    void sendMessage(User user);
}

// KafkaAdapter.java
public class KafkaAdapter implements OutputPort {
    private KafkaProducer kafkaProducer;

    public KafkaAdapter(KafkaProducer kafkaProducer) {
        this.kafkaProducer = kafkaProducer;
    }

    public void sendMessage(User user) {
        kafkaProducer.send(user);
    }
}

// CreateUserUseCaseImpl.java
public class CreateUserUseCaseImpl implements CreateUserUseCase {
    private UserRepository userRepository;
    private OutputPort outputPort;

    public CreateUserUseCaseImpl(UserRepository userRepository, OutputPort outputPort) {
        this.userRepository = userRepository;
        this.outputPort = outputPort;
    }

    public void createUser(String name, String email) {
        User user = new User(name, email);
        userRepository.save(user);
        outputPort.sendMessage(user);
    }

}</code></pre>
<p>💡요약💡
장점: 유연성, 테스트 용이성(비즈니스 로직 독립적 테스트 가능), 유지보수성</p>
<p>단점: 구현 복잡성(포트와 어뎁터를 구성하고 관리), 초반 개발 시간 증가(처음 구축시)</p>
<p>출처: <a href="https://tech.osci.kr/hexagonal-architecture/">https://tech.osci.kr/hexagonal-architecture/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring vs Spring Boot]]></title>
            <link>https://velog.io/@yjs_177076/Spring-vs-Spring-Boot</link>
            <guid>https://velog.io/@yjs_177076/Spring-vs-Spring-Boot</guid>
            <pubDate>Thu, 18 Jan 2024 01:45:44 GMT</pubDate>
            <description><![CDATA[<h3 id="spring과-spring-boot는-무엇이고-어떤-차이점이-있는가">Spring과 Spring Boot는 무엇이고 어떤 차이점이 있는가?</h3>
<p>Spring과 Spring Boot은 Java 기반의 웹 애플리케이션 개발을 위한 프레임워크로 널리 사용되고 있다. 두 프레임워크는 공통적으로 Java 기반으로 개발되었지만 몇 가지 중요한 차이점이 존재한다.</p>
<h4 id="1-프로젝트-설정의-간편성">1. 프로젝트 설정의 간편성:</h4>
<ul>
<li>Spring: Spring은 XML 기반의 설정이 주를 이루며, 개발자가 많은 부분을 수동으로 설정해야 합니다. 이는 초기 설정에 시간이 많이 소요되고 복잡성이 증가할 수 있습니다.</li>
<li>Spring Boot: Spring Boot는 설정의 기본값을 제공하며, 자동 설정(Auto-Configuration)을 통해 개발자가 불필요한 설정을 최소화합니다. 이로써 초기 설정이 간편해지고 더 빠르게 프로젝트를 시작할 수 있습니다.</li>
</ul>
<h4 id="2-의존성-관리">2. 의존성 관리:</h4>
<ul>
<li>Spring: 개발자는 프로젝트에 필요한 라이브러리와 의존성을 직접 관리해야 합니다.</li>
<li>Spring Boot: Spring Boot는 내장된 의존성 관리 도구를 제공하여, 프로젝트에 필요한 의존성들을 자동으로 관리합니다. 이로써 버전 충돌 및 의존성 해결이 간편해집니다.</li>
</ul>
<h4 id="3-내장-서버">3. 내장 서버:</h4>
<ul>
<li>Spring: Spring은 서블릿 컨테이너(Tomcat, Jetty 등)를 내장하지 않고, 별도의 설정이 필요합니다.</li>
<li>Spring Boot: Spring Boot는 내장된 서블릿 컨테이너를 제공합니다. 별도의 설정 없이도 내장 서버를 통해 애플리케이션을 실행할 수 있습니다.</li>
</ul>
<h4 id="4-어노테이션-기반의-설정">4. 어노테이션 기반의 설정:</h4>
<ul>
<li>Spring: Spring은 XML 설정 파일을 사용하는 것이 일반적이며, 어노테이션을 적용하기 위해 추가적인 설정이 필요합니다.</li>
<li>Spring Boot: Spring Boot는 어노테이션 기반의 설정을 강조하며, 자주 사용되는 설정들을 어노테이션으로 제공합니다. 이는 더 간결하고 가독성이 좋은 코드를 작성할 수 있도록 도와줍니다.</li>
</ul>
<h4 id="5-프로젝트-구조">5. 프로젝트 구조:</h4>
<ul>
<li>Spring: 프로젝트 구조는 개발자가 직접 정의해야 하며, 복잡한 구조가 될 수 있습니다.</li>
<li>Spring Boot: Spring Boot는 기본적인 프로젝트 구조를 제공하며, 개발자가 추가적인 설정 없이도 쉽게 프로젝트를 구성할 수 있습니다.</li>
</ul>
<p>🤓요약:
Spring과 Spring Boot은 각각의 특징을 가지고 있으며, 프로젝트의 규모와 요구사항에 따라 선택되어야 합니다. Spring은 더 많은 설정과 커스터마이징이 필요한 대규모 프로젝트에 적합하며, Spring Boot는 간단한 설정과 빠른 프로젝트 시작이 가능한 소규모 프로젝트나 마이크로서비스 아키텍처에 적합합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로미스 이해하기]]></title>
            <link>https://velog.io/@yjs_177076/%ED%94%84%EB%A1%9C%EB%AF%B8%EC%8A%A4-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@yjs_177076/%ED%94%84%EB%A1%9C%EB%AF%B8%EC%8A%A4-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 17 Jan 2024 01:51:51 GMT</pubDate>
            <description><![CDATA[<h3 id="🤓오늘의-공부-주제-비동기와-프로미스🤓">🤓오늘의 공부 주제: 비동기와 프로미스🤓</h3>
<h3 id="q-프로미스란-무엇인가">Q. 프로미스란 무엇인가?</h3>
<blockquote>
<p>A. 프로미스는 자바스크립트 비동기 처리에 사용되는 객체. 프로미스는 주로 서버에서 받아온 데이터를 화면에 표시할 때 사용</p>
</blockquote>
<ul>
<li><p><code>new Promise</code>에 전달되는 함수는 executor(실행자, 실행 함수)라고 부른다. executor는 <code>new Promise</code>가 만들어질 때 자동으로 실행되는데 결과를 최종적으로 만들어내는 제작 코드를 포함한다. executor의 인수 resolve와 reject는 자바스크립트에서 자체 제공하는 콜백으로 개발자는 resolve와 reject를 신경쓰지 않고 executor 안 코드만 작성하면 된다. 단, executor에선 결과를 얻는 즉시 상황에 따라 인수로 넘겨준 콜백 중 하나를 반드시 호출해야 한다.</p>
<pre><code class="language-jsx">  let promise = new Promise(function resolve, reject) {
          // executor(제작 코드, &#39;가수&#39;)
  });</code></pre>
</li>
<li><p>new Promise 생성자가 반환하는 promise 객체는 아래와 같은 내부 프로퍼티를 갖는다.</p>
<ul>
<li><p>state - “pending(대기)” → resolve가 호출되면 “fulfilled”, reject가 호출되면 “rejected”로 변한다.</p>
  <aside>
  💡 이행(resolved) 혹은 거부(rejected) 상태의 프로미스는 처리된(settled) 프로미스라고 부른다.

  </aside>
</li>
<li><p>result - undefined → resolve(value)가 호출되면 value로, reject(error)가 호출되면 error로 변한다.</p>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/35cd7e2c-54d8-49f9-b79e-61c7041cac30/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<h3 id="q-프로미스의-3가지-상태states란-무엇인가">Q. 프로미스의 3가지 상태(States)란 무엇인가?</h3>
<blockquote>
<p>A. 상태란 프로미스의 처리 과정을 의미하며 <code>new Promise()</code>로 프로미스를 생성하고 종료될 때까지 3가지 상태를 갖는다.</p>
</blockquote>
<ul>
<li><p>Pending(대기): 비동기 처리 로직이 아직 완료되지 않은 상태</p>
<p>  <code>new Promise()</code> 메서드를 호출하면 대기(Pending)상태가 된다.</p>
<p>  <code>new Promise()</code>메서드를 호출할 때 콜백 함수를 선언할 수 있고, 콜백 함수의 인자는 resolve, reject이다.</p>
<pre><code class="language-jsx">  new Promise(function resolve, reject) {
          // ...
  }</code></pre>
</li>
<li><p>Fulfilled(이행) : 비동기 처리가 완료되어 프로미스 결과 값을 반환해준 상태</p>
<p>  콜백 함수의 인자 resolve를 실행하면 이행(Fulfilled)상태가 되며 이행 상태가 되면 then()을 이용하여 처리 결과 값을 받을 수 있다.</p>
<pre><code class="language-jsx">  function getData() {
          return new Promise(function(resolve, reject) {
                  var data = 100;
                  resolve(data);
          }
  }

  // resolve()의 결과 값 data를 resolvedData로 받음
  getData().then(function(resolvedData) {
          console.log(resolvedData);
  });</code></pre>
</li>
<li><p>Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태</p>
<p>  reject를 호출하면 실패(Rejected)상태가 되며, 실패 상태가 되면 실패한 이유를 catch()로 받을 수 있다.</p>
<pre><code class="language-jsx">  function getData() {
          reject(new Error(&quot;Request is failed&quot;));
  }

  getData().then().catch(function(err) {
          console.log(err);
  });</code></pre>
</li>
</ul>
<p><strong>프로미스 처리 흐름</strong></p>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/dd629764-47a7-4b7e-a5dd-b101d79fc1c6/image.png" alt=""></p>
<h3 id="q-메소드---then-catch-finally란-무엇인가">Q. 메소드 - then, catch, finally란 무엇인가?</h3>
<ul>
<li><p><strong>then</strong></p>
<ul>
<li><p>프로미스에서 가장 중요하고 기본이 되는 메소드</p>
<pre><code class="language-jsx">promise.then(
      function(result) {},   // 첫번째 인수 : 프로미스가 이행되었을 때 실행되는 함수
      function(error) {}  // 두번째 인수 : 프로미스가 거부되었을 때 실행되는 함수
);
// 작업이 성공적으로 처리된 경우만 다루고 싶다면 .then에 인수를 하나만 전달</code></pre>
</li>
</ul>
</li>
<li><p><strong>catch</strong></p>
<ul>
<li><p>에러가 발생한 경우만 다루고 싶을 때 사용</p>
<pre><code class="language-jsx">let promise = new Promise((resolve, reject) =&gt; {
      setTimeout(()=&gt;reject(new Error(&quot;에러 발생&quot;)), 1000);
});

// .catch(f)는 promise.then(null,f)와 동일하게 작동
promose.catch(alert);  // promise.then(null, alert); 동일</code></pre>
</li>
</ul>
</li>
<li><p><strong>finally</strong></p>
<ul>
<li><p>프로미스가 처리되면 항상 실행된다. (<code>.finally(f)</code>호출은 <code>.then(f,f)</code>와 유사)</p>
</li>
<li><p>결과가 어떻든 마무리가 필요하면 finally가 유용하다.</p>
</li>
<li><p><strong>.then(f, f)와 차이점</strong></p>
<ul>
<li><p>finally 핸들러에는 인수가 없으며, finally에서는 프로미스가 이행되었는지 거부되었는지 알 수 없다.</p>
</li>
<li><p>finally 핸들러는 자동으로 다음 핸들러에 결과와 에러를 전달한다.</p>
<pre><code class="language-jsx">new Promise((resolve), reject) =&gt; {
      setTimeout(() =&gt; resolve(&quot;결과&quot;), 2000);
})
      .finally(() =&gt; alert(&quot;프로미스가 준비되었습니다.&quot;)
      .then(result =&gt; alert(result));</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="q-프로미스-체이닝-promise-chaining이란-무엇인가">Q. 프로미스 체이닝 (Promise Chaining)이란 무엇인가?</h3>
<blockquote>
<p>A. 순차적으로 처리해야하는 비동기 작업을 여러개 사용하는 경우 활용</p>
</blockquote>
<pre><code class="language-jsx">new Promise(function(resolve, reject) {

  setTimeout(() =&gt; resolve(1), 1000); // (*)

}).then(function(result) { // (**)

  alert(result); // 1
  return result * 2;

}).then(function(result) { // (***)

  alert(result); // 2
  return result * 2;

}).then(function(result) {

  alert(result); // 4
  return result * 2;

});</code></pre>
<ol>
<li>1초후 최초의 프로미스 이행</li>
<li>이후 첫번째 .then 핸들러 호출</li>
<li>2에서 반환한 값은 다음 .then 핸들러에 전달</li>
</ol>
<p>출처 :</p>
<ul>
<li><a href="https://ko.javascript.info/promise-basics">https://ko.javascript.info/promise-basics</a></li>
<li><a href="https://joshua1988.github.io/web-development/javascript/promise-for-beginners/">https://joshua1988.github.io/web-development/javascript/promise-for-beginners/</a></li>
<li><a href="https://elvanov.com/2597">https://elvanov.com/2597</a></li>
<li><a href="https://sangminem.tistory.com/284">https://sangminem.tistory.com/284</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Transactional 어노테이션]]></title>
            <link>https://velog.io/@yjs_177076/Transactional-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@yjs_177076/Transactional-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</guid>
            <pubDate>Tue, 09 Jan 2024 07:54:14 GMT</pubDate>
            <description><![CDATA[<h3 id="😖문제-상황">😖문제 상황</h3>
<p>@Transactional 어노테이션을 추가해서 save 메서드를 직접 호출하지 않고 변경감지로 update해주는 api를 만들었는데 update쿼리가 날아가지 않는 이슈가 발생했다.</p>
<p>문제 코드 )</p>
<pre><code class="language-java">// controller
@PostMapping(&quot;/{id}/object&quot;)
public void addOrUpdateObject(@PathVariable long id, @ModelAttribute ObjectRequest request){
    objectService.checkObject(request);
}

//service
public void addOrUpdateObject(ObjectRequest request){
    if(request.getId() == null)
        addObject(request);
    else
        modifyObject(request.getId(),request);
}

@Transactional
public void modifyObject(long objectId, ObjectRequest request){
    Object obj = objectRepositsory.findById(objectId).orElseThrow(() -&gt; new NoSuchElementException(&quot;존재하지 않는 오브젝트입니다.&quot;);
    obj.updateObject(request);
}
</code></pre>
<h3 id="🤓문제-해결-과정">🤓문제 해결 과정</h3>
<h4 id="step1-디버깅을-통해-어느-함수에서-문제가-발생하는지-확인했다-컨트롤러로-잘-들어와서-addorupdateobject함수를-호출하는것을-확인함">step1. 디버깅을 통해 어느 함수에서 문제가 발생하는지 확인했다. (컨트롤러로 잘 들어와서 addOrUpdateObject함수를 호출하는것을 확인함)</h4>
<h4 id="step2-프론트에서-request를-잘못-보낸게-아닌지-확인했다addorupdateobject함수의-request를-확인하니-변경이-필요한-값들이-잘-들어와-있었음">step2. 프론트에서 request를 잘못 보낸게 아닌지 확인했다.(addOrUpdateObject함수의 request를 확인하니 변경이 필요한 값들이 잘 들어와 있었음)</h4>
<h4 id="step3-modifyobject함수에서-호출한-updateobject함수의-문제가-아닌지-확인했다object타입의-엔티티에서-update함수가-정상적으로-작성되어-있고-변경될-값도-잘-들어오는걸-확인함">step3. modifyObject함수에서 호출한 updateObject함수의 문제가 아닌지 확인했다.(Object타입의 엔티티에서 update함수가 정상적으로 작성되어 있고 변경될 값도 잘 들어오는걸 확인함)</h4>
<h3 id="🧐문제의-원인-파악">🧐문제의 원인 파악</h3>
<p>문제의 원인은 service클래스의 어노테이션에 있었다. DB에 직접 접근하는 함수들을 제외한 나머지 함수들에서는 읽기만 허용하기 위해 어노테이션을 걸어두었는데 해당 어노테이션 때문에 addOrUpdateObject 함수도 읽기 권한만 적용이 된 것이었다.</p>
<pre><code class="language-java">@Transactional(readOnly = true)
</code></pre>
<p>그렇다면 왜 modifyObject함수에는 @Transactional 어노테이션을 붙였는데도 위와 같은 오류가 난 것일까?</p>
<blockquote>
<p><em><strong>@Transactional의 전파 속성</strong></em>
@Transactional 어노테이션에는 여러 옵션들이 있습니다. 그 중에서도 propagation 옵션은 트랜잭션 전파 속성을 설정하는데 사용됩니다. 이 속성은 메서드가 이미 실행 중인 트랜잭션과 어떻게 상호작용하는지를 결정합니다.
@Transactional 어노테이션의 propagation 속성 기본값은 Propagation.REQUIRED입니다. 이것은 &quot;현재 실행 중인 트랜잭션이 있으면 해당 트랜잭션을 사용하고, 없다면 새로운 트랜잭션을 시작한다&quot;는 것을 의미합니다. 따라서 @Transactional 어노테이션을 사용하고 아무런 설정을 하지 않으면, 메서드가 이미 다른 트랜잭션 내에서 호출되는 경우에는 해당 트랜잭션을 사용하게 됩니다.</p>
</blockquote>
<p>즉, @Transactional(readOnly = true)를 서비스 클래스나 메서드에 설정하면 해당 트랜잭션은 읽기 전용으로 설정되어 데이터베이스의 변경 작업을 수행하지 않는 것을 나타낸다. 따라서 읽기 작업만 허용되고, 쓰기 작업(데이터 변경)은 허용되지 않는다.</p>
<p>나는 클래스레벨에서 선언을 했기 때문에 _<strong>서비스 클래스의 모든 메서드에 해당 속성이 전파</strong>_된 것이다. 따라서 데이터를 수정하려는 시도가 있더라도 해당 트랜잭션은 읽기 전용으로 설정되었기 때문에 데이터 변경 작업이 허용되지 않았던 것이다. 이로 인해 modifyObject 메서드에서의 데이터 변경 작업도 허용되지 않게 되었던 것이다. </p>
<h3 id="🤗해결-방법">🤗해결 방법</h3>
<p>@Transactional(readOnly = true)를 사용하고 있는 상황에서 modifyObject 메서드가 수정 작업이 필요하다면, @Transactional(readOnly = true) 옵션을 제거하거나, 해당 메서드 내에서 새로운 트랜잭션을 시작하도록 설정하여 쓰기 작업을 수행하도록 변경해야 한다. 나는 클래스 레벨의 어노테이션은 유지한채로 modifyObject의 경우에만 쓰기 작업을 허용하고 싶었기 때문에 새로운 어노테이션을 추가하기로 했다.</p>
<p>서비스 클래스에 있는 @Transactional(readOnly = true)는 클래스 내의 모든 메서드에 해당 트랜잭션 속성을 적용하는 것이지만, 메서드에 별도의 @Transactional 어노테이션을 추가하면 그 메서드에 대해서는 해당 @Transactional 어노테이션의 설정이 우선시 된다.
따라서 checkObject 메서드에 별도의 @Transactional 어노테이션을 추가하면 해당 메서드에 대한 트랜잭션 속성이 @Transactional(readOnly = true)를 덮어씌우게 된다. 그렇기 때문에 checkObject 메서드 내에서는 새로운 트랜잭션이 생성되고, 그 트랜잭션의 전파 속성은 @Transactional 어노테이션에 설정한대로 동작하게 된다.</p>
<p>해결된 코드)</p>
<pre><code class="language-java">//service
@Transactional
public void addOrUpdateObject(ObjectRequest request){
    if(request.getId() == null)
        addObject(request);
    else
        modifyObject(request.getId(),request);
}

@Transactional
public void modifyObject(long objectId, ObjectRequest request){
    Object obj = objectRepositsory.findById(objectId).orElseThrow(() -&gt; new NoSuchElementException(&quot;존재하지 않는 오브젝트입니다.&quot;);
    obj.updateObject(request);
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자바의 정석] 람다식]]></title>
            <link>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D-%EB%9E%8C%EB%8B%A4%EC%8B%9D</link>
            <guid>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D-%EB%9E%8C%EB%8B%A4%EC%8B%9D</guid>
            <pubDate>Mon, 08 Jan 2024 00:56:29 GMT</pubDate>
            <description><![CDATA[<h1 id="1-람다식-사용법">1. 람다식 사용법</h1>
<hr>
<p>람다식이란?</p>
<p>메서드를 하나의 식으로 표현한 것.</p>
<p>→ 메서드의 이름과 반환값이 없어짐 = 익명함수</p>
<p>→ 클래스나 객체 생성 없이 메서드의 역할 수행 가능.</p>
<p>→ 메서드의 매개변수 및 결과로 반환 가능 = 메서드를 변수처럼 다루는 것</p>
<aside>
💡 람다식 작성 방법

<p>&lt;기존 함수 선언 방법&gt;</p>
<p>반환타입 메서드명 (변수 선언) {
           문장들   }</p>
<p>&lt;람다식&gt;</p>
<p>(매개변수 선언) → { 
        문장들   }</p>
</aside>

<p>→ 매개변수의 반환 타입이 추론 가능한 경우 생략</p>
<p>→ 선언된 매개변수가 한개인 경우 괄호 생략</p>
<p>(단, 매개변수 타입이 있으면 괄호 생략 불가)</p>
<p>→ {중괄호} 안의 문장이 하나인 경우 생략 가능. (이때 문장의 끝에 ‘;’ 붙이지 않음)</p>
<p>(단, {괄호}안의 문장이 return 문일 경우 생략 불가)</p>
<pre><code class="language-java">int max(int a, int b){
return a&gt;b ? a:b;}

(int a, int b) -&gt; {return a&gt;b ? a:b;}
(int a, int b) -&gt; a&gt;b? a:b
(a,b) -&gt; a&gt;b? a:b</code></pre>
<h1 id="2-함수형-인터페이스">2. 함수형 인터페이스</h1>
<hr>
<p>람다식을 다루기 위한 인터페이스를 함수형 인터페이스라고 함.</p>
<pre><code class="language-java">@FunctionalInterface
interface Myfunction{
    public abstract int max(int a, int b);
}</code></pre>
<p>→ 오직 하나의 추상 메서드만 정의되어야 함 (그래야 람다식과 인터페이스가의 메서드가 1:1로 연결)</p>
<p>→ 반면, static과 default 메서드의 개수에는 제약이 없음</p>
<pre><code class="language-java"> @FunctionalInterface
interface MyFunction {
    void run();  // public abstract void run();
}

class LambdaEx1 {
    static void execute(MyFunction f) { // 매개변수의 타입이 MyFunction인 메서드
        f.run();
    }

    static MyFunction getMyFunction() { // 반환 타입이 MyFunction인 메서드 
        MyFunction f = () -&gt; System.out.println(&quot;f3.run()&quot;);
        return f;
    }

    public static void main(String[] args) {
        // 람다식으로 MyFunction의 run()을 구현
        MyFunction f1 = ()-&gt; System.out.println(&quot;f1.run()&quot;);

        MyFunction f2 = new MyFunction() {  // 익명클래스로 run()을 구현
            public void run() {   // public을 반드시 붙여야 함
                System.out.println(&quot;f2.run()&quot;);
            }
        };

        MyFunction f3 = getMyFunction();

        f1.run();
        f2.run();
        f3.run();

        execute(f1);
        execute( ()-&gt; System.out.println(&quot;run()&quot;) );
    }
}</code></pre>
<p>-함수형 인터페이스로 람다식을 참조하는 것이지 람다식의 타입이 함수형 인터페이스의 타입과 일치하는 것은 아님. (람다식은 익명 객체이고 익명 객체는 컴파일러가 임의로 이름을 정하기 때문에 타입을 알 수 없음.) </p>
<p>→ 대입 연산자의 양변의 타입을 일치시키기 위해 형변환이 필요</p>
<p>→ 람다식은 Object 타입으로 형변환 불가. 오직 함수형 인터페이스로만 형변환 가능.</p>
<p>java.util.function패키지의 주요 함수형 인터페이스</p>
<table>
<thead>
<tr>
<th>함수형 인터페이스</th>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>Runnable</td>
<td>void run()</td>
<td>매개변수도 없고, 반환값도 없음</td>
</tr>
<tr>
<td>Supplier<T></td>
<td>T get()</td>
<td>매개변수는 없고, 반환값만 있음</td>
</tr>
<tr>
<td>Consumer<T></td>
<td>void accept(T t)</td>
<td>Supplier와 반대로 매개변수만 있고, 반환값이 없음</td>
</tr>
<tr>
<td>Function&lt;T,R&gt;</td>
<td>R apply(T t)</td>
<td>일반적인 함수, 하나의 매개변수를 받아서 결과를 반환</td>
</tr>
<tr>
<td>Predicate<T></td>
<td>boolean test(T t)</td>
<td>조건식을 표현하는데 사용됨. 매개변수는 하나, 반환타입은 boolean</td>
</tr>
</tbody></table>
<h1 id="3-variable-capture">3. Variable Capture</h1>
<hr>
<p>람다식의 실행 블록 내에서 람다식을 감싸고 있는 클래스의 인스턴스 변수, 스태틱 변수, 지역 변수에 접근하는 것이 가능</p>
<p>→ 그러나 지역 변수에 접근할 때는 Variable Capture라는 특별한 작업이 수행되기 때문에 한 가지 제약이 생김</p>
<p>= Variable Capture란 객체 외부에서 선언된 변수를 객체 내부로 복사하는 행위. ****지역 변수 뿐만 아니라 파라미터로 전달된 변수 또한 외부에서 선언된 변수이므로 같은 규칙이 적용</p>
<pre><code class="language-java">public class CaseOne {

    static int staticVariable = 10;

    int instanceVariable;

    @FunctionalInterface
    interface MyFunction {

        void myMethod();
    }

    public static void main(String[] args) {

        CaseOne caseOne = new CaseOne();
        caseOne.instanceVariable = 20;

        int localVariable = 30;

        MyFunction myFunction = () -&gt; {
            System.out.println(&quot;static variable = &quot; + CaseOne.staticVariable);
            System.out.println(&quot;instance variable = &quot; + caseOne.instanceVariable);
            System.out.println(&quot;local variable = &quot; + localVariable);
        };

        myFunction.myMethod();
    }

}

실행결과
static variable = 10
instance variable = 20
local variable = 30</code></pre>
<p>스태틱 변수나 인스턴스 변수를 변경하는 것은 문제가 없으나, 지역변수를 변경하는 순간 오류가 발생</p>
<p>⇒ 오류가 발생하는 이유는 클래스 내부에 선언된 로컬 클래스(여기선 람다식)가 지역 변수를 참조할 때는 그 값을 복사해서 사용하기 때문(=Variable Capture)</p>
<pre><code class="language-java">public class CaseOne {

    static int staticVariable = 10;

    int instanceVariable;

    @FunctionalInterface
    interface MyFunction {

        void myMethod();
    }

    public static void main(String[] args) {

        CaseOne caseOne = new CaseOne();
        caseOne.instanceVariable = 20;

        int localVariable = 30;

        // 값 변경
        CaseOne.staticVariable += 5;
        caseOne.instanceVariable += 5;
        localVariable += 5;

        MyFunction myFunction = () -&gt; {
            System.out.println(&quot;static variable = &quot; + CaseOne.staticVariable);
            System.out.println(&quot;instance variable = &quot; + caseOne.instanceVariable);
            System.out.println(&quot;local variable = &quot; + localVariable);    // 컴파일 오류 발생!
        };

        myFunction.myMethod();
    }
}</code></pre>
<h1 id="4-메소드-생성자-레퍼런스">4. 메소드, 생성자 레퍼런스</h1>
<hr>
<p>1) 메서드 참조</p>
<p>람다식이 하나의 메서드만 호출하는 경우에는 메서드 참조를 통해 간략히 할 수 있음</p>
<pre><code class="language-java">Function&lt;String , Integer&gt; f = (String s) -&gt; Integer.parseInt(s);

Function&lt;String , Integer&gt; f = Integer::parseInt;</code></pre>
<p>“클래스이름::메서드이름” 혹은 ”참조변수:메서드이름”으로 바꿀 수 있음</p>
<p>2)생성자의 메서드 참조</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자바의 정석]제네릭]]></title>
            <link>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D%EC%A0%9C%EB%84%A4%EB%A6%AD</link>
            <guid>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D%EC%A0%9C%EB%84%A4%EB%A6%AD</guid>
            <pubDate>Wed, 20 Dec 2023 11:12:53 GMT</pubDate>
            <description><![CDATA[<h1 id="1-제네릭-사용법">1. 제네릭 사용법</h1>
<hr>
<p>제네릭이란?</p>
<p>다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입체크를 해주는 기능.</p>
<p>→ 객체 타입을 컴파일 시에 체크하기 때문에 타입 안정성을 높이고 형변환 생략을 통해 간결한 코드 가능</p>
<pre><code class="language-java">class Box&lt;T&gt;             //제네릭 타입 T를 선언
{
    T item;
    void setItem(T item){ this. item = item;}
    T getItem(){ return item;}
}

Box&lt;String&gt; b = new Box&lt;String&gt;(); //타입 T대신 실제 타입을 지정</code></pre>
<p>→ T를 type variable 이라고 하며 다른 글자로 대체 가능.</p>
<p>(e.g. ArrayList의 경우 element의 약자 E 사용. </p>
<p>Map&lt;K,V&gt; - Key, Value)</p>
<p><strong>제네릭 클래스의 객체 생성</strong></p>
<p>참조변수와 생성자에 대입된 타입(매개변수화된 타입)이 일치해야 함</p>
<p>e.g. Box<Apple> appleBox = new Box<Apple>();</p>
<p>Box<Apple> appleBox = new Box&lt;&gt;();  // 추정 가능한 경우 타입 생략 가능</p>
<p> Box<Apple> appleBox = new FruitBox<Apple>(); // 상속관계</p>
<pre><code class="language-java">import java.util.ArrayList;

class Fruit                  { public String toString() { return &quot;Fruit&quot;;}}
class Apple extends Fruit { public String toString() { return &quot;Apple&quot;;}}
class Grape extends Fruit { public String toString() { return &quot;Grape&quot;;}}
class Toy                  { public String toString() { return &quot;Toy&quot;  ;}}

class FruitBoxEx1 {
    public static void main(String[] args) {
        Box&lt;Fruit&gt; fruitBox = new Box&lt;Fruit&gt;();
        Box&lt;Apple&gt; appleBox = new Box&lt;Apple&gt;();
        Box&lt;Toy&gt;   toyBox   = new Box&lt;Toy&gt;();
//        Box&lt;Grape&gt; grapeBox = new Box&lt;Apple&gt;(); // 에러. 타입 불일치

        fruitBox.add(new Fruit());
        fruitBox.add(new Apple()); // OK. void add(Fruit item)

        appleBox.add(new Apple());
        appleBox.add(new Apple());
//        appleBox.add(new Toy()); // 에러. Box&lt;Apple&gt;에는 Apple만 담을 수 있음

        toyBox.add(new Toy());
//        toyBox.add(new Apple()); // 에러. Box&lt;Toy&gt;에는 Apple을 담을 수 없음

        System.out.println(fruitBox);
        System.out.println(appleBox);
        System.out.println(toyBox);
    }  // main의 끝
}

class Box&lt;T&gt; {
    ArrayList&lt;T&gt; list = new ArrayList&lt;T&gt;();
    void add(T item)  { list.add(item); }
    T get(int i)      { return list.get(i); }
    int size() { return list.size(); }
    public String toString() { return list.toString();}
}</code></pre>
<h1 id="2-제네릭-주요-개념-바운디드-타입-와일드-카드">2. 제네릭 주요 개념 (바운디드 타입, 와일드 카드)</h1>
<hr>
<p>제네릭스 용어</p>
<aside>
💡 class Box<T>{}

<p>Box: 원시타입
T: 타입 변수 또는 타입 매개변수. (T는 타입 문자)
Box<T>: 제네릭 클래스</p>
</aside>

<p>1) 제네릭스의 제한</p>
<p>제네릭 클래스 Box의 객체를 생성할 때, 객체별로 다른 타입을 지정하는 것은 가능</p>
<p>(= 인스턴스 별로 다르게 동작하도록 만든 기능이므로)</p>
<pre><code class="language-java">Box&lt;Apple&gt; appleBox = new Box&lt;Apple&gt;(); // apple객체만 저장 가능
Box&lt;Grape&gt; grapeBox = new Box&lt;Grape&gt;(); // grape객체만 저장 가능</code></pre>
<p>→ 그러나, static멤버에 타입 변수 T 사용 불가</p>
<p>(T는 인스턴스변수로 간주되기 때문에 모든 객체에 대해 동일하게 동작해야하는 static 멤버는 인스턴스 변수를 참조할 수 없음. </p>
<p>⇒ static 멤버는 타입 변수에 지정도니 타입, 즉 대입된 타입의 종류에 관계없이 동일한 것이어야 함)</p>
<p>→ 제네릭 배열 타입의 참조변수 선언은 가능하나, 제네릭 타입의 배열을 생성하는 것은 불가.</p>
<pre><code class="language-java">
class Box&lt;T&gt;{
T[] itemArr; // (o) T타입의 배열을 위한 참조변수 

T[] toArray(){
    T[] tmpArr = new T[itemArr.length]; // (x) 제네릭 배열 생성 불가</code></pre>
<p>→ new 연산자는 컴파일 시점에 타입 T가 뭔지 알아야함. 그러나 위의 코드에서는 컴파일 시점에 T가 어떤 타입이 될지 알 수 없음. (instance of 역시 마찬가지) </p>
<p>→ 따라서, new 연산자 대신 Reflection API의 newInstance()메서드 혹은 Object 배열을 생성 후 형변환 하는 방법 사용</p>
<p>제네릭 타입에 extends 활용하면 특정 타입의 자손들만 대입하도록 제한 가능</p>
<pre><code class="language-java">import java.util.ArrayList;

class Fruit implements Eatable {
    public String toString() { return &quot;Fruit&quot;;}
}
class Apple extends Fruit { public String toString() { return &quot;Apple&quot;;}}
class Grape extends Fruit { public String toString() { return &quot;Grape&quot;;}}
class Toy                  { public String toString() { return &quot;Toy&quot;  ;}}

interface Eatable {}

class FruitBoxEx2 {
    public static void main(String[] args) {
        FruitBox&lt;Fruit&gt; fruitBox = new FruitBox&lt;Fruit&gt;();
        FruitBox&lt;Apple&gt; appleBox = new FruitBox&lt;Apple&gt;();
        FruitBox&lt;Grape&gt; grapeBox = new FruitBox&lt;Grape&gt;();
//        FruitBox&lt;Grape&gt; grapeBox = new FruitBox&lt;Apple&gt;(); // 에러. 타입 불일치
//        FruitBox&lt;Toy&gt;   toyBox    = new FruitBox&lt;Toy&gt;();   // 에러.

        fruitBox.add(new Fruit());
        fruitBox.add(new Apple());
        fruitBox.add(new Grape());
        appleBox.add(new Apple());
//        appleBox.add(new Grape());  // 에러. Grape는 Apple의 자손이 아님
        grapeBox.add(new Grape());

        System.out.println(&quot;fruitBox-&quot;+fruitBox);
        System.out.println(&quot;appleBox-&quot;+appleBox);
        System.out.println(&quot;grapeBox-&quot;+grapeBox);
    }  // main
}

class FruitBox&lt;T extends Fruit &amp; Eatable&gt; extends Box&lt;T&gt; {}

class Box&lt;T&gt; {
    ArrayList&lt;T&gt; list = new ArrayList&lt;T&gt;();
    void add(T item)  { list.add(item);      }
    T get(int i)      { return list.get(i); }
    int size()        { return list.size();  }
    public String toString() { return list.toString();}
}</code></pre>
<p>2) 와일드 카드</p>
<p>여러가지 타입의 매개변수를 갖는 제네릭 타입을 만들때 제네릭 타입이 다른 것만으로는 오버로딩이 성립하지 않기때문에 고안된 방법</p>
<p>?로 표시하며 어떤 타입도 될 수 있음</p>
<aside>
💡 <? extends T>: 와일드 카드의 상한 제한. T와 그 자손들만 가능
<? super T>: 와일드 카드의 하한 제한. T와 그 조상들만 가능
<? >: 제한 없이 모든 타입이 가능. <? T extends Object>와 동일

</aside>

<pre><code class="language-java">import java.util.ArrayList;

class Fruit                  { public String toString() { return &quot;Fruit&quot;;}}
class Apple extends Fruit { public String toString() { return &quot;Apple&quot;;}}
class Grape extends Fruit { public String toString() { return &quot;Grape&quot;;}}

class Juice {
    String name;

    Juice(String name)         { this.name = name + &quot;Juice&quot;; }
    public String toString() { return name;         }
}

class Juicer {
    static Juice makeJuice(FruitBox&lt;? extends Fruit&gt; box) {
        String tmp = &quot;&quot;;

        for(Fruit f : box.getList()) 
            tmp += f + &quot; &quot;;
        return new Juice(tmp);
    }
}

class FruitBoxEx3 {
    public static void main(String[] args) {
        FruitBox&lt;Fruit&gt; fruitBox = new FruitBox&lt;Fruit&gt;();
        FruitBox&lt;Apple&gt; appleBox = new FruitBox&lt;Apple&gt;();

        fruitBox.add(new Apple());
        fruitBox.add(new Grape());
        appleBox.add(new Apple());
        appleBox.add(new Apple());

        System.out.println(Juicer.makeJuice(fruitBox));
        System.out.println(Juicer.makeJuice(appleBox));
    }  // main
}

class FruitBox&lt;T extends Fruit&gt; extends Box&lt;T&gt; {}

class Box&lt;T&gt; {
//class FruitBox&lt;T extends Fruit&gt; {
    ArrayList&lt;T&gt; list = new ArrayList&lt;T&gt;();
    void add(T item) { list.add(item);      }
    T get(int i)     { return list.get(i); }
    ArrayList&lt;T&gt; getList() { return list;  }
    int size()       { return list.size(); }
    public String toString() { return list.toString();}
}</code></pre>
<h1 id="3-제네릭-메소드-만들기">3. 제네릭 메소드 만들기</h1>
<hr>
<p>메서드의 선언부에 제네릭 타입이 선언된 메서드</p>
<p>→ 제네릭 메서드 호출 시 대입된 타입을 생략할 수 없는 경우에는 참조변수나 클래스 이름을 생략 할 수 없음.</p>
<pre><code class="language-java">static &lt;T extends Fruit&gt; Juice makeJuice(FruitBox &lt;T&gt; box)
{
    String tmp =&quot;&quot;;
    for(Fruit F : box.getList())
        tmp += f + &quot;&quot;;
    return new Juice(tmp);
}

    FruitBox&lt;Fruit&gt; fruitBox = new FruitBox&lt;Fruit&gt;();
    FruitBox&lt;Apple&gt; appleBox = new FruitBox&lt;Apple&gt;();

    System.out.println(Juicer.&lt;Fruit&gt;makeJuice(fruitBox));//메서드 호출시 타입변수에 타입 대입
    System.out.println(Juicer.&lt;Apple&gt;makeJuice(appleBox));

    System.out.println(Juicer.makeJuice(fruitBox));// 대입된 타입 생략 가능
    System.out.println(Juicer.makeJuice(appleBox));

    System.out.println(makeJuice(fruitBox));//에러. 클래스 이름 생략 불가</code></pre>
<h1 id="4-erasure">4. Erasure</h1>
<hr>
<ol>
<li>제네릭 타입의 경계를 제거한다.</li>
</ol>
<pre><code class="language-java">class Box&lt;T extends Fruit&gt; 
{
    void add(T t)
        {...}
}

👇

class Box {
    void add (Fruit t) 
        { ... }
}</code></pre>
<ol>
<li>제네릭 타입을 제거한 후에 타입이 일치하지 않으면, 형변환을 추가한다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자바의 정석]I/O]]></title>
            <link>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9DIO</link>
            <guid>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9DIO</guid>
            <pubDate>Wed, 13 Dec 2023 01:04:02 GMT</pubDate>
            <description><![CDATA[<h1 id="1-스트림-stream--버퍼-buffer--채널-channel-기반의-io">1. 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O</h1>
<hr>
<p>입출력이란?</p>
<p>IO = Input과 Output의 약자</p>
<p>컴퓨터 내부 또는 외부의 장치와 프로그램간의 데이터를 주고받는것</p>
<p>1) 스트림</p>
<p>데이터를 운반하는데 사용되는 연결통로</p>
<p>단방향 통신만 가능. = 하나의 스트림으로 입력과 출력을 동시에 처리할 수 없음.</p>
<p>큐와 같은 구조(선입선출)</p>
<p>2)버퍼</p>
<p>보조스트림은 실제 데이터를 주고받는 스트림이 아니기 때문에 데이터를 입출력할 수 있는 기능은 없으나 스트림의 기능을 향상시키거나 새로운 기능 추가 가능.</p>
<p>→ 따라서 스트림을 먼저 생성한 다음에 보조스트림 생성해야함</p>
<p>→모든 보조 스트림 역시 InputStream 과 OutputStream의 자손임</p>
<table>
<thead>
<tr>
<th>입력</th>
<th>출력</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>FileInputStream</td>
<td>FileOutputStream</td>
<td>필터를 이용한 입출력 처리</td>
</tr>
<tr>
<td>BufferedInputStream</td>
<td>BufferedOutputStream</td>
<td>버퍼를 이용한 입출력 성능향상</td>
</tr>
<tr>
<td>DataInputStream</td>
<td>DataOutputStream</td>
<td>int, float와 같은 기본형 단위로 데이터를 처리하는 기능</td>
</tr>
<tr>
<td>SequenceInputStream</td>
<td>없음</td>
<td>두개의 스트림을 하나로 연결</td>
</tr>
<tr>
<td>LineNumberInputStream</td>
<td>없음</td>
<td>읽어 온 데이터의 라인 번호를 카운트</td>
</tr>
<tr>
<td>ObjectInputStream</td>
<td>ObjectOutputStream</td>
<td>데이터를 객체단위로 읽고 쓰는데 사용</td>
</tr>
<tr>
<td>없음</td>
<td>PrintStream</td>
<td>버퍼를 이용하며, 추가적인 print 관련 기능(print, printf, println)</td>
</tr>
<tr>
<td>PushbackInputStream</td>
<td>없음</td>
<td>버퍼를 이용해서 읽어 온 데이터를 다시 되돌리는 기능(unread, push back to buffer)</td>
</tr>
</tbody></table>
<p>3)채널</p>
<p>데이터가 통과하는 쌍방향 통로</p>
<p>→ 채널에서 데이터를 주고 받을 때 사용 되는 것이 버퍼</p>
<p>→ 채널에는 소켓과 연결된 SocketChannel, 파일과 연결된 FileChannel, 파이프와 연결된 Pipe.SinkChannel 과 Pipe.SourceChannel 등이 존재하며, 서버소켓과 연결된 ServerSocketChannel 도 존재</p>
<h1 id="2-inputstream과-outputstream">2. InputStream과 OutputStream</h1>
<hr>
<p>스트림은 바이트단위로 데이터를 전송</p>
<table>
<thead>
<tr>
<th>입력스트림</th>
<th>출력스트림</th>
<th>입출력 대상의 종류</th>
</tr>
</thead>
<tbody><tr>
<td>FileInputStream</td>
<td>FileOutputStream</td>
<td>파일</td>
</tr>
<tr>
<td>ByteArrayInputStream</td>
<td>ByteArrayOutputStream</td>
<td>메모리(byte배열)</td>
</tr>
<tr>
<td>PipedInputStream</td>
<td>PipedOutputStream</td>
<td>프로세스(프로세스간의 통신)</td>
</tr>
<tr>
<td>AudioInputStream</td>
<td>AudioOutputStream</td>
<td>오디오장치</td>
</tr>
</tbody></table>
<p>java.io패키지를 통해 입출력 관련 클래스 제공</p>
<p>메서드를 통해서 데이터를 읽고 쓸 수 있음</p>
<p>e.g. int read(byte[]b, int off, int len) , void write(byte[]b, int off, int len)</p>
<p>= 입력스트림으로부터 len개의 byte를 읽어서 byte배열 b의 off위치부터 저장</p>
<p>( 추상클래스를(abstract class InputStream) 상속받아서 추상메서드를(abstract int read) 구현한 클래스의 인스턴스에 대해서 추상메서드가 호출되는 것이기 때문에 read()는 반드시 구현되어야하는 핵심적인 메서드임. 따라서 read()없이 int read(byte[]b, int off, int len)는 사용 불가.)</p>
<p>1)InputStream</p>
<ul>
<li>바이트 기반 입력 스트림의 최상위 추상 클래스</li>
<li>모든 바이트 기반 입력 스트림은 이 클래스를 상속 받아서 만들어 짐</li>
<li>버퍼, 파일, 네트워크 단에서 입력되는 데이터를 읽어오는 기능을 수행</li>
</ul>
<table>
<thead>
<tr>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>read()</td>
<td>입력 스트림으로부터 1바이트를 읽어서 바이트를 리턴</td>
</tr>
<tr>
<td>read(byte[] b)</td>
<td>입력 스트림으로부터 읽은 바이트들을 매개값으로 주어진 바이트 배열 b 에 저장하고 실제로 읽은 바이트 수를 리턴</td>
</tr>
<tr>
<td>read(byte[] b, int off, int len)</td>
<td>입력 스트림으로부터 len 개의 바이트만큼 읽고 매개값으로 주어진 바이트 배열 b[off] 부터 len 개까지 저장. 그리고 실제로 읽은 바이트 수인 len 개를 리턴. 만약 len 개를 모두 읽지 못하면 실제로 읽은 바이트 수를 리턴</td>
</tr>
<tr>
<td>close()</td>
<td>사용한 시스템 자원을 반납하고 입력 스트림 닫기</td>
</tr>
</tbody></table>
<p>1)OutputStream</p>
<ul>
<li>바이트 기반 출력 스트림의 최상위 추상 클래스</li>
<li>모든 바이트 기반 출력 스트림은 이 클래스를 상속 받아서 만들어 짐</li>
<li>버퍼, 파일, 네트워크 단으로 데이터를 내보내는 기능을 수행</li>
</ul>
<table>
<thead>
<tr>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>write(int b)</td>
<td>출력 스트림으로부터 1바이트를 보낸다.(b 의 끝 1바이트</td>
</tr>
<tr>
<td>write(byte[] b)</td>
<td>출력 스트림으로부터 주어진 바이트 배열 b의 모든 바이트를 보낸다.</td>
</tr>
<tr>
<td>write(byte[ ] b, int off, int len)</td>
<td>출력 스트림으로 주어진 바이트 배열 b[off] 부터 len 개까지의 바이트를 보낸다.</td>
</tr>
<tr>
<td>flush()</td>
<td>버퍼에 잔류하는 모든 바이트를 출력한다.</td>
</tr>
<tr>
<td>close()</td>
<td>사용한 시스템 자원을 반납하고 입력 스트림 닫기</td>
</tr>
</tbody></table>
<h1 id="3-byte와-character-스트림">3. Byte와 Character 스트림</h1>
<hr>
<p>Byte기반 스트림: 입출력의 단위가 1byte임.</p>
<p>(자바에서는 한 문자를 의미하는 char형이 1 byte가 아니라 2 byte이기 때문에 바이트기반의 스트림으로 2byte인 문자를 처리하는 데는 어려움이 있음. 이를 보완하기 위해 문자 기반의 스트림이 제공됨.)</p>
<p>InputStream → Reader</p>
<p>OutputStream → Writer</p>
<p>1) Byte Stream</p>
<ul>
<li><p>binary 데이터를 입출력하는 스트림</p>
</li>
<li><p>데이터는 1바이트 단위로 처리</p>
</li>
<li><p>이미지, 동영상 등을 송수신 할 때 주로 사용</p>
<p>  <img src="https://velog.velcdn.com/images/yjs_177076/post/64fe455c-69d4-490e-ab8e-e56743628403/image.png" alt=""></p>
</li>
</ul>
<p>2) Character Stream</p>
<ul>
<li><p>text 데이터를 입출력하는 스트림</p>
</li>
<li><p>데이터는 2바이트 단위로 처리</p>
</li>
<li><p>일반적인 텍스트 및 JSON, HTML 등을 송수신할 때 주로 사용</p>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/fef076b1-08af-4037-ad10-a8df8f926377/image.png" alt=""></p>
</li>
</ul>
<h1 id="4-표준-스트림-systemin-systemout-systemerr">4. 표준 스트림 (System.in, System.out, System.err)</h1>
<hr>
<p>애너테이션에 대한 기본 정보가 javadoc으로 작성한 문서에 포함되도록함.</p>
<p>표준 입출력 스트림의 종류는 java.lang 패키지의 System 클래스 내부에 static 으로 선언되어 있음</p>
<pre><code class="language-java">public final class System {
  public static final InputStream in;
  public static final PrintStream out;
  public static final PrintStream err;
  ....
}</code></pre>
<p>→ System.out 은 콘솔 화면에 문자열을 출력하기 위한 용도로 사용되는 출력 스트림이다.</p>
<p>→ System.in 은 키보드의 입력을 받아들이기 위해서 사용되는 입력 스트림이다.</p>
<p>cf. System.out 과 System.err</p>
<p>둘다 출력 스트림</p>
<p>→ err 은 버퍼링을 지원하지 않음. (err 이 보다 정확하고 빠르게 출력되어야 하기 때문) 버퍼링을 하던 도중 프로그램이 멈추면 버퍼링된 내용은 출력되지 않기 때문</p>
<h1 id="5-파일-읽고-쓰기">5. 파일 읽고 쓰기</h1>
<hr>
<p>애노테이션 프로세서는 소스코드 레벨에서 소스코드에 붙어있음.</p>
<p>→ 텍스트 파일인 경우 문자 스트림 클래스들을 사용하면 되고, 바이너리 파일인 경우 바이트 스트림을 기본적으로 사용한다.</p>
<p>→ 입출력 효율을 위해 Buffered 계열의 보조 스트림을 함께 사용하는 것이 좋음.</p>
<ul>
<li><p>텍스트 파일인 경우</p>
<pre><code class="language-java">  BufferedReader br = new BufferedReader(new FileReader(&quot;a.txt&quot;));
  BufferedWriter bw = new BufferedWriter(new FileWriter(&quot;b.txt&quot;));
  String s;
  while ((s = br.readLine()) != null) {
    bw.write(s + &quot;\n&quot;);
  }</code></pre>
</li>
<li><p>이진 파일인 경우</p>
<pre><code class="language-java">  BufferedInputStream is = new BufferedInputStream(new FileInputStream(&quot;a.jpg&quot;));
  BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(&quot;b.jpg&quot;));
  byte[] buffer = new byte[16384];
  while (is.read(buffer) != -1) {
    os.write(buffer);
  }</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자바의 정석]애노테이션]]></title>
            <link>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D%EC%95%A0%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D%EC%95%A0%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</guid>
            <pubDate>Tue, 12 Dec 2023 01:25:25 GMT</pubDate>
            <description><![CDATA[<h1 id="1-애노테이션-정의하는-방법">1. 애노테이션 정의하는 방법</h1>
<hr>
<p>애노테이션이란?</p>
<p>프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨것.</p>
<p>자바는 소스코드와 문서를 하나의 파일로 관리. 따라서 주석에 소스코드에 대한 정보를 저장하고 소스코드의 주석으로부터 HTML문서를 생성해내는 javadoc.exe를 사용.</p>
<p>(=미리 정의된 태그들을 이용해서 주석안에 정보를 저장하고 javadoc.exe 프로그램이 이 정보를 읽어서 문서를 작성)</p>
<p>&lt;애너테이션 요소의 규칙&gt;</p>
<ul>
<li><p>요소의 타입은 기본형, String, enum, 어노테이션, Class만 허용됨.</p>
</li>
<li><p>()안에 매개변수는 선언할 수 없음.</p>
</li>
<li><p>예외를 선언할 수는 없음.</p>
</li>
<li><p>요소를 타입 매개변수로 정의 할 수 없음.</p>
</li>
</ul>
<p>&lt;표준 애노테이션&gt;</p>
<table>
<thead>
<tr>
<th>애너테이션</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>@Override</td>
<td>컴파일러에게 오버라이딩 메서드라는 것을 알림</td>
</tr>
<tr>
<td>@Deprecated</td>
<td>앞으로 사용하지 않을 것을 권장하는 대상에 붙임</td>
</tr>
<tr>
<td>@SuppressWarnings</td>
<td>컴파일러의 특정 경고메세지가 나타나지 않게 해줌</td>
</tr>
<tr>
<td>@SafeVarags</td>
<td>지네릭스 타입의 가변인자에 사용</td>
</tr>
<tr>
<td>@FunctionalInerface</td>
<td>함수형 인터페이스임을 알림</td>
</tr>
<tr>
<td>@Native</td>
<td>native메서드에서 참조되는 상수 앞에 붙임</td>
</tr>
<tr>
<td>@Target*</td>
<td>애너테이션이 적용가능한 대상을 지정하는데 사용</td>
</tr>
<tr>
<td>@Documented*</td>
<td>애너테이션 정보가 javadoc으로 작성한 문서에 포함되게 함.</td>
</tr>
<tr>
<td>@Inherited*</td>
<td>애너테이션이 자손 클래스에 상속되도록함</td>
</tr>
<tr>
<td>@Retention*</td>
<td>애너테이션이 유지되는 범위를 지정</td>
</tr>
<tr>
<td>@Repeatable*</td>
<td>애너테이션이 반복해서 적용할 수 있게 함.</td>
</tr>
</tbody></table>
<p>메타 애너테이션</p>
<p>-애너테이션을 위한 애너테이션 = 애너테이션에 붙이는 애너테이션으로 애너테이션을 정의할 때 적용대상이나 유지기간등을 지정하는데 사용. </p>
<p>-java.lang.annotation 패키지에 포함되어 있음</p>
<h1 id="2-retention">2. <strong>@retention</strong></h1>
<hr>
<p>애너테이션이 유지되는 기간을 지정하는데 사용</p>
<p>&lt;애너테이션 유지정책의 종류&gt;</p>
<table>
<thead>
<tr>
<th>유지 정책</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>SOURCE</td>
<td>소스파일에만 존재. 클래스 파일에는 존재하지 않음</td>
</tr>
<tr>
<td>CLASS</td>
<td>클래스 파일에 존재. 실행시에 사용불가. 기본값</td>
</tr>
<tr>
<td>RUNTIME</td>
<td>클래스파일에 존재. 실행시에 사용가능.</td>
</tr>
</tbody></table>
<p>@Override, @SuppressWarnings (컴파일러가 사용하는 애너테이션) ⇒ SOURCE</p>
<p>@FunctionalInterface(컴파일러 확인, 실행시 유지) ⇒ RUNTIME</p>
<h1 id="3-target">3. <strong>@target</strong></h1>
<hr>
<p>애너테이션이 적용가능한 대상을 지정하는데 사용. </p>
<p>→ 여러개의 값을 지정할 경우 배열을 사용. </p>
<pre><code class="language-java">@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})</code></pre>
<p>&lt;@Target 애너테이션 적용대상의 종류&gt;</p>
<table>
<thead>
<tr>
<th>대상 타입</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>ANNOTATION_TYPE</td>
<td>애너테이션</td>
</tr>
<tr>
<td>CONSTRUCTOR</td>
<td>생성자</td>
</tr>
<tr>
<td>FIELD</td>
<td>필드(멤버변수, enum상수), 기본형</td>
</tr>
<tr>
<td>LOCAL_VARIABLE</td>
<td>지역변수</td>
</tr>
<tr>
<td>METHOD</td>
<td>메서드</td>
</tr>
<tr>
<td>PACKAGE</td>
<td>패키지</td>
</tr>
<tr>
<td>PARAMETER</td>
<td>매개변수</td>
</tr>
<tr>
<td>TYPE</td>
<td>타입(클래스, 인터페이스, enum)</td>
</tr>
<tr>
<td>TYPE_PARAMETER</td>
<td>타입 매개변수</td>
</tr>
<tr>
<td>TYPE_USE</td>
<td>타입이 사용되는 모든 곳, 참조형</td>
</tr>
</tbody></table>
<h1 id="4-documented">4. <strong>@documented</strong></h1>
<hr>
<p>애너테이션에 대한 기본 정보가 javadoc으로 작성한 문서에 포함되도록함.</p>
<p>@Override, @SuppressWarnings 제외한 나머지는 모두 해당 메타 애너테이션이 붙어있음.</p>
<h1 id="5-애노테이션-프로세서">5. 애노테이션 프로세서</h1>
<hr>
<p>(참고 강의 : <a href="https://www.inflearn.com/course/the-java-code-manipulation/dashboard">www.inflearn.com/course/the-java-code-manipulation/dashboard</a> 인프런 - 더 자바, 코드를 조작하는 다양한 방법)</p>
<p><a href="https://www.notion.so/37d183f38389426d9700453f00253532?pvs=21">https://www.notion.so/37d183f38389426d9700453f00253532</a></p>
<h3 id="애노테이션-프로세서">애노테이션 프로세서</h3>
<p>애노테이션 프로세서는 소스코드 레벨에서 소스코드에 붙어있음.</p>
<p>애노테이션을 읽어서 컴파일러가 컴파일 하는 중에 새로은 소스코드를 생성하거나 기존 소스코드를 바꿀 수 있음.</p>
<p>또는, 클래스(바이트코드) 도 생성할 수 있고 별개의 리소스파일을 생성할 수 있는 강력한 기능.</p>
<h3 id="애노테이션-프로세서-사용-예">애노테이션 프로세서 사용 예</h3>
<ul>
<li>롬복 (기존코드를 변경한다)</li>
<li>AutoService (리소스 파일을 생성해준다.)<ul>
<li>java.util.ServiceLoader 용 파일 생성 유틸리티</li>
</ul>
</li>
<li>@Override</li>
</ul>
<h3 id="애노테이션-프로세서-장점">애노테이션 프로세서 장점</h3>
<ul>
<li>바이트코드에 대한 조작은 런타임에 발생되는 조작임으로 런타임에 대한 비용이 발생</li>
<li><strong>but. 애노테이션 프로세서는 애플리케이션을 구동하는 런타임 시점이 아니라,</strong></li>
<li><strong>컴파일 시점에 조작하여 사용함으로 런타임에 대한 비용이 제로가 됨</strong></li>
</ul>
<p><strong>단점</strong>은 기존의 코드를 고치는 방법은 현재로써는 public 한 API 가 없음.</p>
<ul>
<li>롬복 같은 경우 기존 코드를 변경하는 방법이지만 public 한 api를 이용한 것이 아님으로 해킹이라고 할 수 도 있음.</li>
</ul>
<h3 id="롬복lombok의-동작원리">롬복(Lombok)의 동작원리</h3>
<p>Lombok</p>
<ul>
<li>@Getter @Setter, @Builder 등의 애노테이션과</li>
<li>애노테이션 프로세서를 제공하여 표준적으로 작성해야 할 코드를 개발자 대신 생성해주는 라이브러리이다.</li>
</ul>
<h3 id="사용하기">사용하기</h3>
<ul>
<li>의존성 추가</li>
<li>IntelliJ Lombok 플로그인 설치</li>
<li>Intellij Annotation Processing 옵션 활성화</li>
</ul>
<h3 id="동작원리">동작원리</h3>
<ul>
<li>컴파일 시점에 <strong>&quot;애노테이션 프로세서&quot;</strong>를 사용하여  (자바가 제공하는 애노테이션 프로세서)</li>
<li><strong>소스코드의 <code>AST(Abstract Syntax Tree)</code></strong> 를 <strong><code>조작</code></strong>한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자바의 정석] Enum]]></title>
            <link>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D-Enum</link>
            <guid>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D-Enum</guid>
            <pubDate>Mon, 11 Dec 2023 01:21:17 GMT</pubDate>
            <description><![CDATA[<h1 id="1-enum-정의하는-방법">1. enum 정의하는 방법</h1>
<hr>
<p>열거형이란?</p>
<p>-JDK1.5부터 추가</p>
<p>-타입에 안전한 열거형: 실제 값과 타입이 일치해야 같다고 인식.(서로 다른 개념이나 동일 이름을 가진 값의 충돌을 막을 수 있음)</p>
<p>&lt;정의방법&gt;</p>
<p>enum 열거형이름 {상수명1, 상수명2 ...}</p>
<pre><code class="language-java">enum Direction {EAST, SOUTH, WEST, NORTH}

class Unit{
int x, y;
Direction dir;
void init(){
    dir = Direction.EAST;
    }
}

if (dir == Direction.EAST){
    x++;
}else if(dir.compareTo(Direction.WEST) &gt; 0) {
...

//첫줄에 열거할 상수의 이름을 선언
//이름은 대문자로 선언하는 것이 관례
//각 상수는 콤마로 구분(제일 마지막 상수의 끝에는 세미콜론을 붙여야 하나,
//간단히 상수의 이름만 선언할 때는 세미콜론을 붙이지 않아도 됨)</code></pre>
<p>-열거형의 상수간의 비교에는 ==와 compareTo 사용 가능.(단, &lt;,&gt;비교 연산자 사용 불가능)</p>
<p>자바 enum의 특징</p>
<ol>
<li>enum에 정의된 상수들은 해당 enum type의 객체임.</li>
<li>생성자와 메서드를 추가할 수 있음.(enum이 클래스이기 때문)</li>
</ol>
<p>→ enum 생성자의 접근제어자는 private이기 때문에 외부에서 상수 추가 불가능.</p>
<p>→ 상수 하나당 각각의 인스턴스가 만들어지며 모두 public static final 임.</p>
<pre><code class="language-java">enum Currency {

    PENNY(1), NICKLE(5), DIME(10), QUARTER(25);

    private int value;

    Currency(int value) {
        this.value = value;
    }

    public int value() {
        return value;
    }
}

public class EnumDemo {

    public static void main(String[] args) {
        System.out.println(Currency.DIME.value());    // 10
    }
}</code></pre>
<h1 id="2-enum이-제공하는-메소드-values와-valueof">2. enum이 제공하는 메소드 (values()와 valueOf())</h1>
<hr>
<p>-values() : 열거형의 모든 상수를 배열에 담아 반환. (모든 열거형이 가지고 있는 메서드로 컴파일러가 자동으로 추가해 줌)</p>
<pre><code class="language-java">Direction []dArr = Direction.values();
for(DIrection d: dArr)
    System.out.printf(&quot;%s =%d%n&quot;, d.name, d.ordinal());</code></pre>
<pre><code class="language-java">enum Transport {
    BUS, TAXI, SUBWAY;
}

public class EnumDemo {

    public static void main(String[] args) {
        for (var e : Transport.values()) {
            System.out.println(e.name()); // BUS, TAXI, SUBWAY반환
        }
                Transport taxi = Enum.valueOf(Transport.class, &quot;Taxi&quot;);
            Transport bus = Transport.valueOf(&quot;BUS&quot;);
    }
}</code></pre>
<p>-valueOf(enumType, String name) : 지정된 열거형에서 name과 일치하는 열거형을 반환.</p>
<h1 id="3-javalangenum">3. java.lang.Enum</h1>
<hr>
<p>-모든 열거형의 조상</p>
<p>→모든 열거형은 Enum 클래스를 상속받기 때문에 enum type은 별도의 상속을 받을 수 없음.</p>
<p>&lt;Enum 클래스에 정의된 메서드&gt;</p>
<table>
<thead>
<tr>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>Class<E>getDeclaringClass()</td>
<td>열거형의 class 객체 반환</td>
</tr>
<tr>
<td>String name()</td>
<td>열거형 상수의 이름을 문자열로 반환</td>
</tr>
<tr>
<td>int ordinal()</td>
<td>상수가 정의된 순서를 반환(0부터시작)</td>
</tr>
<tr>
<td>T valueOf(Class<T>enumType, String name)</td>
<td>지정된 열거형에서 name과 일치하는 열거형 상수를 반환</td>
</tr>
</tbody></table>
<h1 id="4-enumset">4. EnumSet</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/ec19fd30-26f8-437d-a4fa-7701495328d7/image.png" alt=""></p>
<p>출처: <a href="https://www.geeksforgeeks.org/enumset-class-java/">https://www.geeksforgeeks.org/enumset-class-java/</a></p>
<p>-EnumSet은 AbstractSet 클래스를 상속하고 Set 인터페이스를 구현함.</p>
<p>-오직 열거형 상수만을 값으로 가질 수 있고 모든 값은 같은 enum type이어야 함.</p>
<p>-null value를 추가하는 것을 허용하지 않음. NullPointerException을 던지는 것도 허용하지 않음.</p>
<p>-ordinal 값의 순서대로 요소가 저장됨.</p>
<p>-tread-safe하지 않음. 동기식으로 사용하려면 Collections.synchronizedMap을 사용하거나, 외부에서 동기화를 구현해야함.</p>
<p>-모든 메서드는 arithmetic bitwise operation을 사용하기 때문에 모든 기본 연산의 시간 복잡도가 O(1)임.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자바의 정석]]]></title>
            <link>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D-rvshsbr6</link>
            <guid>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D-rvshsbr6</guid>
            <pubDate>Sun, 03 Dec 2023 00:07:42 GMT</pubDate>
            <description><![CDATA[<h1 id="1-thread-클래스와-runnable-인터페이스">1. Thread 클래스와 Runnable 인터페이스</h1>
<hr>
<p>프로세스란</p>
<p>-실행 중인 프로그램</p>
<p>-사용자가 작성한 프로그램이 운영체제에 의해 메모리 공간을 할당 받아 실행 중인 것으로 프로그램에 사용되는 데이터와 메모리 등의 자원 그리고 쓰레드로 구성.</p>
<p>쓰레드란?</p>
<p>-프로세스 내에서 실제로 작업을 수행하는 주체</p>
<p>-모든 프로세스에는 1개 이상의 쓰레드가 존재</p>
<p>-두 개 이상의 쓰레드를 가지는 프로세스를 멀티 쓰레드 프로세스</p>
<p>-경량 프로세스라고 불리며 가장 작은 실행 단위</p>
<p>쓰레드 구현의 2가지 방법(Thread 클래스 vs Runnable 인터페이스)</p>
<pre><code class="language-java">public class ThreadDemo {

    public static void main(String[] args) {
        // 상속으로 구현
        ThreadByInheritance thread1 = new ThreadByInheritance();

        //인터페이스로 구현
        Runnable r = new ThreadByImplement();
        Thread thread2 = new Thread(r);    //생성자: Thread(Runnable target)
        // 아래 코드로 축약 가능
        // Thread thread2 = new Thread(new ThreadByImplement());

        thread1.start();
        thread2.start();
    }
}

class ThreadByInheritance extends Thread {

    @Override
    public void run() {
        for (int i = 0; i &lt; 500; i++) {
            System.out.print(0);
        }
    }
}

class ThreadByImplement implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i &lt; 500; i++) {
            System.out.print(1);
        }
    }
}</code></pre>
<p>⇒ <code>Thread</code> 클래스가 다른 클래스를 확장할 필요가 있을 경우에는 <code>Runnable</code> 인터페이스를 구현하면 되며, 그렇지 않은 경우는 <code>Thread</code> 클래스를 사용하는 것이 좋음.</p>
<p>⇒ 쓰레드를 생성했다고 자동을 실행되지 않음. start()를 호출해야만 쓰레드가 실행됨.</p>
<p>⇒ start()가 호출되어도 바로 실행되는 것이 아니라, 실행대기 상태에 있다가 자신의 차례가 되어야 실행됨.</p>
<p>⇒ 쓰레드의 실행 순서는 OS의 스케쥴러가 작성한 스케쥴에 의해 결정됨.</p>
<p>⇒ 한 번 실행이 종료된 쓰레드는 다시 실행할 수 없음 (하나의 쓰레드에 start()가 한 번만 호출될 수 있음.)</p>
<p>⇒ 쓰레드를 start로 호출 시 자신만의 스택을 만들어서 사용.</p>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/5033573b-4f7e-4185-908b-ed1d4a6365ca/image.png" alt=""></p>
<h1 id="2-쓰레드의-상태">2. 쓰레드의 상태</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/cab226ca-3bc1-4ee3-9eae-19eb667c9d4e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/d08cddbc-a941-4914-8947-ccefa9e5e54d/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/5efbeb5d-5641-45d8-ac19-0d13ac7aeb61/image.png" alt=""></p>
<p><strong>sleep(long millis)</strong></p>
<p>:지정된 시간 동안 쓰레드를 멈춤.</p>
<p>→ static 메서드임. (자기 자신만 재울 수 있음. ) </p>
<p>→반드시 try-catch 블록으로 예외처리를 해줘야함.</p>
<pre><code class="language-java">public class ThreadDemo {

    public static void main(String[] args) {
        Thread t1 = new Thread(new ThreadEx_1());
        Thread t2 = new Thread(new ThreadEx_2());

        t1.start();
        t2.start();

        try {
            Thread.sleep(2000);          // t1이 아닌 실행중인 자기자신 Thread여야함
        } catch (InterruptedException e) { }

        System.out.print(&quot;&lt;메인 쓰레드 종료&gt;&quot;);
    }

}

class ThreadEx_1 implements Runnable {

    @Override
    public void run() {
        System.out.print(&quot;&lt;t1 시작&gt;&quot;);
        for (int i = 0; i &lt; 100; i++) {
            System.out.print(&quot;-&quot;);
        }
        System.out.print(&quot;&lt;t1 종료&gt;&quot;);
    }
}

class ThreadEx_2 implements Runnable {

    @Override
    public void run() {
        System.out.print(&quot;&lt;t2 시작&gt;&quot;);
        for (int i = 0; i &lt; 100; i++) {
            System.out.print(&quot;|&quot;);
        }
        System.out.print(&quot;&lt;t2 종료&gt;&quot;);

    }
}</code></pre>
<p><strong>interrupt()</strong></p>
<p>:쓰레드에게 작업을 멈추라고 요청. (강제 종료는 아님.)</p>
<p>→interrupted()는 쓰레드에 대해 interrupt()가 호출되었는지 알려줌.</p>
<p>(호출되지 않았다면 false, 호출 되었다면 true 반환)</p>
<p>→쓰레드가 sleep(), wait(), join()에 의해 일시정지(waiting) 상태에 있을 때, 해당 쓰레드에 대해 interrupt()를 호출하면sleep(), wait(), join()에서 <code>Interrupted Exception</code>이 발생하고 쓰레드는 실행대기(Runnable) 상태로 바뀜.즉, 멈춰있던 쓰레드를 깨워서 실행가능한 상태로 만드는 것.</p>
<pre><code class="language-java">void interrupt()                //  쓰레드의 interrupted 상태를 false에서 true로 바꾼다
boolean isInterrupted()         //  쓰레드의 interrupted 상태를 반환한다
static boolean interrupted()    //  쓰레드의 interrupted 상태를 반환하고, false로 초기화한다</code></pre>
<pre><code class="language-java">public class ThreadDemo {

    public static void main(String[] args) {
        ThreadEx_1 t1 = new ThreadEx_1();

        t1.start();

        String input = JOptionPane.showInputDialog(&quot;게임을 다시 진행하시겠습니까? [Y/N]&quot;);
        System.out.println(input);
        t1.interrupt();
    }

}

class ThreadEx_1 extends Thread {

    @Override
    public void run() {
        int i = 10;

        while (i != 0 &amp;&amp; !isInterrupted()) {
                    try {
                        System.out.println(i--);
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        interrupt();
                    }
}
}</code></pre>
<p><strong>suspend(), resume(), stop()</strong></p>
<p>: stop은 쓰레드를 완전히 종료시키는 메서드</p>
<p>suspend는 쓰레드를 일시정지 상태로 만드는 메서드</p>
<p> resume은 정지상태의 쓰레드를 다시 실행 대기 상태로 만드는 메서드</p>
<p>→이 세 개의 메서드는 교착상태(deadlock)를 일으킬 가능성이 있어서 deprecated되었음. 따라서 사용하지 않는 것이 권장됨.</p>
<p><strong>join()</strong></p>
<p>:join 메서드는 일정 시간 동안 특정 쓰레드가 작업하는 것을 기다리게 만드는 메서드. </p>
<p>→sleep과 마찬가지로 try-catch 블록으로 예외처리를 해야 함.</p>
<pre><code class="language-java">ublic class ThreadDemo {

    public static void main(String[] args) {
        Thread t1 = new Thread(new ThreadEx_1());
        Thread t2 = new Thread(new ThreadEx_2());

        long startTime = System.currentTimeMillis();

        t1.start();
        t2.start();

        try {
            t1.join();    // t1의 작업이 끝날 때까지 기다린다.
            t2.join();    // t2의 작업이 끝날 때까지 기다린다.

        } catch (InterruptedException e) {}

        System.out.println(&quot;소요시간 : &quot; + (System.currentTimeMillis() - startTime));
        // 메인쓰레드가 종료된다.
    }

}

class ThreadEx_1 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i &lt; 500; i++) {
            System.out.print(&quot;-&quot;);
        }

    }
}

class ThreadEx_2 implements Runnable {

    boolean suspended = false;
    boolean stopped = false;

    @Override
    public void run() {
        for (int i = 0; i &lt; 500; i++) {
            System.out.print(&quot;|&quot;);
        }
    }
}</code></pre>
<p><strong>yield()</strong></p>
<p>: 자신에게 할당된 시간이 남았더라도 다음 쓰레드에게 작업을 넘기도록 하는 메서드</p>
<p>→static 메서드이므로 자기 자신에게만 사용할 수 있음.</p>
<p>→ 쓰레드가 busy-waiting 상태(작업할 내용이 없는데 작업 시간이 할당되어 쓰레드가 돌아가는 상태) 일 때 yield를 호출하도록 설계하면 프로그램의 응답성과 효율을 높일 수 있음.</p>
<h1 id="3-쓰레드의-우선순위">3. 쓰레드의 우선순위</h1>
<hr>
<p>각 쓰레드는 우선순위(priority)에 관한 자신만의 필드를 가지고 있으며 이러한 우선순위에 따라 특정 쓰레드가 더 많은 시간 동안 작업을 할 수 있도록 설정</p>
<p>!<a href="https://blog.kakaocdn.net/dn/MFHjS/btqTPzhtqy7/bqJqzVIKyMB1XUGf0xZvZ1/img.png">https://blog.kakaocdn.net/dn/MFHjS/btqTPzhtqy7/bqJqzVIKyMB1XUGf0xZvZ1/img.png</a></p>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/82f87a0d-0351-4593-8681-705a24292b75/image.png" alt="">
<img src="https://velog.velcdn.com/images/yjs_177076/post/de7c7b38-9d9d-4a22-b6fb-94dd9c3ab9e4/image.png" alt=""></p>
<p>-getPriority()와 setPrioritiy()메소드를 통해 쓰레드의 우선순위를 반환하거나 변경 가능.</p>
<p>-쓰레드의 우선순위가 가질 수 있는 범위는 1부터 10까지이며, 숫자가 높을수록 우선순위 또한 높아짐</p>
<p>-BUT, 쓰레드의 우선순위는 비례적인 절댓값이 아닌 어디까지나 상대적인 값</p>
<p>(=우선순위가 10인 쓰레드가 우선순위가 1인 쓰레드보다 10배 더 빨리 수행되는 것이 아님. 단지 우선순위가 10인 쓰레드는 우선순위가 1인 쓰레드 보다 좀 더 많이 실행 큐에 포함되어, 좀 더 많은 작업 시간을 할당받는 것.)</p>
<h1 id="4-main-쓰레드">4. Main 쓰레드</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/9179e362-ff42-4be7-8287-f1f7513a5892/image.png" alt=""></p>
<p>-main 메서드도 하나의 쓰레드 =  메인 쓰레드(Main Thread)</p>
<p>-메인 쓰레드는 프로그램이 시작하면 가장 먼저 실행되는 쓰레드이며, 모든 쓰레드는 메인 쓰레드로부터 생성됨.</p>
<p>-다른 쓰레드를 생성해서 실행하지 않으면, 메인 메서드, 즉 메인 쓰레드가 종료되는 순간 프로그램도 종료됨. (여러 쓰레드를 실행하면, 메인 쓰레드가 종료되어도 다른 쓰레드가 작업을 마칠 때까지 프로그램이 종료되지 않음.)</p>
<p>-쓰레드는 &#39;사용자 쓰레드(user thread)&#39;와 &#39;데몬 쓰레드(daemon thread)&#39;로 구분되는데,실행 중인 사용자 쓰레드가 하나도 없을 때 프로그램이 종료됨.</p>
<p>cf. Daemon Thread</p>
<p>-Main 쓰레드의 작업을 돕는 보조적인 역할을 하는 쓰레드</p>
<p>-Main 쓰레드가 종료되면 데몬 쓰레드는 강제적으로 자동 종료.(어디까지나 Main 쓰레드의 보조 역할을 수행하기 때문에 , Main 쓰레드가 없어지면 의미가 없어지기 때문)</p>
<p>-Main 쓰레드가 Daemon 이 될 쓰레드의 <code>setDaemon(true)</code>를 호출해주면 Daemon 쓰레드가 됨.</p>
<pre><code class="language-java">public class DaemonThread extends Thread{
    public void run() {
        try {
            Thread.sleep(Long.MAX_VALUE);
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}
public void runCommonThread() {
    DaemonThread thread = new DaemonThread();
    thread.start();
}
--------------------------------------------------------------------
public void runDaemonThread() {
    DaemonThread thread = new DaemonThread();
    thread.setDaemon(true);
    thread.start();
}</code></pre>
<h1 id="5-동기화">5. 동기화</h1>
<hr>
<p>동기화란?</p>
<p>어떤 쓰레드가 진행 중인 작업을 다른 쓰레드가 간섭하지 못하도록 하는 작업. </p>
<p>멀티 쓰레드 프로세스에서는 여러 프로세스가 메모리를 공유하기 때문에, 한 쓰레드가 작업하던 부분을 다른 쓰레드가 간섭하는 문제가 생길 수 있음. </p>
<p>따라서 다른 쓰레드가 간섭해서는 안 되는 부분을 임계 영역(critical section)으로 설정해야함. </p>
<p>→임계 영역 설정은 <strong>synchronized</strong> 키워드를 사용</p>
<p>1) 메서드 전체를 임계영역으로 설정</p>
<p>public synchronized void method1 () { ...... }</p>
<p>→ 쓰레드는 synchronized 키워드가 붙은 메서드가 호출된 시점부터 해당 메서드가 포함된 객체의 lock을 얻어 작업을 수행하다가 메서드가 종료되면 lock을 반환</p>
<p>2) 특정한 영역을 임계영역으로 설정</p>
<p>synchronized(객체의 참조변수) {......}</p>
<p>→이 영역으로 들어가면서부터 쓰레드는 지정된 객체의 lock을 얻게 되고 블록을 벗어나면 lock을 반납.(단, 이때 참조 변수는 락을 걸고자 하는 객체를 참조하는 것이어야 함)</p>
<p>lock이란?</p>
<p>일종의 자물쇠 개념으로 모든 객체는 lock을 하나씩 가지고 있음.</p>
<p>해당 객체의 lock을 가지고 있는 쓰레드만 임계 영역의 코드를 수행할 수 있으며 한 객체의 lock은 하나밖에 없기 때문에 다른 쓰레드들은 lock을 얻을 때까지 기다리게 됨.</p>
<pre><code class="language-java">public class ThreadDemo {

    public static void main(String[] args) {
        Runnable r = new ThreadEx_1();
        new Thread(r).start();
        new Thread(r).start();
    }
}

class Account {
    private int balance = 1000; //잔고

    public int getBalance() {
        return balance;
    }

    public void withdraw(int money) {
        synchronized (this) {
            if (balance &gt;= money) {
                try {
                    // 문제 상황을 만들기 위해 고의로 쓰레드를 일시정지
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }

                balance -= money;
            }
        }
    }
}

class ThreadEx_1 implements Runnable {

    Account account = new Account();

    @Override
    public void run() {
        while (account.getBalance() &gt; 0) {
            // 100, 200, 300 중 임의의 값을 선택해서 출금
            int money = (int) (Math.random() * 3 + 1) * 100;
            account.withdraw(money);
            System.out.println(&quot;balance: &quot; + account.getBalance());
        }
    }
}</code></pre>
<p><strong>wait() &amp; notify()</strong></p>
<table>
<thead>
<tr>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>void wait()void wait(long timeout)void wait(long timeout, int nanos)</td>
<td>객체의 락을 풀고 쓰레드를 해당 객체의 waiting pool에 넣는다.</td>
</tr>
<tr>
<td>void notify()</td>
<td>waiting pool에서 대기 중인 쓰레드 하나를 깨운다.</td>
</tr>
<tr>
<td>void notifyAll()</td>
<td>waiting pool에서 대기 중인 모든 쓰레드를 깨운다.</td>
</tr>
<tr>
<td>1. 동기화된 임계 코드 영역의 작업을 수행하다가 작업을 더 이상 진행할 상황이 아니면, 일단 wait()을 호출하여 쓰레드가 락을 반납하고 기다리게 함.</td>
<td></td>
</tr>
<tr>
<td>2. 그러면 다른 쓰레드가 락을 얻어서 해당 객체에 대한 작업을 수행할 수 있게 됨.</td>
<td></td>
</tr>
<tr>
<td>3. 나중에 작업을 진행할 수 있는 상황이 되면 notify()를 호출해서 작업을 중단했던 쓰레드가 다시 락을 얻어 작업을 진행할 수 있게 됨.</td>
<td></td>
</tr>
</tbody></table>
<pre><code class="language-java">class Account {
    private int balance = 1000;

    public synchronized void withdraw(int money) {
        //잔고가 출금액보다 적어 인출을 할 수 없다.
        while (balance &lt; money) {
            try {
                // 해당 객체의 락을 풀고 waiting pool에서 대기
                wait();
            } catch (InterruptedException e) {}
        }
        balance -= money;
    }

    public synchronized void deposit(int money) {
        // 돈을 입금하고 waiting pool의 쓰레드에 통보 
        balance += money;
        notify();
    }
}</code></pre>
<h1 id="6-데드락">6. 데드락</h1>
<hr>
<p>데드락이란?</p>
<p>한 자원을 여러 시스템이 사용하려고 할 때 발생할 수 있는 교착상태
<img src="https://velog.velcdn.com/images/yjs_177076/post/cc68a439-cc2f-47f4-b2d7-6244406dff80/image.png" alt=""></p>
<p>서로 원하는 리소스가 상대방에게 할당되어 있기 때문에 두 프로세스는 무한히 대기 상태에 있게됨.</p>
<p>&lt;데드락 발생 조건&gt; </p>
<ol>
<li><p>상호 배제(Mutual exclusion)</p>
<ul>
<li>자원은 한 번에 한 프로세스만이 사용할 수 있어야 한다.</li>
</ul>
</li>
<li><p>점유 대기(Hold and wait)</p>
<ul>
<li>최소한 하나의 자원을 점유하고 있으면서 다른 프로세스에 할당되어 사용하고 있는 자원을 추가로 점유하기 위해 대기하는 프로세스가 있어야 한다.</li>
</ul>
</li>
<li><p>비선점(No preemption)</p>
<ul>
<li>다른 프로세스에 할당된 자원은 사용이 끝날 때까지 강제로 빼앗을 수 없어야 한다.</li>
</ul>
</li>
<li><p>순환 대기(Circular wait)</p>
<ul>
<li><p>프로세스의 집합{P0, P1, ,…Pn}에서P0는P1이 점유한 자원을 대기하고P1은P2가 점유한 자원을 대기하고P2…Pn-1은Pn이 점유한 자원을 대기하며Pn은P0가 점유한 자원을 요구해야 한다.</p>
<p>⇒ 4가지 조건이 모두 성립할때만 데드락 발생. 하나라도 성립하지 않으면 교착 상태 해결 가능.</p>
<p>(출처:<a href="https://jwprogramming.tistory.com/12%5B%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC">https://jwprogramming.tistory.com/12[개발자를</a> 꿈꾸는 프로그래머])</p>
</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자바의 정석] 예외 처리]]></title>
            <link>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Sat, 02 Dec 2023 06:57:54 GMT</pubDate>
            <description><![CDATA[<h1 id="1-자바에서-예외-처리-방법-try-catch-throw-throws-finally">1. 자바에서 예외 처리 방법 (try, catch, throw, throws, finally)</h1>
<hr>
<p>에러의 종류</p>
<p>-컴파일 에러: 컴파일 시에 발생하는 에러</p>
<p>-런타임 에러: 실행 시에 발생하는 에러</p>
<p>-논리적 에러: 실행은 되지만 의도와 다르게 동작</p>
<ol>
<li>try-catch문</li>
</ol>
<pre><code class="language-java">try {
//예외 발생 가능성 있는 문장들
} catch (Exception e1)
{
// Exception e1이 발생했을 경우 처리할 문장
} catch (Exception2 e2)
{
// Exception e1이 발생했을 경우 처리할 문장
} catch (ExceptionN eN)
{
// Exception e1이 발생했을 경우 처리할 문장
}

// try 블럭이나 catch 블럭에서는 문장이 한줄이어도 괄호 생략 불가.

//try 블럭이나 catch 블럭 내에 또다른 try-catch 구문 사용 가능.

// 발생한 예외와 일치하는 catch 블럭으로 이동해서 문장 수행하고 try-catch구문 빠져나가서
//그 다음 문장 수행. 일치하는 catch 가 없다면 예외 처리 이루어지지 않음.

// try-catch 마지막에 exception클래스 타입의 참조변수를 선언한 catch 블럭 만들면
// 어떤 종류의 예외가 발생하더라도 해당 catch 문으로 처리가능</code></pre>
<p>cf. printStackTrace(): 예외 발생 당시의 호출스택에 있던 메서드의 정보와 예외 메세지를 화면에 출력.</p>
<p>getMessage: 발생한 예외 클래스의 인스턴스에 저장된 메세지를 얻을 수 있음.</p>
<ol>
<li>throw/ throws문</li>
</ol>
<p>메서드에 예외 선언하려면 메서드 선언부에 키워드 throws 사용해서 발생 가능한 예외를 , 기준으로 나열.</p>
<pre><code class="language-java">void method() throws Exception1, Exception2, Exception3{
//메서드 내용
} </code></pre>
<p>보통 반드시 처리해야하는 예외의 경우 나열(RuntimeException클래스들은 보통 적지 않음)</p>
<p>자신을 호출한 메서드에게 예외를 전달하여 떠맡기는 형식으로 전달받은 메서드가 또다시 넘길 수 있음</p>
<p>이런식으로 계속 호출스택에 있는 메서드들 따라서 전달되다가 마지막에는 main에서 try-catch 문으로 예외처리해주어야 정상적으로 종료 가능.</p>
<ol>
<li>finally 블럭</li>
</ol>
<p>try-catch 문과 함께 예외의 발생 여부에 상관없이 실행되어야할 코드를 포함시킬 목적으로 사용. </p>
<pre><code class="language-java">try {
//예외 발생 가능성 있는 문장들
} catch (Exception e1)
{
// Exception e1이 발생했을 경우 처리할 문장
} finally{
//예외 밟생 여부에 관계없이 수행되어야하는 문장
}</code></pre>
<p>try블럭 혹은 catch블럭에서 예외가 발생하거나 return하는 경우에도 finally 블럭에 있는 문장들을 시행시키고 프로그램 종료됨.</p>
<h1 id="2-자바가-제공하는-예외-계층-구조">2. 자바가 제공하는 예외 계층 구조</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/5b04a879-a393-4a2e-bd23-bee6126fa968/image.png" alt=""></p>
<p>출처: 자바의 정석 3판 415p</p>
<p>→ 모든 예외의 최고 조상은 exception클래스</p>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/36ee752e-9033-442e-ac71-6061f05659c6/image.png" alt=""></p>
<p>출처: 자바의 정석 3판 415p</p>
<p>→ Exception 클래스들: 사용자의 실수와 같은 외적 요인에 의해 발생하는 예외</p>
<p>e.g. FileNotFoundException : 존재하지 않는 파일의 이름 입력</p>
<p>ClassNotFoundException: 클래스 이름 잘못 입력</p>
<p>DataFormatException: 입력한 데이터 형식의 오류</p>
<p>→Runtime Exception클래스들: 프로그래머의 실수</p>
<p>e.g. IndexOutOfBoundException: 배열의 범위를 멋어남</p>
<p>NullPointerException: 값이 null인 참조변수의 멤버를 호출</p>
<p>ClassCastException: 클래스간의 형변환 오류</p>
<p>ArthimeticException: 정수를 0으로 나누려함</p>
<h1 id="3-exception과-error의-차이는">3. Exception과 Error의 차이는?</h1>
<hr>
<p>에러(error) vs 예외(exception)</p>
<p>-에러: 메모리 부족이나 스택오버플로우와 같은 코드로 수습 불가능한 심각한 오류</p>
<p>-예외: 프로그램 코드로 수습될 수 있는 다소 미약한 오류</p>
<h1 id="4-runtimeexception과-re가-아닌-것의-차이는">4. RuntimeException과 RE가 아닌 것의 차이는?</h1>
<hr>
<p><img src="https://velog.velcdn.com/images/yjs_177076/post/835e4afe-b126-4d0d-8274-789f65265c59/image.png" alt=""></p>
<p>RE란?</p>
<p>말 그대로 실행 중에 발생하며 시스템 환경적으로나 인풋 값이 잘못된 경우, 혹은 의도적으로 프로그래머가 잡아내기 위한 조건등에 부합할 때 발생</p>
<p>→RuntimeException을 상속받지 않고 Exception을 상속받는 모든 Exception은 Checked Exception</p>
<p>unchecked예외: 컴파일러가 예외처리를 확인하지 않는 RuntimeException클래스들</p>
<p>checked예외: 예외처리를 확인하는 클래스들</p>
<h1 id="5-커스텀한-예외-만드는-방법">5. 커스텀한 예외 만드는 방법</h1>
<hr>
<pre><code class="language-java">class MyException extends Exception{
        MyException(String msg) {
            super(msg); // 조상인 Exception 클래스의 생성자 호출
        }
}</code></pre>
<p>→ 보통 예외 처리 강제하지 않는 uncheked를 선호함.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자바의 정석] 인터페이스]]></title>
            <link>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D</link>
            <guid>https://velog.io/@yjs_177076/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D</guid>
            <pubDate>Thu, 30 Nov 2023 05:16:28 GMT</pubDate>
            <description><![CDATA[<h1 id="1-인터페이스-정의하는-방법">1. 인터페이스 정의하는 방법</h1>
<hr>
<p>인터페이스란?</p>
<p>일종의 추상클래스이나 추상클래스보다 추상화 정도가 높아서 오직 추상메서드와 상수만을 멤버로 가질 수 있음. (일반 메서드나 멤버변수 등 어떠한 요소도 허용되지 않음)</p>
<pre><code class="language-java">interface 인터페이스이름{
    public static final 타입 상수이름 = 값;
    public abstract 메서드이름(매개변수목록);
}</code></pre>
<p>→ 모든 멤버변수는 public static final 이어야하며 생략 가능.</p>
<p>→모든 메서드는 public abstract 이어야하며 생략 가능.</p>
<p>(단, JDK1.8부터 static 메서드와 디폴트 메서드는 예외)</p>
<p>cf. 인터페이스의 이름</p>
<p>: 주로 able로 끝나는 경우가 많음 </p>
<p>= 어떠한 기능 또는 행위를 하는데 필요한 메서드를 제공한다는 의미를 강조하기 위해. 또한 해당 인터페이스를 구현한 클래스는 ~를 할 수  있는 능력을 갖추었다는 의미.</p>
<h1 id="2-인터페이스-구현하는-방법">2. 인터페이스 구현하는 방법</h1>
<hr>
<p>인터페이스 자체로는 인스턴스 생성 불가.</p>
<p>추상클래스와 마찬가지로 정의된 추상메서드의 몸통을 만들어주는 클래스 작성. </p>
<p>extends가 아닌 implements 사용(구현한다는 의미)</p>
<pre><code class="language-java">class 클래스이름 implements 인터페이스이름{}

class Fighter implements Fightable{
    public void move(int x, int y){ .....}
    public void attack(Unit u) {.....}
}</code></pre>
<p>→ 인터페이스 메서드 중 일부만 구현한다면 abstract 붙여서 추상클래스로 선언.</p>
<p>→ 상속과 구현 동시에 가능</p>
<p>e.g. class Fighter extends Unit implements Fightable{}</p>
<h1 id="3-인터페이스-레퍼런스를-통해-구현체를-사용하는-방법">3. 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법</h1>
<hr>
<p>⇒ 인터페이스를 이용한 다형성</p>
<p>인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조 가능. </p>
<p>인터페이스 타입으로 형변환도 가능</p>
<pre><code class="language-java">Fightable f = (Fightable) new Fighter();
// fightable 타입의 참조변수로는 인터페이스 fightable에 정의된 멤버들만 호출 가능.</code></pre>
<p>→ 인터페이스 타입의 매개변수는 메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공. </p>
<pre><code class="language-java">class Fighter extends Unit implements Fightable {
    public void move(int x, int y)
    public void attack(Fightable f)
}
//attack 메서드 호출 시 매개변수로 fightable 인터페이스를 구현한 클래스의 인스턴스를 넘겨주어야함
//fightable을 구현한 fighter 클래스가 있을때 attack메서드의 매개변수로 fighter인스턴스 넘김
= attack(new Fighter())

Fightable method()
{
        Fighter f = new Fighter();
        return f;
}
// 메서드의 리턴타입으로 인터페이스의 타입 지정 가능.
// 리턴타입이 인터페이스 = 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스 반환</code></pre>
<h1 id="4-인터페이스-상속">4. 인터페이스 상속</h1>
<hr>
<p>인터페이스는 인터페이스로부터만 상속 가능.</p>
<p>→ 클래스와 달리 다중 상속 가능. Object클래스처럼 최고 조상 없음.</p>
<pre><code class="language-java">interface Movable{
    void move(int x, int y);
}

interface Attackable{
    void attack(Unit u);
}

interface Fightable extends Movable, Attackable{}</code></pre>
<h1 id="5인터페이스의-기본-메소드-default-method-자바-8">5.인터페이스의 기본 메소드 (Default Method), 자바 8</h1>
<hr>
<p>디폴트 메서드란?</p>
<p>추상 메서드의 기본적인 구현을 제공하는 메서드로, 추상 메서드가 아니기 때문에 디폴트 메서드가 추가되어도 해당 인터페이스를 구현한 클래스 변경하지 않아도 됨.</p>
<p>→JDK1.8부터 인터페이스에 디폴트메서드와 static 메서드 추가 가능. </p>
<p>→ 추상메서드와 달리 일반 메서드처럼 몸통이 있어야함.</p>
<p>→ public 접근제어자 </p>
<pre><code class="language-java">interface MyInterface{
    void method();
    public void newMethod(){}
}</code></pre>
<p>** 새로 추가된 디폴트 메서드와 기존 메서드의 이름 중복 충돌 해결 규칙</p>
<ol>
<li><p>여러 인터페이스의 디폴트 메서드간 충돌</p>
<p> → 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩</p>
</li>
<li><p>디폴트 메서드와 조상 클래스의 메서드 간의 충돌</p>
<p> → 조상 클래스의 메서드가 상속되고 디폴트 메서드는 무시.</p>
</li>
</ol>
<h1 id="6인터페이스의-static-메소드-자바-8">6.인터페이스의 static 메소드, 자바 8</h1>
<hr>
<p>인스턴스 생성하지 않고 사용가능한 메서드</p>
<p><a href="https://www.notion.so/4b0cf3f6ff7549adb2951e27519fc0e6?pvs=21">https://www.notion.so/4b0cf3f6ff7549adb2951e27519fc0e6</a></p>
<h1 id="7-인터페이스의-private-메소드-자바-9">7. 인터페이스의 private 메소드, 자바 9</h1>
<hr>
<p>특정 기능을 처리하는 내부 메서드의 경우 다른 인터페이스 혹은 클래스가 해당 메서드에 엑세스 하지 않도록 하기 위해 사용. (캡슐화 개념)</p>
<p>&lt;private 메서드 구현 규칙&gt;</p>
<ul>
<li>private 메소드는 구현부를 가져야함</li>
<li>오직 인터페이스 내부에서만 사용 가능</li>
<li>private static 메소드는 다른 static 또는 static이 아닌 메소드에서 사용할 수 있음</li>
<li>static이 아닌 private 메소드는 다른 private static 메소드에서 사용할 수 없음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MSA vs Monolithic architecture]]></title>
            <link>https://velog.io/@yjs_177076/MSA-vs-Monolithic-architecture</link>
            <guid>https://velog.io/@yjs_177076/MSA-vs-Monolithic-architecture</guid>
            <pubDate>Tue, 28 Nov 2023 02:44:16 GMT</pubDate>
            <description><![CDATA[<h3 id="🤓오늘의-공부-주제-msa-monolithic-architecture🤓">🤓오늘의 공부 주제: MSA, Monolithic architecture🤓</h3>
<h3 id="q-모놀리식-구조와-msa의-차이는-무엇인가">Q. 모놀리식 구조와 MSA의 차이는 무엇인가?</h3>
<blockquote>
<p>A. 모놀리식(Monolithic) 아키텍처와 마이크로서비스(Microservices) 아키텍처는 소프트웨어 시스템을 설계하고 구축하는 두 가지 주요 접근 방식</p>
</blockquote>
<h4 id="1-아키텍처-구조">1. 아키텍처 구조:</h4>
<ul>
<li>모놀리식(Monolithic): 모놀리식 아키텍처는 하나의 큰 코드베이스로 이루어져 있습니다. 애플리케이션의 모든 구성 요소(데이터베이스, 사용자 인터페이스, 비즈니스 로직 등)가 단일한 코드베이스에 통합되어 있습니다.</li>
<li>마이크로서비스(Microservices): 마이크로서비스 아키텍처는 여러 작은 서비스로 구성되어 있습니다. 각 서비스는 자체의 독립적인 코드베이스와 데이터베이스를 가지며, 서로 통신하여 전체 애플리케이션을 형성합니다.</li>
</ul>
<h4 id="2-커뮤니케이션과-통합">2. 커뮤니케이션과 통합:</h4>
<ul>
<li>모놀리식: 애플리케이션의 모든 부분이 같은 코드베이스에 있으므로, 컴포넌트 간의 통합이 비교적 간단합니다. 하지만 큰 규모의 애플리케이션에서는 모든 부분을 이해하고 유지보수하기 어려울 수 있습니다.</li>
<li>마이크로서비스: 각 마이크로서비스는 독립적으로 배포되고 업데이트될 수 있으므로, 서비스 간의 커뮤니케이션과 통합이 중요한 과제가 됩니다. API를 통한 외부 통신이 일반적이며, 이를 통해 각 서비스는 독립적으로 개발, 배포, 확장될 수 있습니다.</li>
</ul>
<h4 id="3배포-및-확장성">3.배포 및 확장성:</h4>
<ul>
<li>모놀리식: 전체 애플리케이션을 한 번에 배포해야 하며, 특정 부분만 확장하기가 어려울 수 있습니다. 확장성이 부족할 수 있습니다.</li>
<li>마이크로서비스: 각 서비스는 독립적으로 배포 가능하며, 필요한 서비스만 확장할 수 있습니다. 이로 인해 전체 시스템이 더 효율적으로 확장될 수 있습니다.</li>
</ul>
<h4 id="4-유지보수-및-확장성">4. 유지보수 및 확장성:</h4>
<ul>
<li>모놀리식: 작은 프로젝트나 초기 단계에서는 유지보수가 쉬울 수 있지만, 시간이 지남에 따라 코드베이스가 커지면 유지보수가 어려워질 수 있습니다.</li>
<li>마이크로서비스: 각 서비스가 독립적으로 개발되고 관리되기 때문에 유지보수가 상대적으로 쉽습니다. 또한, 새로운 서비스를 추가하거나 기존 서비스를 변경하기가 용이합니다.</li>
</ul>
<p>이러한 차이로 인해 모놀리식 아키텍처는 간단한 애플리케이션 및 초기 단계의 프로젝트에 적합할 수 있으며, 마이크로서비스 아키텍처는 대규모 및 복잡한 시스템을 구축하고 유지보수하는 데 더 적합할 수 있습니다. 선택은 프로젝트의 규모, 요구 사항, 팀의 기술적 선호도 등에 따라 다를 수 있습니다.</p>
<h4 id="모놀리식-구조의-예시">모놀리식 구조의 예시</h4>
<pre><code>/my-monolith-app
|-- /src
|   |-- /components
|   |-- /services
|   |-- /utils
|   |-- /...
|-- /public
|-- package.json
|-- webpack.config.js
|-- ...
</code></pre><h4 id="msa-구조의-예시">MSA 구조의 예시</h4>
<pre><code>/msa-project
|-- /service1
|   |-- /src
|   |   |-- /components
|   |   |-- /models
|   |   |-- /routes
|   |   |-- /tests
|   |   |-- ...
|   |-- package.json
|   |-- Dockerfile
|   |-- ...
|-- /service2
|   |-- /src
|   |   |-- /components
|   |   |-- /models
|   |   |-- /routes
|   |   |-- /tests
|   |   |-- ...
|   |-- package.json
|   |-- Dockerfile
|   |-- ...
|-- /service3
|   |-- /src
|   |   |-- /components
|   |   |-- /models
|   |   |-- /routes
|   |   |-- /tests
|   |   |-- ...
|   |-- package.json
|   |-- Dockerfile
|   |-- ...
|-- /common
|   |-- /src
|   |   |-- /constants
|   |   |-- /helpers
|   |   |-- /utils
|   |   |-- ...
|   |-- package.json
|   |-- ...
|-- /gateway
|   |-- /src
|   |   |-- /routes
|   |   |-- /middlewares
|   |   |-- ...
|   |-- package.json
|   |-- Dockerfile
|   |-- ...
|-- docker-compose.yml
|-- ...
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[동기와 비동기 그리고 promise]]></title>
            <link>https://velog.io/@yjs_177076/%EB%8F%99%EA%B8%B0%EC%99%80-%EB%B9%84%EB%8F%99%EA%B8%B0-%EA%B7%B8%EB%A6%AC%EA%B3%A0-promise</link>
            <guid>https://velog.io/@yjs_177076/%EB%8F%99%EA%B8%B0%EC%99%80-%EB%B9%84%EB%8F%99%EA%B8%B0-%EA%B7%B8%EB%A6%AC%EA%B3%A0-promise</guid>
            <pubDate>Mon, 27 Nov 2023 00:02:33 GMT</pubDate>
            <description><![CDATA[<h3 id="🤓오늘의-공부-주제-동기비동기-promise🤓">🤓오늘의 공부 주제: 동기/비동기, promise🤓</h3>
<h3 id="q-동기비동기란-무엇인가">Q. 동기/비동기란 무엇인가?</h3>
<blockquote>
<p>A. 동기(Synchronous)와 비동기(Asynchronous)는 프로그램이 작업을 수행하는 방식에 관한 용어입니다. 프로미스(Promise)는 비동기 코드를 더 효과적으로 다루기 위한 자바스크립트의 패턴 중 하나입니다.</p>
</blockquote>
<h4 id="1-동기synchronous">1. 동기(Synchronous):</h4>
<p>동기적인 코드는 한 번에 하나의 작업만 수행하며, 다음 작업은 이전 작업이 완료될 때까지 기다립니다.
코드는 위에서 아래로 순차적으로 실행되며, 각 작업이 끝나기 전까지 다음 작업으로 진행하지 않습니다.</p>
<pre><code class="language-javascript">console.log(&quot;Start&quot;);

function synchronousTask() {
  console.log(&quot;Task 1&quot;);
  console.log(&quot;Task 2&quot;);
}

synchronousTask();

console.log(&quot;End&quot;);

//출력
Start
Task 1
Task 2
End
</code></pre>
<h4 id="2-비동기asynchronous">2. 비동기(Asynchronous):</h4>
<p>비동기적인 코드는 작업을 기다리지 않고 다음 코드를 실행합니다. 이때, 비동기 작업은 별도의 실행 컨텍스트에서 백그라운드에서 수행됩니다.
주로 콜백 함수, 이벤트 핸들러, 프로미스 등을 사용하여 비동기 작업을 다룹니다.</p>
<pre><code class="language-javascript">console.log(&quot;Start&quot;);

function asynchronousTask() {
  setTimeout(function () {
    console.log(&quot;Async Task&quot;);
  }, 2000);
}

asynchronousTask();

console.log(&quot;End&quot;);

//출력
Start
End
Async Task  // 2초 후에 출력
</code></pre>
<h4 id="3-프로미스promise">3. 프로미스(Promise):</h4>
<p>프로미스는 비동기 작업을 더 편리하게 다루기 위한 객체입니다.
성공 또는 실패와 같은 비동기 작업의 최종 완료 또는 실패를 나타내는 객체로, 비동기 작업이 완료되면 resolve 또는 reject 콜백 중 하나가 호출됩니다.</p>
<pre><code class="language-javascript">console.log(&quot;Start&quot;);

function promiseTask() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve(&quot;Promise Task&quot;);
    }, 2000);
  });
}

promiseTask().then(function (result) {
  console.log(result);
});

console.log(&quot;End&quot;);

//출력
Start
End
Promise Task  // 2초 후에 출력
</code></pre>
]]></description>
        </item>
    </channel>
</rss>