<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>parkrootseok.log</title>
        <link>https://velog.io/</link>
        <description>동료들의 시간과 노력을 더욱 빛내줄 수 있는 개발자가 되고자 노력합니다.</description>
        <lastBuildDate>Sat, 16 Aug 2025 06:33:20 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. parkrootseok.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/park_rootseok" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[람다를 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%EB%9E%8C%EB%8B%A4%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/%EB%9E%8C%EB%8B%A4%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sat, 16 Aug 2025 06:33:20 GMT</pubDate>
            <description><![CDATA[<h2 id="람다">람다</h2>
<p><code>람다</code>는 익명 함수를 표현하기 위해 사용하는 문법입니다. 이를 활용하여 메서드 자체를 메서드의 매개변수로 전달할 수 있습니다.</p>
<h3 id="java에서의-람다">Java에서의 람다</h3>
<p>Java는 함수를 2급시민으로 취급합니다. 즉, 변수에 직접 할당하거나 파라미터로 전달할 수 없습니다. 그렇기 때문에 아래와 같이 함수형 인터페이스를 활용해야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/f9fe1eff-c67c-4c0d-b16c-7f1ee7de8c57/image.png" alt=""></p>
<blockquote>
<h4 id="함수형-인터페이스-종류">함수형 인터페이스 종류</h4>
</blockquote>
<ul>
<li>Predicate&amp;ltT&gt; : 조건 검사 (true/false 반환)</li>
<li>Function&amp;ltT,R&amp;gt : 입력 → 출력 변환</li>
<li>Consumer&amp;ltT&amp;gt : 입력 소비 (리턴 없음)</li>
<li>Supplier&amp;ltT&amp;gt : 값 제공 (입력 없음)</li>
</ul>
<h3 id="kotlin에서의-람다">Kotlin에서의 람다</h3>
<p>Kotlin에서는 함수를 1급시민으로 취급합니다. 즉, 함수 자체를 변수에 할당하거나 파라미터로 전달할 수 있고, 별도의 함수형 인터페이스가 필요하지 않습니다. 함수형 인터페이스를 활용해 전달받는 Java와 달리 아래와 같이 파라미터 타입과 반환 타입을 통해 전달받을 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/3e2c8f2c-92d8-4373-8066-8eced32a78bb/image.png" alt=""></p>
<p>이는 아래와 같이 변수에 할당하지 않고 바로 선언하는 형태로 변형될 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/94b07fd8-5df4-4301-8194-8428e35ac064/image.png" alt=""></p>
<p>중괄호와 화살표를 활용하는 형태의 함수의 경우 함수를 받는 파라미터가 마지막에 위치해 있다면 다음과 같은 형태도 가능합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/f1268c7b-68b8-445c-83d7-72e68dfa7531/image.png" alt=""></p>
<p>파라미터에 들어가야 할 파라미터 타입 추론도 가능하기 때문에 타입 생략이 가능하고, Kotlin에서는 파라미터가 1개인 경우 <code>It</code> 키워드를 사용하여 다음과 같이 형태로도 변형할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/c9dab07f-ff2a-4c12-8295-4ae892cbe84e/image.png" alt=""></p>
<h2 id="closure">Closure</h2>
<p><code>Closure</code>는 람다가 실행되는 시점에 사용하고 있는 외부 변수를 포획하여, 해당 변수가 원래의 스코프를 벗어난 이후에도 계속 접근할 수 있도록 만들어주는 개념입니다.</p>
<h3 id="java에서의-closure">Java에서의 Closure</h3>
<p>Java는 <code>final</code> 혹은 <code>effectively final(사실상 값이 변하지 않는) 변수</code>만 캡처할 수 있습니다. 아래와 같이 변경되는 외부 변수는 람다 표현식 내부에서 사용 불가합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/459f49c4-aaf9-4230-b10b-137df826799a/image.png" alt=""></p>
<h3 id="kotlin에서의-closure">Kotlin에서의 Closure</h3>
<p>Kotlin은 Java와 달리 외부 변수를 자유롭게 캡처할 수 있고, 심지어 값 변경도 가능합니다. 아래와 같이 변경되는 외부 변수도 람다 표현식 내부에서 사용 가능합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/cb6ea1de-fff3-43ea-8134-b2cd870fcf9f/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[함수를 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%ED%95%A8%EC%88%98%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95-y2cfn66e</link>
            <guid>https://velog.io/@park_rootseok/%ED%95%A8%EC%88%98%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95-y2cfn66e</guid>
            <pubDate>Fri, 15 Aug 2025 11:37:32 GMT</pubDate>
            <description><![CDATA[<h2 id="확장-함수">확장 함수</h2>
<h3 id="왜-필요할까요">왜 필요할까요?</h3>
<p>대부분의 Java 라이브러리는 Java로 작성되어 있습니다. 하지만 Kotlin 개발자는 val과 var, Null-Safety 등 Kotlin의 장점을 유지한 채 Java 라이브러리를 활용하고 싶어합니다. 그러나 기존 Java 클래스에 기능을 추가하려면 상속이나 헬퍼 클래스를 사용해야 하며, 이는 번거롭고 유지보수에 불리합니다. 이 한계를 넘어 원본 수정 없이 Kotlin 스타일로 기능을 확장하기 위해 등장한 것이 확장 함수입니다.</p>
<h3 id="그래서-확장-함수는-뭔가요">그래서, 확장 함수는 뭔가요?</h3>
<p><code>확장 함수</code>는 <strong>기존 클래스의 소스를 수정하지 않고도, 마치 원래부터 그 클래스에 있던 메서드처럼 호출</strong>할 수 있게 해주는 함수입니다. 이를 통해 Kotlin과 Java의 상호 운용성을 높이고, 코드 가독성과 유지 보수성을 개선할 수 있습니다.</p>
<h3 id="어떻게-쓰나요">어떻게 쓰나요?</h3>
<h4 id="예시">예시</h4>
<p>아래와 같이 <code>String</code>은 원래 <code>trimmedLength()</code> 메서드를 가지고 있지 않지만, 확장 함수를 통해 마치 원래부터 있었던 것처럼 호출할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/aa9e30bc-d06f-4d5d-9cba-c70244a8f1d9/image.png" alt=""></p>
<h4 id="참고-사항">참고 사항</h4>
<ul>
<li><p>수신 객체의 private 함수를 가져오면 캡슐화가 깨지지 않나요?</p>
<ul>
<li>확장 함수는 수신 객체의 <code>private, protected</code> 멤버에는 접근할 수 없습니다. 이는 캡슐화를 깨뜨리지 않고, 오직 public 범위 내에서만 동작함을 의미합니다.</li>
</ul>
</li>
<li><p>멤버 함수와 확장 함수의 시그니처가 같을 경우 무엇이 호출되나요?</p>
<ul>
<li>Kotlin에서는 멤버 함수가 항상 우선합니다. 즉, 동일한 시그니처를 가진 멤버 함수와 확장 함수가 동시에 존재하면, 확장 함수는 무시되고 멤버 함수가 호출됩니다. </li>
</ul>
</li>
<li><p>확장 함수를 오버라이드한 경우 무엇이 호출되나요?</p>
<ul>
<li>호출되는 확장 함수는 변수의 현재 타입 즉 정적인 타입에 의해 결정됩니다.</li>
</ul>
</li>
</ul>
<h2 id="중위-함수">중위 함수</h2>
<p><code>중위 함수</code>는 <code>infix</code> 라는 키워드를 활용하여 <code>변수.함수이름(인자)</code> 대신 <code>변수 함수이름 인자</code> 형태로 호출할 수 있게 해주는 함수입니다. 아래와 같이 활용할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/bbf3becb-9250-4a01-9c1b-eeee6e5a6150/image.png" alt=""></p>
<h2 id="인라인-함수">인라인 함수</h2>
<p><code>인라인 함수</code>는 함수가 호출되는 대신 함수를 호출한 지점에 함수 본문을 그대로 복사/붙어넣기 할 수 있게 해주는 함수입니다. 아래와 같이 자바 코드로 변환된 결과를 보면, 함수를 호출하지 않고 덧셈 로직 자체가 복사/붙어넣기가 수행된 것을 알 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/78b9b321-67a9-4582-b80f-0e45e8f023fe/image.png" alt=""></p>
<h2 id="지역-함수">지역 함수</h2>
<p><code>지역 함수</code>는 함수 안에 선언되어 있는 함수를 말합니다. 아래와 같이 활용할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/303dcd9a-6332-430b-b25d-56194e060434/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[직렬화와 역직렬화]]></title>
            <link>https://velog.io/@park_rootseok/%EC%A7%81%EB%A0%AC%ED%99%94%EC%99%80-%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94</link>
            <guid>https://velog.io/@park_rootseok/%EC%A7%81%EB%A0%AC%ED%99%94%EC%99%80-%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94</guid>
            <pubDate>Wed, 13 Aug 2025 05:13:24 GMT</pubDate>
            <description><![CDATA[<h2 id="직렬화">직렬화</h2>
<h3 id="직렬화란">직렬화란?</h3>
<p><code>직렬화</code>는 자바 객체를 바이트 스트림으로 변환하는 과정입니다. 이 과정 덕분에 객체를 파일로 저장하거나, 네트워크로 전송할 수 있습니다.</p>
<h3 id="동작-방식">동작 방식</h3>
<p>자바에서는 <code>ObjectOutputStream</code> 클래스를 사용하여 아래와 같이 직렬화를 수행합니다.</p>
<pre><code class="language-java">import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SerializationExample {

    static class FileDto implements Serializable {        // 반드시, Serializable 구현 필요
        private static final long serialVersionUID = 1L;    // 클래스 버전 관리 (역직렬화 시 호환성 보장)
        private transient String password;    // transient 키워드가 선언된 필드는 직렬화 제외 (static도 해당)
        private String name;
        private int size;

        public FileDto(String name, int size) {
            this.name = name;
            this.size = size;
        }
    }

    public static void main(String[] args) {
        try {
            // 직렬화 대상
            FileDto dto = new FileDto(&quot;example.txt&quot;, 1024);

            // 직렬화 수행
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(&quot;obj.dat&quot;));

            // writeObject()는 자바 객체를 바이트 스트림으로 변환 후
            // 해당 스트림을 연결된 출력 대상에 기록
            // - 클래스 메타데이터, serialVersionUID 저장
            // - transient, static은 제외
            // - 참조 타입이 있을 경우, 재귀적으로 직렬화
            oos.writeObject(dto);
            oos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<blockquote>
<h4 id="static-변수는-왜-역직렬화하지-않나요">static 변수는 왜 (역)직렬화하지 않나요?</h4>
<p><code>static</code> 필드는 Method Area에서 관리되는 상태로, 인스턴스의 상태가 아닌 클래스 전체가 공유하는 상태입니다. 즉, <code>static</code> 필드를 굳이 각 객체에 저장할 필요가 없다는 것을 의미합니다.</p>
</blockquote>
<h2 id="역직렬화란">역직렬화란?</h2>
<p><code>역직렬화</code>는 바이트 스트림을 다시 자바 객체로 변환하는 과정입니다. 이 과정을 통해 파일이나 네트워크에서 받은 데이터를 원래의 객체 상태로 복원할 수 있습니다.</p>
<h3 id="동작-방식-1">동작 방식</h3>
<p>자바에서는 <code>ObjectInputStream</code> 클래스를 사용하여 아래와 같이 역직렬화를 수행합니다.</p>
<pre><code class="language-java">import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class DeserializationExample {
    static class FileDto implements Serializable {    // 반드시, Serializable 구현 필요
        private static final long serialVersionUID = 1L;    // 클래스 버전 관리 (역직렬화 시 호환성 보장)
        private transient String password;    // transient 키워드가 선언된 필드는 역직렬화 제외 (static도 해당)
        private String name;
        private int size;

        public FileDto(String name, int size) {
            this.name = name;
            this.size = size;
        }

        @Override
        public String toString() {
            return &quot;FileDto{name=&#39;&quot; + name + &quot;&#39;, size=&quot; + size + &quot;}&quot;;
        }
    }

    public static void main(String[] args) {
        try {
            // 역직렬화 수행
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(&quot;obj.dat&quot;));

            // readObject()는 obj.dat에 저장된 바이트 스트림을 읽어
            // 클래스 메타데이터와 serialVersionUID를 확인한 후 객체 복원
            // - 복원 과정에서 기본 생성자 호출 X
            // - serialVersionUID가 일치하지 않으면 InvalidClassException 발생
            FileDto dto = (FileDto) ois.readObject();
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[파라미터 바인딩 어노테이션 정리]]></title>
            <link>https://velog.io/@park_rootseok/%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0-%EB%B0%94%EC%9D%B8%EB%94%A9-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@park_rootseok/%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0-%EB%B0%94%EC%9D%B8%EB%94%A9-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 12 Aug 2025 12:53:20 GMT</pubDate>
            <description><![CDATA[<h2 id="requestbody란">@RequestBody란?</h2>
<p><code>@RequestBody</code>는 HTTP 요청 본문(Body)의 <strong>JSON 등 데이터를 자바 객체로 변환한 뒤, 해당 객체를 Controller 메서드의 파라미터로 주입</strong>하는 어노테이션입니다. 동작 과정은 아래와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/4cc7402c-5425-40f2-92bc-236fd8b91a4a/image.png" alt=""></p>
<h2 id="requestparam">@RequestParam</h2>
<p><code>@RequestParam</code>은 HTTP 요청의 <strong>Query String 또는 폼 데이터 값을 추출해 바인딩한 뒤, 변환된 값을 Controller 메서드의 파라미터로 주입</strong>하는 어노테이션입니다. 동작 과정은 아래와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/571a5e80-0c1e-4877-8693-2f07c748aa52/image.png" alt=""></p>
<h2 id="modelattribute">@ModelAttribute</h2>
<p><code>@ModelAttribute</code>는 HTTP 요청의 <strong>Query String 또는 폼 데이터 값을 자바 객체의 필드에 바인딩하고, 변환된 객체를 Controller 메서드 파라미터로 주입</strong>합니다. 또한, 해당 객체를 <strong>Model에 자동 등록하여 뷰 렌더링 시에도 사용</strong>할 수 있게 합니다. 동작 과정은 아래와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/36fe9599-dc60-4603-ae4c-f65bb3597cb1/image.png" alt=""></p>
<h2 id="정리">정리</h2>
<table>
<thead>
<tr>
<th>어노테이션</th>
<th>데이터 출처</th>
<th>바인딩 대상</th>
<th>결과</th>
<th>주요 사용 사례</th>
</tr>
</thead>
<tbody><tr>
<td><code>@RequestBody</code></td>
<td>HTTP Body (JSON, XML 등)</td>
<td>요청 본문 전체</td>
<td>자바 객체</td>
<td>REST API JSON 요청 처리</td>
</tr>
<tr>
<td><code>@RequestParam</code></td>
<td>Query String, Form Data</td>
<td>단일 요청 파라미터</td>
<td>단일 값, 배열, 컬렉션</td>
<td>검색어, 페이지 번호</td>
</tr>
<tr>
<td><code>@ModelAttribute</code></td>
<td>Query String, Form Data</td>
<td>객체(POJO) 필드 단위</td>
<td>자바 객체</td>
<td>폼 제출, 검색 조건 객체</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[격리 수준]]></title>
            <link>https://velog.io/@park_rootseok/%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80</link>
            <guid>https://velog.io/@park_rootseok/%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80</guid>
            <pubDate>Sun, 10 Aug 2025 11:56:45 GMT</pubDate>
            <description><![CDATA[<h2 id="격리-수준이란">격리 수준이란?</h2>
<p>격리 수준이란 동시에 실행되는 트랜잭션이 서로에게 얼마나 영향을 미치지 않도록 할지를 결정하는 정도를 말합니다. 즉, <strong>트랜잭션 간의 동시성과 정합성의 균형을 조절하는 설정</strong>입니다.</p>
<h2 id="왜-필요할까요">왜, 필요할까요?</h2>
<p>데이터베이스는 기본적으로 <strong>여러 사용자가 동시에 접근</strong>할 수 있습니다. 만약, <strong>격리 수준이 낮으면 성능은 좋지만</strong> 예상치 못한 결과가 나올 수 있습니다. 또한, <strong>격리 수준이 너무 높아도 Lock 경합으로 인해 성능이 저하</strong>될 수 있습니다. 즉, 트랜잭션을 사용하는 목적에 따라 정합성과 성능의 균형을 맞추기 위해 필요합니다.</p>
<h2 id="종류">종류</h2>
<p>격리 수준에는 4가지 종류가 존재합니다.</p>
<h3 id="read-uncommitted">READ UNCOMMITTED</h3>
<p><code>Read Uncommitted</code>는 커밋되지 않은 데이터까지 읽을 수 있는 수준으로 정합성 낮으나 성능은 제일 높습니다.</p>
<h3 id="read-commited">READ COMMITED</h3>
<p><code>Read Committed</code>는 커밋된 데이터까지 읽을 수 있는 수준으로 대부분 DB에서 기본 격리 수준으로 사용합니다. 특정 레코드를 읽는 동안 다른 트랜잭션이 해당 레코드를 수정하지 못하도록 공유락을 설정하여 정합성을 유지합니다.</p>
<h3 id="repeatable-read">REPEATABLE READ</h3>
<p><code>Repeatable Read</code>는 트랜잭션 내에서 조회한 레코드에 대한여 동일한 결과값이 나오는 것을 보장하는 수준으로 MySQL의 기본 격리 수준입니다. 처음으로 레코드를 조회할 때 스냅샷을 생성하여 정합성을 유지합니다.</p>
<blockquote>
<h4 id="왜-mysql은-repeatable-read를-기본으로-선택했을까요">왜, MySQL은 REPEATABLE READ를 기본으로 선택했을까요?</h4>
<p>MySQL은 데이터의 무결성을 우선시하도록 설계된 DB이며, 이유는 다음과 같습니다.</p>
</blockquote>
<ul>
<li>MySQL의 InnoDB는 MVCC를 사용<ul>
<li>MVCC는 스냅샷을 이용해 트랜잭션 시작 지점의 데이터를 계속 읽을 수 있음</li>
</ul>
</li>
<li>Gap Lock과 Next-Key Lock을 사용해 Phantom Read 방지 가능<ul>
<li>InnoDB에서는 Repeatable Read 수준에서 거의 Serializable 수준의 정합성 확보</li>
</ul>
</li>
</ul>
<h3 id="serializable">SERIALIZABLE</h3>
<p><code>Serializable</code>은 모든 트랜잭션이 순차적으로 처리하도록 보장하는 수준으로 가장 정합성은 높으나 성능은 제일 낮습니다. 범위락을 걸어서 다른 트랜잭션이 범위 내에 읽기/쓰기를 불가하도록 하여 정합성을 유지합니다.</p>
<h2 id="이상-현상">이상 현상</h2>
<p>격리 수준이 낮을수록 데이터 정합성 또한 낮습니다. 이로 인해, 3가지 이상 현상이 발생할 수 있습니다.</p>
<h3 id="dirty-read">Dirty Read</h3>
<p><code>Dirty Read</code>는 <strong>커밋되지 않은 데이터를 읽을 수 있는 현상</strong>으로 <code>Read Uncommitted</code> 수준에서 발생하는 이상 현상입니다.</p>
<h3 id="non-repeatble-read">Non-Repeatble Read</h3>
<p><code>Non-Repeatble Read</code>는 <strong>동일한 트랜잭션 내에서 같은 행을 두 번 읽었을 때 결과가 다를 수 있는 현상</strong>으로 <code>Read Committed</code> 수준에서 발생하는 이상 현상입니다.</p>
<h3 id="phantom-read">Phantom Read</h3>
<p><code>Phantom Read</code>는 <strong>특정 범위에 대한 조회 쿼리를 수행한 결과가 가지는 행의 갯수가 다를 수 있는 현상</strong>으로 <code>Repeatable Read</code>에서 발생하는 이상 현상입니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[배열과 컬렉션을 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%EB%B0%B0%EC%97%B4%EA%B3%BC-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%84-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/%EB%B0%B0%EC%97%B4%EA%B3%BC-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%84-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Fri, 08 Aug 2025 08:42:51 GMT</pubDate>
            <description><![CDATA[<h2 id="배열">배열</h2>
<p>Kotlin과 Java의 배열은 구조적으로는 유사하지만, 문법적으로 배열을 순회하는 방식에서 아래와 같이 큰 차이가 존재합니다</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/4770f94e-2d1e-46da-ab12-ef428bdb1310/image.png" alt=""></p>
<h2 id="collection">Collection</h2>
<h3 id="가변과-불변을-구분하자">가변과 불변을 구분하자</h3>
<p>Kotlin에서는 Collection을 생성할 때 아래와 같이 불변인지, 가변인지를 명확히 결정해야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/6cc11596-6b46-42fd-a011-959cfe0db8ac/image.png" alt=""></p>
<p>반면, Java는 기본적으로 <code>ArrayList</code>, <code>HashMap</code> 등 가변 Collection을 사용합니다. 불변 Collection을 만들려면 명시적으로 <code>Collections.unmodifiableList()</code> 또는 <code>List.of()</code> 등의 메서드를 사용해야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/7dad6a6f-b883-4484-a9f5-8c89dc2fdeb3/image.png" alt=""></p>
<h3 id="kotlin의-collection은-기본-구현체가-존재">Kotlin의 Collection은 기본 구현체가 존재</h3>
<p>Java와 달리 Kotlin에서는 List, Set, Map 등의 Collection에 대한 기본 구현체가 존재하며, 아래와 같습니다.</p>
<h4 id="불변">불변</h4>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/810b16df-21d5-43d2-84f2-d0eddd6ef0c3/image.png" alt=""></p>
<h4 id="가변">가변</h4>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/00af8dc1-0606-40fd-b124-937ef71b972b/image.png" alt=""></p>
<h3 id="collection-사용-방법은-무엇이-다를까">Collection 사용 방법은 무엇이 다를까?</h3>
<h4 id="list">List</h4>
<p>Kotlin에서는 아래와 같이 <code>List</code>를 을 사용할 수 있습니다.
<img src="https://velog.velcdn.com/images/park_rootseok/post/53e6a158-a584-465b-879b-86aa6d40b2e5/image.png" alt=""></p>
<h4 id="set">Set</h4>
<p>Kotlin에서는 아래와 같이 <code>Set</code>을 사용할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/2d4ce20f-d6cc-49fd-8ad0-3d29f52ca452/image.png" alt=""></p>
<h4 id="map">Map</h4>
<p>Kotlin에서는 아래와 같이 <code>Map</code>을 사용할 수 있습니다.
<img src="https://velog.velcdn.com/images/park_rootseok/post/4f5364ab-797e-4a42-9535-cb96499405c1/image.png" alt=""></p>
<h2 id="null-가능성">Null 가능성</h2>
<h3 id="-위치에-따른-null-가능성">? 위치에 따른 Null 가능성</h3>
<p><code>?</code> 위치에 따라 아래와 같이 Null 가능성을 구분할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/85f00b98-5f0d-4ac0-9f77-22c4deefbdf6/image.png" alt=""></p>
<h3 id="java와-kotlin이-혼용된-코드에서-collection-사용시-주의할-점">Java와 Kotlin이 혼용된 코드에서 Collection 사용시 주의할 점</h3>
<h4 id="kotlin으로-작성된-collection을-java에서-사용할-때">Kotlin으로 작성된 Collection을 Java에서 사용할 때</h4>
<p>Java에서 Kotlin의 Collection을 사용할 경우 아래와 같은 2가지 경우를 조심해야 합니다.</p>
<ul>
<li><p>Java는 Collection에 대한 가변(읽기 전용)과 불변(변경 가능)을 구분하지 않음</p>
<ul>
<li><code>Immutable Collection</code>에 대한 수정 작업을 수행할 수 있고, 이로 인해 Kotlin에서 오동작 발생 가능</li>
</ul>
</li>
<li><p>Java는 <code>nullable</code>과 <code>non-nullable</code> 타입을 구분하지 않음</p>
<ul>
<li><code>non-nullable Collection</code>에 null을 리스트에 추가할 수 있고, 이로 인해 Kotlin에서 오동작 발생 가능</li>
</ul>
</li>
</ul>
<p>이러한 문제를 예방하기 위해, Kotlin에 정의한 Collection이 Java에서 호출될 수 있다면 작업 이후 방어 로직을 작성하여 처리하거나 Java에도 존재하는  <code>Collections.unmodifableXXX()</code>를 활용하여 변경이 불가능하도록 해야합니다.</p>
<h4 id="java로-작성된-collection을-kotlin에서-사용할-때">Java로 작성된 Collection을 Kotlin에서 사용할 때</h4>
<p>Kotlin에서 Java의 Collection을 사용할 경우 플랫폼 타입을 조심해야 합니다.</p>
<blockquote>
<h4 id="플랫폼-타입이란">플랫폼 타입이란?</h4>
<p>플랫폼 타입은 다른 프로그래밍 언어에서 잔달되어 nullable 여부를 알 수없는 타입을 말합니다.</p>
</blockquote>
<p>Kotlin에서는 Java에서 가져온 Collection이 <code>List&lt;Int?&gt;, List&lt;Int?&gt;?, List&lt;Int&gt;?</code> 인지 알 수 없습니다. 이 경우는 Java 코드를 보며 맥락을 확인하고, 가져오는 지점을 wrapping해서 영향 범위를 최소화해야 합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[다양한 클래스를 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%EB%8B%A4%EC%96%91%ED%95%9C-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/%EB%8B%A4%EC%96%91%ED%95%9C-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Thu, 07 Aug 2025 09:05:28 GMT</pubDate>
            <description><![CDATA[<h2 id="data-class">Data Class</h2>
<p>Kotlin에서는 <code>data</code>라는 지시어를 Class 앞에 명시하여 DTO Class를 매우 간결하게 정의할 수 있습니다. </p>
<p>아래는 Java로 작성된 DTO Class입니다. Getter, Constructor, Equlas 등으로 인해 코드가 장황하고, 이를 보완하기 위해선 Lombok 어노테이션을 선언하는 추가적인 조치가 필요합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/57b84ccc-239c-470c-af9d-a055cb14d705/image.png" alt=""></p>
<p>하지만, Kotlin에서는 <code>data</code> 키워드를 명시하면 eqauls, hashCode, toString 등을 자동으로 만들어주기 때문에 아래와 같이 간결하게 작성할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/2247a32b-6ac8-47c0-af7e-9fd24334d8d5/image.png" alt=""></p>
<p>또한, Kotlin은 아래와 같이 Named Argument를 지원하기 때문에 Builder 패턴까지 활용하는 것 같은 효과를 받을 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/df069195-429f-4c32-961d-139c83f1a454/image.png" alt=""></p>
<h2 id="enum-class">Enum Class</h2>
<p>Kotlin에서의 Enum Class는 코드 작성에 있어서는 Java와 별 다른 차이가 없습니다.</p>
<p>하지만, Enum을 활용한 코드에 대한 가독성 측면에서는 차이가 존재합니다. Kotlin에서는 아래와 같이 <code>when</code>을 사용하면 <strong>컴파일러가 Enum Class에 대한 모든 타입을 알고 있기 때문에, 다른 타입에 대한 예외 처리 로직(else 문) 작성이 불필요</strong>합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/26332283-25a5-4bf3-a8eb-b0e33b00f13c/image.png" alt=""></p>
<p>또한, Kotlin에서는 아래와 같이 Enum Class에 열거 상수 이름을 추가한 후 반영하지 않은 경우 warning을 주지만 Java는 그렇지 않습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/2e910014-8676-4fca-816e-153dcfe264ae/image.png" alt=""></p>
<h2 id="sealed-class">Sealed Class</h2>
<p><code>Sealed Class</code>는 상속을 위한 추상 클래스를 정의했을 때, 이를 외부에서도 상속 받아 활용하는 것을 막기 위해 만들어진 Class입니다. 즉, 외부에서 추상 클래스를 상속하는 것을 막고자 <strong>&#39;우리가 작성한 클래스만 하위 클래스가 될 수 있도록 봉인한 것&#39;</strong>입니다. 이에 따른 <code>Sealed Class</code>의 특징은 다음과 같습니다.</p>
<ul>
<li>컴파일 타임에 하위 클래스의 타입을 모두 기억하여 런타임에서 클래스 타입이 추가 불가</li>
<li>하위 클래스는 같은 패키지에 존재해야 함</li>
</ul>
<p>아래는 Sealed Class 작성 예시입니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/40c065dd-ee37-4eb8-b4b0-d4eb84dc7868/image.png" alt=""></p>
<p>또한, Sealed Class는 컴파일 타임 때 하위 클래스 타입을 모두 기억하고 있다는 특징이 있기 때문에 아래와 같이 <code>when</code>과 같이 활용활 때 매우 유용합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/ac31a73c-7c1e-46e8-a828-400d6fc8de0d/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[중첩 클래스를 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%EC%A4%91%EC%B2%A9-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/%EC%A4%91%EC%B2%A9-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Wed, 06 Aug 2025 08:37:47 GMT</pubDate>
            <description><![CDATA[<h2 id="중첩-클래스의-종류">중첩 클래스의 종류</h2>
<p>Java에서의 중첩 클래스는 아래와 같이 여러 종류로 나뉩니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/c169ee76-0001-4ec9-9fac-7bf8d40a0644/image.png" alt=""></p>
<p>일반적으로 중첩 클래스를 지칭할 땐 static을 사용하는 증첩 클래스와, Inner Class를 지칭하고, 아래와 같은 특징을 가지고 있습니다.</p>
<ul>
<li>static을 사용하는 중첩 클래스<ul>
<li>외부 클래스 직접 참조 불가</li>
</ul>
</li>
<li>static을 사용하지 않는 중첩 클래스<ul>
<li>Inner Class : 외부 클래스 직접 참조 가능</li>
</ul>
</li>
</ul>
<p>이를 Java 코드로 살펴보면 아래와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/ea068d02-0c63-4d47-b780-3d568aa78bf7/image.png" alt=""></p>
<blockquote>
<h4 id="inner-class-사용을-지양하자">Inner Class 사용을 지양하자</h4>
<p>Effective Java에 따르면 Inner Class에 대하여 아래와 같이 설명하고 있으며, 중첩 클래스를 사용할 경우 <code>static class</code>를 사용하는 방법을 권장합니다.</p>
</blockquote>
<ul>
<li>숨겨진 외부 클래스 정보를 가지고 있어, 참조 해지가 불가한 경우 메모리 누수 발생</li>
<li>직렬화 형태가 명확하게 정의되지 않아 직렬화에 있어 제한됨</li>
</ul>
<h2 id="kotlin에서의-중첩-클래스와-내부-클래스">Kotlin에서의 중첩 클래스와 내부 클래스</h2>
<p>Kotlin에서의 중첩 클래스는 아래와 같이 기본적으로 외부 클래스에 대한 직접 참조를 하지 않습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/d7cb3fda-c601-4cfe-9656-690dc808a5e2/image.png" alt=""></p>
<p>만약, 외부 클래스에 대한 직접 참조가 필요할 경우 <code>inner</code> 키워드를 활용하여 다음과 같이 작성하면 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/35fcc0d6-40dd-4f50-acb6-9cb83e876899/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Object 키워드를 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/Object-%ED%82%A4%EC%9B%8C%EB%93%9C</link>
            <guid>https://velog.io/@park_rootseok/Object-%ED%82%A4%EC%9B%8C%EB%93%9C</guid>
            <pubDate>Tue, 05 Aug 2025 11:03:16 GMT</pubDate>
            <description><![CDATA[<h2 id="static-함수와-변수">Static 함수와 변수</h2>
<h3 id="companion-object">Companion Object</h3>
<p>Kotlin에서는 Java와 달리 <code>static</code> 키워드가 존재하지 않고, 아래와 같이 <code>companion object</code> 키워드를 사용합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/41d80345-1e3d-4a2a-9ef6-1417b689a7ed/image.png" alt=""></p>
<p>또한, <code>companion object</code>는 하나의 객체로 간주되기 때문에 Java의 <code>static</code>과 달리 아래와 같이 이름을 명시할 수 있으며 interface를 구현할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/1e5c9764-e519-4b16-81fc-89d3b2a8c202/image.png" alt=""></p>
<blockquote>
<h4 id="const"><code>const</code></h4>
<p><code>const</code> 키워드는 컴파일 단계에서 변수에 값을 할당하도록 하는 지시어입니다. <code>const</code>를 명시하지 않은 경우 컴파일 단계에서는 기본값을 할당한 후, 런타임 단계에서 값을 할당니다.</p>
</blockquote>
<h3 id="jvmstatic">@JvmStatic</h3>
<p>Java에서 Kolin에 작성된 <code>companion object</code>를 Java의 <code>static</code>처럼 사용하기 위해선 아래와 같이 <code>@JvmStatic</code>을 명시해야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/56238f73-462c-4df0-ba73-74de5b7248cb/image.png" alt=""></p>
<h2 id="singleton">Singleton</h2>
<p>Kotlin에서는 <code>object</code> 키워드를 사용하여 아래와 같이 간단하게 Singleton 클래스를 생성할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/a6406628-5d5b-4880-9936-4bbf7731b9c6/image.png" alt=""></p>
<h2 id="익명-class">익명 Class</h2>
<p>Kotlin에서 익명 Class를 사용할 경우 <code>new Type() { ... }</code>을 통해 Java와 달리 <code>object : Type { ... }</code> 을 통해 익명 Class를 사용할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/0894e14d-d187-4cc7-aa8d-6c06f1bb51af/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[접근 제어를 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%EC%A0%91%EA%B7%BC-%EC%A0%9C%EC%96%B4%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/%EC%A0%91%EA%B7%BC-%EC%A0%9C%EC%96%B4%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Mon, 04 Aug 2025 09:03:57 GMT</pubDate>
            <description><![CDATA[<h2 id="가시성-제어">가시성 제어</h2>
<p>Kotlin과 Java의 접근 제한자는 아래와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/c1554d93-317d-46cf-99df-1dc11fc206d6/image.png" alt=""></p>
<p>Kotlin에서는 <code>default</code> 키워드가 사라지고, <code>internal</code>이 추가 되었습니다. 이는 Kotlin에서는 패키지를 namespace를 관하기 용도로만 사용하고 가시성 제어로는 사용하지 않기 때문입니다. 또한, Java의 경우 <code>defaul</code>를 기본 접근 제한자로 사용하지만, Kotlin은 <code>public</code>을 기본 접근 제한자로 사용하고 있습니다.</p>
<h2 id="파일의-접근-제어">파일의 접근 제어</h2>
<p>Kotlin에서는 파일 내에 아래와 같이 변수, 함수, 클래스 등을 즉시 정의할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/88e205a9-a6b3-4efb-b20a-4be1d7caaea5/image.png" alt=""></p>
<p>하지만, 파일 최상단에 정의한 변수, 함수, 클래스 등에는 아래와 같이 <code>protected</code>는 사용할 수 없습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/cf4835bf-451c-48e2-afcc-8e22ea224a51/image.png" alt=""></p>
<h2 id="다양한-구성요소의-접근-제어">다양한 구성요소의 접근 제어</h2>
<h3 id="constructor">Constructor</h3>
<p>Constructor에 접근 제한자를 사용하기 위해선 아래와 같이 <code>constructor</code> 키워드를 반드시 명시해야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/43c0bef1-6550-4f27-8194-c655202c2658/image.png" alt=""></p>
<h3 id="property">Property</h3>
<p>Property에 선언된 접근 제한자는 Getter, Setter에도 적용됩니다. 두 함수에 동일한 접근 제한자를 적용하는 경우 아래와 같이 선언하면 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/dea518a3-0f39-4941-b662-bf320853642d/image.png" alt=""></p>
<p>하지만, 두 함수의 가시성을 별도로 제어하기 위해선 아래와 같은 방법으로 접근 제한자를 선언해야 합니다.
<img src="https://velog.velcdn.com/images/park_rootseok/post/d33c0481-057a-4975-8d8a-11a87ac9c044/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[상속을 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%EC%83%81%EC%86%8D%EC%9D%84-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/%EC%83%81%EC%86%8D%EC%9D%84-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Fri, 01 Aug 2025 12:19:39 GMT</pubDate>
            <description><![CDATA[<h2 id="abstract-class">Abstract Class</h2>
<p>Java로 작성한 Abstract Class(Animal)와 이를 상속하는 하위 Class(Cat, Penguin)를 Kotlin으로 변환하는 과정을 통해, Java와 다른점은 무엇이 있을지 살펴보겠습니다.</p>
<p>사용할 Java 코드는 다음과 같습니다.
<img src="https://velog.velcdn.com/images/park_rootseok/post/42674525-6b10-4df0-9d41-92e9a743f6e0/image.png" alt=""></p>
<h3 id="extends가-아닌--사용하라">extends가 아닌 <code>:</code> 사용하라</h3>
<p>Java에서는 상속을 위해 <code>extends</code> 키워드를 사용합니다. 하지만, Kotlin은 아래와 같이 <code>:</code>을 사용하며, 반드시 상위 Class에 대한 생성자를 호출해야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/671c721a-4247-4499-b153-5dfa71bec2c0/image.png" alt=""></p>
<h3 id="override-지시어를-반드시-사용하자">override 지시어를 반드시 사용하자</h3>
<p>Java에서는 부모 Class가 가진 Abstract 함수를 재정의할 때, <code>@Override</code> 어노테이션을 사용하며 반드시 명시할 필요가 없습니다. 하지만, Kotlin에서는 <code>override</code>라는 키워드가 별도로 존재하며 반드시 명시해야합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/36ad4d48-9366-4260-81d1-aecb8b664654/image.png" alt=""></p>
<h3 id="property를-override-하기-위해선-open을-명시하자">Property를 override 하기 위해선 open을 명시하자</h3>
<p>Kotlin에서는 상위 Class에 자동으로 생성된 Getter를 Override하여 Custom Getter를 정의하기 위해선 부모 Class의 Property에 <code>open</code> 키워드를 반드시 명시해야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/4d2e9419-17f2-4f74-a0c6-5654536c8dad/image.png" alt=""></p>
<h2 id="interface">Interface</h2>
<p>Java로 작성한 Interface(Swimable, Flyable)을 Kotlin으로 변환하는 과정을 통해, Java와 다른점은 무엇이 있을지 살펴보겠습니다.</p>
<h3 id="default-키워드-생략-가능">Default 키워드 생략 가능</h3>
<p>Java에서는 Interface에서 함수를 정의할 경우 <code>default</code> 키워드를 명시하지만, Kotlin에서는 명시하지 않고도 default 함수를 정의할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/176d258b-61bc-4d02-9635-4569728c9078/image.png" alt=""></p>
<h3 id="implements-키워드가-아닌-를-사용하자">implements 키워드가 아닌 :를 사용하자</h3>
<p>Java에서는 Interface를 사용할 때 Implements를 사용하지만, Kotlin에서는 <code>:</code>를 사용합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/93f683a3-1ab1-40ad-9980-9b013f861f82/image.png" alt=""></p>
<h3 id="상위-inteface의-함수를-호출할-때-를-사용하자">상위 Inteface의 함수를 호출할 때 &lt;&gt;를 사용하자</h3>
<p>Java에서는 상위 Interface의 함수를 호출할 때 <code>Interface.super.method()</code>를 사용지만, Kotlin에서는 <code>super&lt;Interface&gt;.method()</code>를 사용합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/f83bf3b2-d2de-41bc-9124-14a951c871dc/image.png" alt=""></p>
<h3 id="property-정의가-가능">Property 정의가 가능</h3>
<p>Kotlin에서는 Interface에 Property 또한 미리 정의할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/64bda161-c88b-4498-9c71-f6a0b412f344/image.png" alt=""></p>
<h2 id="상속할-때-주의할-점">상속할 때 주의할 점</h2>
<h3 id="일반적인-class를-상속해야-할-경우-open-키워드를-명시하자">일반적인 Class를 상속해야 할 경우 open 키워드를 명시하자</h3>
<p>Kotlin은 Abstract, Interface가 아닌 Class를 상속해야 할 경우, 반드시 해당 Class에 open 키워드를 명시해야 가능합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/094d55a0-040e-4437-9849-6917c6d61d88/image.png" alt=""></p>
<h3 id="상위-class의-constructor-또는-init에서-사용하는-property에-open-사용-금지">상위 Class의 Constructor 또는 Init에서 사용하는 Property에 open 사용 금지</h3>
<p>Kotlin에서 상위 Class를 설계할 때 생성자 또는 초기화 블록에 사용하는 Property에는 open을 사용하는 것을 조심해야 합니다. 그 이유는 아래 예시를 통해 살펴보겠습니다.</p>
<p>아래와 같이 2개의 Class(Base, Derived)가 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/a5db3f52-f8f0-4568-970f-e5d8297d4453/image.png" alt=""></p>
<p>Derived Class를 생성할 경우 다음과 같은 결과를 볼 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/7c5dee91-5a9d-4953-9012-86742bdf61f0/image.png" alt=""></p>
<p>왜, 100이나 300이 아닌 0이 출력되었을까요? 그 이유는 <strong>상위 Class인 Base의 init 블록에서 접근하는 number는 하위 Class의 number</strong>이기 때문입니다. 아래와 같이 상위 Class의 생성자가 먼저 호출이 되고, 그 시점엔 아직 하위 Class인 Derived의 생성자가 호출되지 않아 number가 초기값을 가지고 있는 상태입니다. 즉, 인자로 전달받은 300을 아직 하위 Class가 가지고 있는 number에 주입하기 전이기 때문에 초기값인 0을 출력하게 됩니다.</p>
<p><img src="blob:https://velog.io/94e5cad1-f053-4734-89c1-b333381b9d86" alt="업로드중.."></p>
<p>이러한 상황이 발생할 수 있기 때문에, 상위 Class에서 Constructor 또는 Init 블록에서 Property를 사용할 경우 <code>open</code> 키워드를 명시하면 안됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[클래스를 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Thu, 31 Jul 2025 13:01:38 GMT</pubDate>
            <description><![CDATA[<h2 id="class와-property">Class와 Property</h2>
<h3 id="class">Class</h3>
<p>Java의 경우 일반적으로 아래와 같은 형태의 Class 구조를 가집니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/b7e95573-d6d5-447d-a43a-b901f968d498/image.png" alt=""></p>
<p>위 코드를 Kotlin으로 작성할 시 아래와 같이 Constructor, Getter, Setter 추가로 정의할 필요가 없습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/19193e8a-8c52-48ed-b251-b5cb38f89d8e/image.png" alt=""></p>
<h3 id="property">Property</h3>
<p>Kotlin에서는 아래와 같은 Constructor의 인자들을 Property라고 하는데, 이는 Field와 Getter, Setter를 모두를 포함하는 요소라는 의미를 지닙니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/f04d899a-356d-4113-a39f-bf9c5424daa7/image.png" alt=""></p>
<p>즉, Kotlin에서는 Field만 정의해주어도 Getter와 Setter를 자동으로 생성해주기 때문에, Java처럼 별도의 메소드를 생성하지 않아도 아래와 같이 작성할 경우 Getter, Setter 메소드와 동일한 동작을 수행하게 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/4a9be8c5-624f-4d0f-a388-2768c314a0c9/image.png" alt=""></p>
<h2 id="init과-constructor">Init과 Constructor</h2>
<h3 id="init">Init</h3>
<p>Java의 경우 일반적으로 아래와 같이 Constructor에서 유효성 검증을 수행합니다. 반면, Kotlin에서는 Constructor 호출 시 한 번만 수행되는 <code>init</code> 블록을 활용하여 Property에 대한 유효성 검증을 수행합니다. </p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/4504b597-fb3b-4367-9399-d2f4d9d0f76c/image.png" alt=""></p>
<p>이러한 동작을 Kotlin에서는 아래와 같이 작성하여 동일하게 구현할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/a3cefe42-41df-4451-aa00-4dbcc52a1877/image.png" alt=""></p>
<h3 id="constructor">Constructor</h3>
<p>Java의 경우 Constructor의 인자 일부에 고정값을 주입하기 위해 <code>Constructor Overloading</code>를 활용합니다. 반면,  Kotlin에서는 아래와 같이 <code>Secondary Custructor</code>를 활용하여 동일한 기능을 수행합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/5f2f5b93-e8c1-4a8c-8624-d2c532e7cdf7/image.png" alt=""></p>
<p>추가로, Kotlin에서는 아래와 같이 <code>Default Value</code>를 활용하여 동일한 동작을 수행할 수 있으며, 여러 개의 <code>Constructor</code>를 정의하기 보다 아래와 같은 방법을 더 권장하고 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/7a1c6db3-d145-40a6-b643-6c64d2cf1bd2/image.png" alt=""></p>
<h2 id="custom-getter와-setter">Custom Getter와 Setter</h2>
<p>Kotlin에서는 커스텀 Getter와 Setter는 함수가 아닌 Class의 Property로 표현할 때 사용하는 방법입니다. </p>
<p>예를 들어, Java에서는 <code>Person</code>이라는 Class에서 <code>age</code>를 활용하여 성인 여부를 확인하기 위해선 아래와 같은 함수를 정의해야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/6e6ffb44-d1c0-4744-9f8f-3fa7d6d471fc/image.png" alt=""></p>
<p>하지만, Kotlin에서는 아래와 같이 <code>get()</code>을 활용하여 함수가 아닌 Property처럼 구현할 수 있습니다.
<img src="https://velog.velcdn.com/images/park_rootseok/post/580450c8-0983-48cf-b9e3-48f42dbaa830/image.png" alt=""></p>
<p>Custom Setter는 아래와 같이 활용할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/f989f542-ac3f-4173-8f57-f2b3ec34cfcf/image.png" alt=""></p>
<h2 id="backing-field">Backing Field</h2>
<p>Kotlin에는 자기 자신을 가리키는 보이지 않는 Field인 <code>Backing Field</code>라는 개념이 존재합니다.<code>field</code>라는 예약어를 통해 사용할 수 있고, Custom Getter/Setter를 정의할 때 무한루프를 방지하기 위해 사용합니다.</p>
<p>아래는 <code>name</code>을 조회할 때 대문자로 출력하도록 Custom Getter를 정의한 코드입니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/482dab8e-d7e8-4d7b-8376-ab86e9092208/image.png" alt=""></p>
<p>Kotlin에서는 <code>변수명.프로퍼티명</code>, <code>프로퍼티명</code>을 호출한 경우 Getter 호출해 값을 얻어옵니다. 즉, 아래와 같이 <code>name</code>을 호출하면 다시 또 Getter를 호출하게 되면서 무한루프가 발생합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/1e06d8bc-f6dd-49e3-bf38-e1424bc0efd2/image.png" alt=""></p>
<p>이러한 상황에서 아래와 같이 자기 자신을 가리키는 <code>Backing Field</code>를 활용하여 무한루프를 방지하고 원하는 동작을 수행할 수 있습니다.
<img src="https://velog.velcdn.com/images/park_rootseok/post/b453bdd7-dbcb-4c85-b3f2-220214ddc668/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[함수를 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%ED%95%A8%EC%88%98%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/%ED%95%A8%EC%88%98%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Wed, 30 Jul 2025 09:53:08 GMT</pubDate>
            <description><![CDATA[<h2 id="함수-선언-문법">함수 선언 문법</h2>
<p>Kotlin에서는 함수가 하나의 결과값을 반환하는 경우, 아래 예시와 같이 <code>블록({ .. })</code>를 제거하고 <code>=</code>를 대신 사용할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/9f3e9bec-0564-4cb3-b164-7c169bd7dfc9/image.png" alt=""></p>
<p>위와 같이 형태의 함수는 반환값의 타입이 명확한 경우 반환 타입을 생략할 수 있으며 if-else문의 중괄호도 생략 가능합니다. 예시는 아래와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/54d536ef-5d93-4d1d-b562-814e7fe1c802/image.png" alt=""></p>
<h2 id="default-parameter">Default Parameter</h2>
<p>Kolit에서는 Parameter에 기본값을 설정할 수 있습니다. 문자열을 반복 출력하는 함수를 예시로 이를 어떻게 활용할 수 있는지 살펴보겠습니다.</p>
<p>우선, 아래와 같이 메시지와 반복 횟수 그리고 개행 추가 여부를 받는 문자열 반복 함수가 존재합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/ef123638-c121-4fee-8d63-a55329c5a792/image.png" alt=""></p>
<p>이 함수를 호출할 때 높은 비율로 반복 횟수를 3, 개행 추가 여부를 true로 사용하는 상황이라면 매번 이를 입력해주는 것은 불편할 수 있습니다. Java에서는 이를 Overloading을 통해 아래와 같이 해결할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/0f5a5b37-db72-4e43-b90a-38c52b669e4c/image.png" alt=""></p>
<p>하지만, 3개의 함수를 만드는 것은 조금 비효율적이라 생각이 들 수 있습니다. Kotlin은 아래와 같이 <strong>기본값을 활용하여 Parameter가 전달되지 않을 경우 기본적으로 사용할 값을 지정</strong>할 수 있습니다. 이를 활용하여, 1개의 함수만으로 동일한 기능을 더욱 간단하게 구현할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/0fa95f32-dca0-4b34-8994-fe8c6da9b569/image.png" alt=""></p>
<p>그리고 활용 예시를 보여주기 위해 기본값을 사용했지만, Kotlin도 Java와 동일하게 Overloading 기능을 지원합니다.</p>
<h2 id="named-argument">Named Argument</h2>
<p>Kotlin은 <code>Named Argument</code>를 지원하기에 Parameter를 명시하여 값을 지정할 수 있습니다. 이 기능은 Parameter를 명시하여 값을 주입하는 방식이므로 <strong>Builder를 직접 만들지 않고도 Builder의 장점</strong>을 가질 수 있습니다. 단, Java 코드로 작성된 함수를 호출할 경우 기능을 활용할 수 없습니다.</p>
<p>활용 예시는 아래와 같습니다.
<img src="https://velog.velcdn.com/images/park_rootseok/post/c70b0d00-033a-4278-bb7e-a084c0f9e414/image.png" alt=""></p>
<h2 id="가변-인자">가변 인자</h2>
<p>Kotlin에서 Java와 달리 가변 인자를 사용하기 위해선 <code>vararg</code> 키워드를 인자명 옆에 명시하고, 배열을 바로 인자로 전달할 수 없고 반드시 <code>스프레드 연산자(*)</code>를 명시해야 합니다. 예시는 아래와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/590bea17-212d-4d66-878f-dd629cb5d081/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[반복문과 예외를 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%EB%B0%98%EB%B3%B5%EB%AC%B8%EA%B3%BC-%EC%98%88%EC%99%B8%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/%EB%B0%98%EB%B3%B5%EB%AC%B8%EA%B3%BC-%EC%98%88%EC%99%B8%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Mon, 28 Jul 2025 12:30:56 GMT</pubDate>
            <description><![CDATA[<h2 id="반복문">반복문</h2>
<h3 id="for">For</h3>
<p>Kolin에서 <code>for</code>문을 사용하는 방법은 아래와 같습니다. 증감 연산자를 활용하여 인덱스를 조작하는 Java와 달리 <code>in, .., downTo, step</code> 등의 연산자를 활용합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/eb7d9e9f-8225-43c6-b611-20b0aedf957a/image.png" alt=""></p>
<h3 id="for-each">For-Each</h3>
<p>Kotlin에서 <code>for-each</code>문을 사용하는 방법은 아래와 같습니다. <code>:</code>를 사용하는 Java와 달리 <code>in</code> 연산자를 활용합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/b39eada2-46c7-4996-a134-a7b2b7232dce/image.png" alt=""></p>
<h3 id="while">While</h3>
<p>Kotlin과 Java의 <code>While</code>문 사용 방법은 동일합니다.</p>
<h2 id="예외">예외</h2>
<h3 id="try-catch-finally">Try-Catch-Finally</h3>
<p>Kotlin과 Java의 <code>try-catch-finally</code>문 사용 방법은 동일합니다.</p>
<h3 id="checked-exception--unchecked-exception">Checked Exception / Unchecked Exception</h3>
<p>Kotlin은 <code>Checked Exception</code>과 <code>Unchecked Exception</code>을 구분하지 않습니다. 아래를 보면 Java의 경우 <code>IOException</code>에 의해 오류가 발생하는 것을 볼 수 있지만, Kotlin의 경우 그렇지 않은 것을 볼 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/0425f843-4a28-4e37-a07d-d4c76f3b62af/image.png" alt=""></p>
<h3 id="try-with-resources">Try-With-Resources</h3>
<p>Kotlin은 <code>try-wiht-resouces</code>문이 사라졌습니다. 대신, 아래와 같이 <code>use</code>라는 inline 확장 함수를 사용하여 동일하게 동작할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/2526f12e-b072-49a8-a4c4-374c29229266/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코틀린에서 제어문을 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%EC%BD%94%ED%8B%80%EB%A6%B0%EC%97%90%EC%84%9C-%EC%A0%9C%EC%96%B4%EB%AC%B8%EC%9D%84-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/%EC%BD%94%ED%8B%80%EB%A6%B0%EC%97%90%EC%84%9C-%EC%A0%9C%EC%96%B4%EB%AC%B8%EC%9D%84-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Thu, 24 Jul 2025 06:56:27 GMT</pubDate>
            <description><![CDATA[<h2 id="if">If</h2>
<p>Kotlin에서의 If문은 Java와 작성 방법은 동일하지만, Kotlin의 경우 아래와 같이 작성하는 것도 가능합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/085dc61e-b0a1-439c-a429-843409ad5fd1/image.png" alt=""></p>
<p>왜냐하면, Java의 경우 If문은 Statement이기 때문이지만, <strong>Kotlin의 경우 If-Else문을 하나의 값으로 도출될 수 있는 Expression으로 취급</strong>하기 떄문입니다. 이러한 차이로 인해, Kotlin에서는 삼항 연산자가 존재하지 않습니다.</p>
<h2 id="switch">Switch</h2>
<p>Kotlin에는 Switch문이 사라진대신 When문을 사용합니다. 이를 Java의 Switch문과 Kotlin의 When문 비교를 통해 살펴보겠습니다.</p>
<p>기본적인 차이점은 아래와 같습니다.
<img src="https://velog.velcdn.com/images/park_rootseok/post/c7fd68e0-30f9-4ceb-ac0c-872003fe9fb7/image.png" alt=""></p>
<p>이에 추가로, When문은 아래와 같이 조건부에 단순 일치 여부외에도 범위 조건, 다중 조건 등 다양한 분기 조건을 만들 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/1661533b-8995-46d8-af1b-7c7ed07b44a2/image.png" alt=""></p>
<p>또한, (value)를 생략하여 Early Return처람 동작하도록 만들 수 있습니다. 아래와 같이 작성할 경우, 첫 번째 조건을 만족하게 되면 수행 후 나머지 분기들은 수행하지 않습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/e090dd6f-c45e-4086-95c2-4e241cbcecac/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[연산자를 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%EC%97%B0%EC%82%B0%EC%9E%90%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/%EC%97%B0%EC%82%B0%EC%9E%90%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Wed, 23 Jul 2025 15:49:22 GMT</pubDate>
            <description><![CDATA[<h2 id="단항--산술-연산자">단항 / 산술 연산자</h2>
<p>Kotlin에서 단항 연산자(++, --), 산술 연산자(+, -, /, %), 산술 대입 연산자의 사용 방법은 Java와 동일합니다.</p>
<h2 id="비교-연산자">비교 연산자</h2>
<p>Kotlin과 Java의 비교 연산자(&gt;, &gt;=, &lt;=, &lt;)의 사용 방법은 Java와 동일하지만, 한 가지 차이점이 존재합니다. 이는 Kotlin의 경우 비교 연산자를 사용하면 자동으로 재정의한 <code>compareTo()</code> 메서드를 호출해 활용한다는 점 입니다. 이게 무엇을 의미하는지 코드를 예시로 살펴보겠습니다.</p>
<p>아래와 같이 클래스에 재정의한 <code>compareTo()</code> 메서드가 존재합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/1055de42-3c23-4c26-8c57-a5b2c6208d95/image.png" alt=""></p>
<p>일반적으로 Java의 경우 아래와 같이 재정의한 메서드를 직접 호출하여 비교를 수행합니다.
<img src="https://velog.velcdn.com/images/park_rootseok/post/1378a733-5b36-46f3-b8aa-bc6402447126/image.png" alt=""></p>
<p>하지만, Kotlin은 아래와 같이 비교 연산자 사용시 자동으로 재정의한 <code>compareTo()</code> 메서드를 활용해 비교 연산을 수행합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/0ca74dad-bf65-4c31-8901-93029bfe17ce/image.png" alt=""></p>
<blockquote>
<h4 id="kotlin에서의-동등성과-동일성">Kotlin에서의 동등성과 동일성</h4>
</blockquote>
<ul>
<li>동등성 : 두 객체의 값이 같은가?<ul>
<li>Java는 <code>equals()</code> 메서드를 활용하지만, Kotlin은 <code>==</code> 연산자 활용</li>
<li>Kotlin에서는 <code>==</code> 연산자를 사용하면 간접적으로 <code>equls()</code> 메서드를 호출</li>
</ul>
</li>
<li>동일성 : 두 객체의 주소가 같은가?<ul>
<li>Java는 <code>==</code> 연산자를 활용하지만, Kotlin은 <code>===</code> 연산자 활용</li>
</ul>
</li>
</ul>
<h2 id="논리-연산자">논리 연산자</h2>
<p>Kotlin에서 논리 연산자(&amp;&amp;, ||, !) 사용 방법 및 Lazy 연산 수행 등 사용 방법은 Java와 동일합니다. </p>
<h2 id="kotlin에-있는-특이한-연산자">Kotlin에 있는 특이한 연산자</h2>
<p>Kotlin에는 <code>in</code>, <code>!in</code>, <code>a..b</code> 등 Java에 존재하지 않는 특이한 연산자가 존재합니다. 각 연산자가 수행하는 동작은 아래와 같습니다.</p>
<ul>
<li><code>in</code>, <code>!in</code><ul>
<li>컬렉션이나 범위에 포함되어 있는지 (or 없는지)</li>
</ul>
</li>
<li><code>a..b</code><ul>
<li>a부터 b까지 범위를 가지는 객체를 생성 </li>
</ul>
</li>
</ul>
<h2 id="연산자-오버로딩">연산자 오버로딩</h2>
<p>Kotlin에서는 <code>operator</code> 키워드를 활용해 객체마다 연산자를 직접 정의할 수 있습니다. 이는 예시를 통해 살펴보겠습니다.</p>
<p>아래와 같이 <code>operator</code> 키워드를 활용해 <code>+</code> 역할을 수행하는 메서드를 정의한 클래스가 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/8b8769a2-4d6c-491b-8ac1-5f1b8e53f9c9/image.png" alt=""></p>
<p>2개의 Money 클래스 가진 값에 대한 더하기 연산을 수행하기 위해선 Java의 경우 아래와 같이 코드를 작성합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/70cce02a-1e13-4924-947a-d222d46c05ae/image.png" alt=""></p>
<p>하지만, Kotlin에서는 아래와 같이 <code>+</code> 연산자를 활용해도 자동으로 <code>plus()</code> 메서드를 호출하여 동일한 동작을 수행합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/c0cb2393-f63e-47ba-abd6-db8ff1ee1391/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Type을 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/Type%EC%9D%84-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/Type%EC%9D%84-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Tue, 22 Jul 2025 13:04:31 GMT</pubDate>
            <description><![CDATA[<h2 id="기본-타입">기본 타입</h2>
<p>Kotlin은 Java와 동일하게 Byte, Short, Int, Long, Float, Double 등을 기본 타입으로 가지고 있습니다. 하지만, 크기의 대소에 따라 기본 타입간 형변환시 암묵적으로 수행할 수 있는 Java와 달리 Kotlin은 명시적으로 수행해야 합니다. </p>
<p>Java는 아래와 같이 크기가 더 작은 int(4Byte) 자료형을 더 큰 자료형인 long(8byte)으로 변환할 경우, 별도로 명시할 필요가 없습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/98d2b14f-ba2e-43e0-8d14-ca8656c7152f/image.png" alt=""></p>
<p>하지만, Kotlin에서 동일한 기능을 수행하기 위해선 아래와 같이 <code>toXXX()</code>를 활용해야합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/c21bea4b-c865-4cf9-8475-9702a692a071/image.png" alt=""></p>
<h2 id="타입-캐스팅">타입 캐스팅</h2>
<p>Kotlin은 타입 캐스팅을 수행할 때 <code>as</code>, <code>is</code> 등을 사용합니다. Java에서 사용했던 <code>instanceOf</code>와 무엇이 다른지 한 번 살펴보겠습니다.</p>
<p>아래와 같이 타입 캐스팅을 수행하는 Java 코드가 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/72a67c18-86fa-4ee1-8944-17d251e2dfc6/image.png" alt=""></p>
<p>이를 Kotlin으로 작성시 아래와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/ecc33503-035e-4840-94ab-14fbf63bc566/image.png" alt=""></p>
<p>여기서 하나의 차이가 더 있습니다. Kotlin은 <code>is</code> 연산자를 통해 특정 클래스임을 확실히 할 경우, 별도의 형변환 없이 아래와 같이도 작성 가능합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/ee7fbaa7-753f-46a7-8d1e-6ebdb5775290/image.png" alt=""></p>
<p>추가로, 아래와 같이 <code>!is</code> 연산자를 사용해 동일한 클래스가 아닌지 또한 쉽게 알 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/cfc7e14f-d841-4243-90b0-0456c76100e7/image.png" alt=""></p>
<h2 id="kotlin의-3가지-특이한-타입">Kotlin의 3가지 특이한 타입</h2>
<h3 id="any">Any</h3>
<p><code>Any</code> 타입은 Java의 Object와 동일한 역할을 수행합니다. 즉, 모든 객체의 최상위 타입을 의미합니다. 즉, Kotlin에서는 Primitive Type과 Reference Type을 구분하지 않기에 두 Type의 최상위 타입은 <code>Any</code> 입니다.</p>
<h3 id="unit">Unit</h3>
<p><code>Unit</code> 타입은 Java의 void와 동일한 역할을 수행합니다. 한 가지 다른점이 있다면, Java의 void와 다르게 <code>Unit</code>은 그 자체로 타입 인자로 사용할 수 있습니다. Java의 경우 Generic 문법에서 void를 사용할 경우 Void 클래스를 사용해야 하지만, <code>Unit</code>은 그렇지 않습니다.  </p>
<h3 id="nothing">Nothing</h3>
<p><code>Nothing</code> 타입은 &#39;함수가 정상적으로 끝나지 않았다&#39;는 사실을 표현하는 역할을 수행합니다. 아래와 같이 무조건 예외를 반환하거나 무한 루프가 발생하는 함수에 명시합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/44126247-bc6f-46df-972d-d28fdc7f110f/image.png" alt=""></p>
<h2 id="string-interpolation--string-indexing">String Interpolation / String Indexing</h2>
<h3 id="string-interpolation">String Interpolation</h3>
<p>Kotlin은 문자열 내 변수를 삽입할 때 <code>${변수}</code>를 사용해 수행할 수 있습니다. Java에서는 <code>String.format()</code> 또는 <code>StringBuilder</code>를 활용하기 때문에 가독성 측면에서 불편하다고 생각했는데, Kotlin으로 작성할 경우 다음 예시와 같이 보다 편하게 작성할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/8843b5b1-d1d4-4fe8-b9d2-c118d5551365/image.png" alt=""></p>
<p>추가로, Kotlin의 경우 여러 줄에 걸친 문자열을 작성할 때 아래와 같이 <code>&quot;&quot;&quot;</code>와 <code>trimIndent()</code>를 사용하면, <code>StringBuilder</code>를 활용하는 것 보다 쉽게 작성할 수 있 습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/a0fc9f7d-c3b2-4c1d-a4e3-857d17c8eb8d/image.png" alt=""></p>
<h3 id="string-indexing">String Indexing</h3>
<p>Kotlin은 문자열에서 특정 문자를 가져올 때 배열처럼 가져오고 싶은 위치를 인덱스로 사용하여 가져올 수 있습니다. 즉, Java의 <code>charAt(int index)</code> 수행 결과와 Kotlin의 <code>string[index]</code>가 동일한 것을 의미합니다. 아래는 예시입니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/f9fa5060-9f75-4946-8139-560f77b77323/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Null을 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/Null%EC%9D%84-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/Null%EC%9D%84-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sun, 20 Jul 2025 12:23:35 GMT</pubDate>
            <description><![CDATA[<h2 id="safe-call과-elvis">Safe Call과 Elvis</h2>
<p>함수의 파라미터로 전달되는 값에 null 값이 들어올 수 있을때, Java의 경우는 IF문을 활용해야 합니다. 반면, Kotlin은 <code>Safe Call</code>과 <code>Elvis</code> 연산자를 지원하기 때문에 보다 간단하게 이를 수행할 수 있습니다.</p>
<h3 id="safe-call">Safe Call</h3>
<p><code>Safe Call</code>은 <strong>null이 아니면 실행하고, 맞으면 실행하지 않도록 하는 기능</strong>입니다. 아래와 같은 활용 예시를 통해 어떻게 동작하는지 살펴보겠습니다.</p>
<p>우선, Safe Call을 사용하지 않고 Java 코드를 변환한 결과입니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/8d8a0ef5-0c59-4470-b104-dc4af463abd4/image.png" alt=""></p>
<p>여기에 함수를 실행하는 주체에 <code>?</code>를 명시하여 Safe Call을 적용해보면 아래와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/cc5e37fb-dbce-4033-9f5a-c5a13de6f171/image.png" alt=""></p>
<p>적용 결과를 보면 IF문을 사용 코드보다 더 간결하게 작성된 것을 볼 수 있습니다. 그런데, 여기서 1번과 3번 코드는 오류가 발생하는 것을 발견할 수 있습니다. 이는 <code>Safe Call</code>의 경우 null 값이 들어올 경우 null을 반환하기 때문입니다. 그럼 이는 어떻게 해결할까요? 그 방법은 <code>Elvis</code> 연산자에서 알아보도록 하겠습니다.</p>
<h3 id="elvis">Elvis</h3>
<p><code>Elvis(?:)</code> 연산자는 <strong>앞의 연산 결과가 null일 경우, 선언한 값을 사용하도록 하는 기능</strong>입니다. 이 연산자는 <code>Safe Call</code> 를 사용할 경우 null 값이 들어오면 null이 반환되는데, null이 아닌 선언한 값을 반환시키고 싶을 때 다음과 같이 사용할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/b5054f50-7ecc-4b8f-b725-628fb234d647/image.png" alt=""></p>
<p>위 결과를 보면, 1번과 3번 함수의 경우 null일 때 null이 아닌 값을 반환하도록 명시했기 때문에, 반환 타입에 <code>?</code>를 명시하지 않아도 정상적으로 작동하는 것을 볼 수 있습니다.</p>
<h2 id="-연산자"><code>!!</code> 연산자</h2>
<p><code>!!</code> 연산자는 <strong>&#39;이 변수는 절대 null이 아니야!&#39; 라고 컴파일러에게 강제로 알려주는 용도로 사용</strong>됩니다. 하지만, 아래와 같이 실제로 null이 들어오면 NullPointerException이 발생하기 때문에 안전하지 않은 연산입니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/950e1200-90f5-4f18-9a11-21a36e016b61/image.png" alt=""></p>
<h2 id="platform-type">Platform Type</h2>
<p><code>Platform Type</code>은 Kotlin이 <strong>null 관련 정보를 알 수 없는 Type</strong>을 말합니다. 아래와 같이 Java 코드로 작성된 Person 클래스를 Kotlin 코드에서 사용하게 될 경우 name에 null이 발생할 수 있지만 컴파일러는 이를 알 수 없습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/773f47ab-5571-4f29-8ff3-974d321e041a/image.png" alt=""></p>
<p>그렇기 때문에, Kotlin에서 Java로 작성된 Class를 사용할 경우 아래와 같이 반드시 <strong>컴파일러가 null 발생 여부를 판단할 수 있도록 어노테이션을 활용하여 관련 정보를 명시</strong>해주어야 합니다.
<img src="https://velog.velcdn.com/images/park_rootseok/post/6e840c5e-b41e-472e-999e-a9800d6a8eb4/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[변수를 다루는 방법]]></title>
            <link>https://velog.io/@park_rootseok/%EB%B3%80%EC%88%98%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@park_rootseok/%EB%B3%80%EC%88%98%EB%A5%BC-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sun, 20 Jul 2025 05:02:11 GMT</pubDate>
            <description><![CDATA[<h2 id="var과-val">var과 val</h2>
<p>Kotlin은 변수를 선언할 때 반드시 var 또는 val 키워드를 선언해야 합니다. 그렇다면, 이 두 키워드의 차이는 무엇일까요? 이 둘의 차이를 코드를 통해 알아보겠습니다.</p>
<p>아래와 같이 2줄의 변수를 선언하는 Java 코드 작성되어 있습니다. 작성된 2줄의 코드 중 1번은 가변성을, 2번은 불변성을 가집니다. 이를 Kotlin 코드로 변환할 경우 오른쪽과 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/01a888a7-1397-4bda-97f8-dff717076324/image.png" alt=""></p>
<p>결과를 살펴보면, 가변성을 가지는 1번은 <code>var</code> 키워드를, 불변성을 가지는 2번은<code>val</code> 키워드가 사용되고 있습니다. 즉, <code>var(variable)</code>는 변수의 가변성을 의미하고, <strong><code>val(value)</code>은 변수의 불변성</strong>을 의미하는 것을 알 수 있습니다.</p>
<h2 id="타입-추론">타입 추론</h2>
<p>Kotlin은 명시적으로 자료형을 선언하지 않아도 정상 작동합니다. 이는 <strong>컴파일러가 변수의 자료형을 유추하는 타입 추론(type inference) 기능을 제공</strong>하기 때문입니다. 아래 예시처럼 1번과 2번 코드는 동일한 역할을 수행합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/fd7c61fd-3918-4ed1-af7c-2c80aaea31fa/image.png" alt=""></p>
<p>단, <strong>타입을 생략할 경우 반드시 초기값이 필요</strong>합니다. 이는 초기값이 없으면 타입 추론이 불가하기 때문입니다. 실제로, 초기값과 타입 모두 명시하지 않을 경우 아래와 같이 컴파일 오류가 발생합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/c4c4a546-b081-41db-b1b6-d9bc7d1e6cbd/image.png" alt=""></p>
<h2 id="primitive-type">Primitive Type</h2>
<p>Java의 경우 사용 목적에 따라 Primitive Type과 Reference Type을 구분하여 사용하지만, Kotlin은 구분 없이 사용합니다. 실제로, <a href="https://kotlinlang.org/docs/basic-types.html#">Kotlin Docs</a>의 Basic Types를 살펴보면 아래와 같은 내용이 존재합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/8f628b52-cc1d-4895-b6a9-745bb44e61a4/image.png" alt=""></p>
<p>해석해보면 &quot;런타임에서 특정 타입(숫자, 문자, 불리언 등)은 <strong>성능을 최적화하기 위해 내부적으로 원시 값으로 표현</strong>될 수 있지만, <strong>개발자 관점에서는 일반 클래스처럼 보이고 동작</strong>합니다.&quot; 라고 명시되어 있습니다. </p>
<p>즉, Kotlin은 타입을 클래스처럼 작성해도 실제 컴파일 시에는 성능을 고려해 primitive 타입으로 변환됩니다. 이러한 동작을 실제로 확인하기 위해, Kotlin 코드를 Java로 Decompile해보면 <code>long</code>으로 선언된 것을 확인할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/51e1d382-b652-4dae-b286-cf2e3bd6bea1/image.png" alt=""> </p>
<h2 id="nullable">Nullable</h2>
<p>Kotlin은 Java와 달리 Primitive Type과 Reference Type을 구분하지 않습니다. 하지만, 여기서 중요한 차이가 하나 있습니다. Java의 Reference Type은 null을 가질 수 있지만, Primitive Type은 그렇지 않습니다.</p>
<p>이 차이를 보완하기 위해, Kotlin에서는 null을 허용하려면 아래 예시와 같이 자료형 뒤에 <code>?</code>를 명시해야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/41899fcb-717a-46d0-b91a-099e44da6ceb/image.png" alt=""></p>
<p>Kotlin은 이처럼 <code>?</code>를 통해 null 가능성을 명시적으로 표현함으로써,
<code>NullPointerException</code>을 예방하고 컴파일 타임에 안정성을 확보하는 장점을 제공합니다.</p>
<h2 id="instance">Instance</h2>
<p>Java에서는 클래스를 인스턴스화할 때 반드시 new 키워드를 사용해야 합니다.
하지만, Kotlin은 <code>new</code> 키워드를 사용하지 않고 클래스 이름을 함수처럼 호출하여 인스턴스를 생성합니다.</p>
<p><img src="https://velog.velcdn.com/images/park_rootseok/post/4c3183c3-6db5-484c-807a-0710264e1a94/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2장. 개략적인 규모 측정]]></title>
            <link>https://velog.io/@park_rootseok/2%EC%9E%A5.-%EA%B0%9C%EB%9E%B5%EC%A0%81%EC%9D%B8-%EA%B7%9C%EB%AA%A8-%EC%B8%A1%EC%A0%95</link>
            <guid>https://velog.io/@park_rootseok/2%EC%9E%A5.-%EA%B0%9C%EB%9E%B5%EC%A0%81%EC%9D%B8-%EA%B7%9C%EB%AA%A8-%EC%B8%A1%EC%A0%95</guid>
            <pubDate>Thu, 08 May 2025 02:42:37 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가며">들어가며</h2>
<p>시스템 설계 면접을 진행하는 과정에서 때로는 시스템 용량이나 성능 요구사항을 개략적으로 추정해 보라는 요구를 받기도 합니다. 이를 효과적으로 수행하기 위해선 규모 확장성을 표현하기 위한 기본기에 능숙해야 합니다. 2장에서는 기본기인 2의 제곱수, 응답지연 값, 고가용성 관련 수치 등을 알아보는 챕터입니다.</p>
<h2 id="2의-제곱수">2의 제곱수</h2>
<p>분산 시스템에서 다루는 데이터 양은 엄청나게 커질 수 있지만, 계산법은 기본을 크게 벗어나지 않습니다. 제대로 된 계산 결과를 얻으려면 데이터 볼륨의 단위를 2의 제곱수로 표현하면 어떻게 되는지를 우선 알아야 합니다. 최소 단위는 1바이트(8비트)로 구성되며, ASCII 문자 하나가 차지하는 메모리 크기가 1바이트입니다. </p>
<p>흔히 사용하는 데이터 볼륨 단위들에 대한 정보는 다음과 같습니다.</p>
<ul>
<li>1KB<ul>
<li>2의 제곱수 : $2^{10}$</li>
<li>근사치 : 1천</li>
</ul>
</li>
<li>1MB<ul>
<li>2의 제곱수 : $2^{20}$</li>
<li>근사치 : 1백만</li>
</ul>
</li>
<li>1GB ($2^{30}$)<ul>
<li>2의 제곱수 : $2^{30}$</li>
<li>근사치 : 10억</li>
</ul>
</li>
<li>1TB<ul>
<li>2의 제곱수 : $2^{40}$</li>
<li>근사치 : 1조</li>
</ul>
</li>
<li>1PB<ul>
<li>2의 제곱수 : $2^{50}$</li>
<li>근사치 : 1000조</li>
</ul>
</li>
</ul>
<h2 id="모든-프로그래머가-알아야-하는-응답지연-값">모든 프로그래머가 알아야 하는 응답지연 값</h2>
<p>구글의 제프 딘은 2010년에 통상적인 컴퓨터에서 구현된 연산들의 응답지연 값을 공개한 바 있습니다. 이들 가운데 몇몇은 HW의 발전으로 유효하지 않게 되었지만, 아직도 이 수치들은 컴퓨터 연산 처리 속도를 짐작할 수 있도록 도와줍니다.</p>
<p>연산명과 그에 대한 응답지연 값의 정보는 다음과 같습니다.</p>
<ul>
<li>L1 캐시 참조 : $1\mathrm{ns}$</li>
<li>분기 예측 오류 : $3\mathrm{ns}$</li>
<li>L2 캐시 참조 : $4\mathrm{ns}$</li>
<li>뮤텍스 락/언락 : $17\mathrm{ns}$</li>
<li>주 메모리 참조 : $100\mathrm{ns}$</li>
<li>Zippy로 1KB 압축 : $2,000\mathrm{ns} = 2\mu\mathrm{s}$</li>
<li>메모리에서 1MB 순차적 Read : $3,000\mathrm{ns} = 3\mu\mathrm{s}$</li>
<li>디스크 탐색 : $2,000,000\mathrm{ns} = 2\mathrm{ms}$</li>
<li>디스크에서 1MB 순차적 Read : $825,000\mathrm{ns} = 825\mu\mathrm{s}$</li>
<li>네트워크에서 1MB 순차적 Read : $10,000,000\mathrm{ns} = 10\mathrm{ms}$</li>
<li>일반 상용 네트워크에서 2KB 전송 : $44,000\mathrm{ns} = 44\mu\mathrm{s}$</li>
<li>동일 데이터 센터 내에서의 패킷 왕복 지연시간 : $500,000\mathrm{ns} = 500\mu\mathrm{s}$</li>
<li>한 패킷이 캘리포니아로부터 네덜란드까지의 왕복 지연시간 : $150,000,000\mathrm{ns} = 150\mathrm{ms}$</li>
</ul>
<p>위 수치들을 분석하면 다음과 같은 결론을 낼 수 있습니다.</p>
<ul>
<li><strong>메모리는 빠르지만 디스크는 아직 느리다.</strong><ul>
<li>메모리에서 1MB 데이터를 읽는데 $3\mu\mathrm{s}$가 소요되는 반면</li>
<li>디스크에서는 $825\mu\mathrm{s}$가 소요</li>
</ul>
</li>
<li><strong>디스크 탐색은 가능한 피해야한다.</strong><ul>
<li>디스크 탐색에서의 응답 지연은 무려 $2\mathrm{ms}$</li>
</ul>
</li>
<li><strong>단순 압축 알고리즘은 빠르다.</strong><ul>
<li>Zippy로 1KB를 압축하기 위한 지연시간은 $2\mu\mathrm{s}$</li>
<li>즉, 데이터를 <strong>인터넷으로 전송하기 전에 가능하면 압축하는 것이 좋음</strong></li>
</ul>
</li>
<li>데이터 센터는 보통 여러 지역에 분산되어 있고, 센터들 간 데이터를 주고받는 데는 시간이 소요된다.</li>
</ul>
<h2 id="가용성에-관계된-수치들">가용성에 관계된 수치들</h2>
<p>고가용성은 시스템이 오랜 시간 동안 지속적으로 중단 없이 운영될 수 있는 능력을 말합니다. 고가용성을 표현하는 값은 퍼센트로 표현하는데, 100%는 시스템이 단 한 번도 중단된 적이 없었음을 의미합니다. 대부분의 서비스는 99% 이상을 유지하고 있습니다.</p>
<p>SLA는 서비스 사업자가 보편적으로 사용하는 용어로, 서비스 사업자와 고객 사이에 맺어진 합의를 의미합니다. 이 합의에는 서비스의 가용시간이 공식적으로 기술되어 있습니다. 가용시간의 경우 관습적으로 숫자 9를 사용해 표시하는데, 9가 많을수록 좋다고 볼 수 있습니다.</p>
<p>9의 개수와 시스템 장애 시간 사이에 대한 관계는 다음과 같습니다.</p>
<table>
<thead>
<tr>
<th align="center">가용률</th>
<th align="center">하루당 장애시간</th>
<th align="center">주당 장애시간</th>
<th align="center">개월당 장애시간</th>
<th align="center">연간 장애시간</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><strong>99%</strong></td>
<td align="center">14.40분</td>
<td align="center">1.68시간</td>
<td align="center">7.31시간</td>
<td align="center">3.65일</td>
</tr>
<tr>
<td align="center"><strong>99.9%</strong></td>
<td align="center">1.44분</td>
<td align="center">10.08분</td>
<td align="center">43.88분</td>
<td align="center">8.77시간</td>
</tr>
<tr>
<td align="center"><strong>99.99%</strong></td>
<td align="center">8.64초</td>
<td align="center">1.01분</td>
<td align="center">4.38분</td>
<td align="center">52.6분</td>
</tr>
<tr>
<td align="center"><strong>99.999%</strong></td>
<td align="center">864밀리초</td>
<td align="center">6.05초</td>
<td align="center">26.30초</td>
<td align="center">5.26분</td>
</tr>
<tr>
<td align="center"><strong>99.9999%</strong></td>
<td align="center">86.4밀리초</td>
<td align="center">604.8밀리초</td>
<td align="center">2.63초</td>
<td align="center">31.56초</td>
</tr>
</tbody></table>
<h2 id="예제-트위터-qps와-저장소-요구량-측정">예제: 트위터 QPS와 저장소 요구량 측정</h2>
<h3 id="가정">가정</h3>
<ul>
<li>MAU(월간 능동 사용자)는 3억 명입니다.</li>
<li>매일 50%의 사용자가 트위터를 사용합니다.</li>
<li>평균적으로 각 사용자는 매일 2건의 트윗을 수행합니다.</li>
<li>미디어를 포함하는 트윗의 비율은 10% 입니다.</li>
<li>데이터는 5년간 보관됩니다.</li>
</ul>
<h3 id="추정">추정</h3>
<ul>
<li><p>QPS 추정치</p>
<ul>
<li>DAU(일간 능동 사용자) = MAU X 사용량 = 3억 X 50% = 1.5억</li>
<li>QPS = DAU(1.5억) X 트윗 수행 개수(2) / 24시간 / 60분 / 60초 = 약 3,500</li>
<li>최대 QPS = 2 X QPS = 약 7,000</li>
</ul>
</li>
<li><p>미디어 저장을 위한 저장소 요구량</p>
<ul>
<li>일당 저장소 요구량<ul>
<li>DAU(1.5억) X 평균 트윗 개수(2) X 미디어 포함 비율(10%) X 미디어 크기(1MB) = 30TB/일</li>
</ul>
</li>
<li>5년간 저장소 요구량<ul>
<li>일당 저장소 요구량(30TB) X 365 X 5 = 약 55PB</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>