<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>기록하기</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sat, 03 May 2025 05:46:28 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>기록하기</title>
            <url>https://velog.velcdn.com/images/cheon-eunjeong/profile/80832611-83a9-412d-bddd-9d72f8453f58/image.PNG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 기록하기. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/cheon-eunjeong" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Java] Java Stream 개념부터 잡기]]></title>
            <link>https://velog.io/@cheon-eunjeong/Java-Java-Stream-API%EB%A5%BC-%EC%9D%B4%ED%95%B4%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@cheon-eunjeong/Java-Java-Stream-API%EB%A5%BC-%EC%9D%B4%ED%95%B4%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sat, 03 May 2025 05:46:28 GMT</pubDate>
            <description><![CDATA[<h2 id="1-api란">1. API란?</h2>
<blockquote>
<p><strong>API (Application Programming Interface)</strong>는 두 소프트웨어가 기능이나 데이터를 주고받기 위해 정해놓은 <strong>규칙(명세)</strong>이다.</p>
</blockquote>
<p>쉽게 말해, <strong>서로 다른 프로그램이 정해진 방식에으로 소통할 수 있게 해주는 설명서 또는 사용법</strong>을 말한다.</p>
<pre><code>List&lt;String&gt; list = new ArrayList&lt;&gt;();
list.add(&quot;추가&quot;);</code></pre><p>위 코드에서 <code>add()</code>는 우리가 직접 구현한 메서드가 아니지만,
<strong>Java API에 정의된 메서드를 호출</strong>함으로써 <strong>리스트에 데이터를 추가</strong>할 수 있다.</p>
<p><code>add()</code>가 아니라 <code>추가해줘()</code> 같은 임의의 이름을 사용하면 동작하지 않는다.
Java API가 <strong>정의한 명세</strong>를 따라야만 우리가 의도한 기능이 수행되는 것이다.</p>
<hr>
<h2 id="2-java-api와-패키지-구조">2. Java API와 패키지 구조</h2>
<blockquote>
<p><strong>Java API</strong>는 Java에서 기본적으로 제공하는 기능들의 집합이다.</p>
</blockquote>
<p>우리가 Java에서 사용하는 <code>List</code>, <code>Map</code>, <code>Math</code>, <code>Stream</code> 등은 모두 <strong>Java API</strong>에 포함되어 있으며,
다음과 같이 기능별로 <strong>패키지(package)</strong>라는 단위로 나뉘어 관리된다.</p>
<ul>
<li><code>java.util</code> → 유틸리티 클래스 (List, Map 등)</li>
<li><code>java.io</code> → 입출력 기능 (InputStream 등)</li>
<li><code>java.util.stream</code> → 스트림 처리 기능 (Stream 등)</li>
</ul>
<hr>
<h2 id="3-java에서-말하는-stream이란">3. Java에서 말하는 &quot;Stream&quot;이란?</h2>
<p><strong>Stream</strong>의 사전적 의미는 <code>흐름</code>, <code>연속적인 흐름</code>이며,
프로그래밍에서는 <strong>일련의 데이터를 한 방향으로 흘려보내며 처리하는 구조</strong>를 의미한다.</p>
<p>대표적인 예:</p>
<ul>
<li>파일을 읽을 때 사용하는 <code>InputStream</code></li>
<li>데이터를 출력하는 <code>OutputStream</code></li>
<li>영상/음악을 실시간으로 전송하는 스트리밍 서비스</li>
</ul>
<blockquote>
<p>Java Stream API를 설명하기 전, 먼저 &quot;Stream&quot;은 <strong>데이터를 흐름처럼 처리하는 방식</strong> 이라는 개념부터 이해하면 된다.</p>
</blockquote>
<hr>
<h2 id="4-java-stream-api란">4. Java Stream API란?</h2>
<blockquote>
<p><strong>Java Stream API</strong>는 위에서 설명한 Stream 개념을 Java에서 공식적으로 구현해 제공하는 기능 집합이다.</p>
</blockquote>
<p><strong>Java Stream API</strong>에는 다음과 같은 클래스들이 포함되어 있으며,
<code>java.util.stream</code> 패키지 안에 정의되어 있다.</p>
<ul>
<li><code>Stream</code>, <code>IntStream</code>, <code>LongStream</code> 등 스트림 인터페이스</li>
<li><code>Collectors</code>, <code>StreamSupport</code>, <code>Spliterator</code> 등 보조 유틸리티 클래스</li>
</ul>
<p>이해하기 쉽게 비유로 포현해보자면 다음과 같다.</p>
<p>비유 대상|    실제 의미
|---|---|
|📦 java.util.stream 패키지|    기능이 정리되어 담긴 서랍|
|🔧 Stream API    |서랍 안에 있는 공구 세트 (기능 집합)|
|🛠️ Stream, Collectors, map, filter...|    우리가 직접 사용하는 공구들|
|🧑‍🔧 개발자|    공구를 조합해 데이터를 가공하는 사람 = Stream 사용자|</p>
<hr>
<h2 id="5-정리하자면">5. 정리하자면</h2>
<ul>
<li><strong>Stream</strong>: 데이터를 흐름처럼 처리하는 개념</li>
<li><strong>API</strong>: 기능을 사용할 수 있도록 정의된 명세</li>
<li><strong>Java Stream API</strong>: Java에서 Stream 기능을 사용할 수 있도록 제공하는 기능 모음</li>
</ul>
<p>이 기능들은 <code>java.util.stream</code> 패키지 안에 포함되어 있고,
우리는 그 안의 메서드들(<code>map</code>, <code>filter</code>, <code>collect</code> 등)을 조합해 데이터를 처리한다.</p>
<p>이러한 과정을 우리는 흔히 <strong>&quot;Stream을 사용한다&quot;</strong>고 말하는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 큐(Queue)와 우선순위큐(PriorityQueue)]]></title>
            <link>https://velog.io/@cheon-eunjeong/Java-%ED%81%90Queue%EC%99%80-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%ED%81%90PriorityQueue</link>
            <guid>https://velog.io/@cheon-eunjeong/Java-%ED%81%90Queue%EC%99%80-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%ED%81%90PriorityQueue</guid>
            <pubDate>Sun, 20 Apr 2025 15:04:47 GMT</pubDate>
            <description><![CDATA[<h2 id="✔️-한-줄-요약">✔️ 한 줄 요약</h2>
<p><strong>Queue는</strong> FIFO(First-In-First-Out) 구조를 따르는 자료구조 인터페이스이며,<br><strong>PriorityQueue는</strong> 이를 구현한 클래스 중 하나로 우선순위 기반 정렬 큐를 제공한다.</p>
<hr>
<h2 id="1-queue란">1. Queue란?</h2>
<p><img src="https://velog.velcdn.com/images/cheon-eunjeong/post/3616e701-aab8-458c-82ff-091f1c40ee1e/image.png" alt=""></p>
<p><strong>Queue는</strong> <strong>선입선출(FIFO)</strong> 구조를 따르는 컬렉션으로,<br><strong>먼저 추가된 요소가 먼저 제거</strong>되는 구조를 가진 인터페이스이다.</p>
<p>인터페이스이므로 직접 객체 생성은 불가능하고, <code>LinkedList</code>, <code>PriorityQueue</code> 등 구현체를 사용한다.</p>
<pre><code class="language-java">Queue&lt;String&gt; queue = new LinkedList&lt;&gt;();
queue.add(&quot;A&quot;);
queue.add(&quot;B&quot;);
System.out.println(queue.poll()); // A</code></pre>
<hr>
<h2 id="2-priorityqueue란">2. PriorityQueue란?</h2>
<p><strong>PriorityQueue</strong>는 Queue 인터페이스를 <strong>우선순위 기반</strong>으로 구현한 클래스다.
즉, 먼저 넣은 순서가 아닌 <strong>값의 크기나 지정한 우선순위 기준에 따라</strong> 요소가 처리된다.</p>
<pre><code class="language-java">PriorityQueue&lt;Integer&gt; pq = new PriorityQueue&lt;&gt;();
pq.add(30);
pq.add(10);
pq.add(20);
System.out.println(pq.poll()); // 10</code></pre>
<p>위 코드처럼 <code>30 → 10 → 20</code> 순으로 데이터를 넣어도,
<strong>우선순위가 가장 높은 값</strong>인 10이 먼저 <code>poll()</code>로 꺼내진다.</p>
<h3 id="기본-정렬-방식">기본 정렬 방식</h3>
<p>기본적으로 <strong>오름차순 정렬(Min-Heap)</strong> 으로 작동하며,
<code>Comparator.reverseOrder()</code>를 통해 <strong>내림차순(Max-Heap)</strong>으로 바꿀 수 있다.</p>
<pre><code class="language-java">// 오름차순 정렬 (기본)
PriorityQueue&lt;Integer&gt; minHeap = new PriorityQueue&lt;&gt;(); 
// 내림차순 정렬
PriorityQueue&lt;Integer&gt; maxHeap = new PriorityQueue&lt;&gt;(Comparator.reverseOrder()); </code></pre>
<h3 id="🔧-내부-구조">🔧 내부 구조</h3>
<p><img src="https://velog.velcdn.com/images/cheon-eunjeong/post/0b946103-da73-45c6-935e-88537bf02b4a/image.png" alt="">
Java의 <strong>PriorityQueue</strong>는 <strong>힙(Heap)</strong> 자료구조를 기반으로 구현되어 있다.</p>
<p><strong>힙(Heap)</strong>은 <strong>완전 이진 트리</strong> 형태로 구성되며,
요소를 삽입하거나 제거할 때마다 <strong>자동으로 우선순위를 유지하도록 정렬</strong>된다.</p>
<ul>
<li>기본적인 <strong>PriorityQueue</strong>는 <strong>최소 힙(Min-Heap)</strong>이며, 가장 작은 값이 루트에 위치</li>
<li><code>Comparator.reverseOrder()</code>를 사용하면 <strong>최대 힙(Max-Heap)</strong>으로 동작 가능</li>
</ul>
<blockquote>
<p>힙은 정렬된 배열이 아니며, <strong>항상 우선순위가 가장 높은 요소만 빠르게 꺼낼 수 있도록 정렬된 트리 구조</strong>다.</p>
</blockquote>
<hr>
<h2 id="3-queue와-priorityqueue의-주요-메서드">3. Queue와 PriorityQueue의 주요 메서드</h2>
<h3 id="1-offere-e">1. offer(E e)</h3>
<pre><code class="language-java">Queue&lt;String&gt; queue = new LinkedList&lt;&gt;();
queue.offer(&quot;A&quot;);  // 큐에 &quot;A&quot; 추가</code></pre>
<p><strong>설명</strong> : 큐의 <strong>끝에 요소를 추가</strong>한다. 공간이 부족하면 false 반환 
<strong>시그니처</strong> : <code>boolean offer(E e)</code><br><strong>매개변수</strong> : <code>e</code> – 큐에 추가할 요소<br><strong>사용 상황</strong> : 큐에 안전하게 요소를 추가하고, 실패 시 예외 대신 false를 받고 싶을 때</p>
<hr>
<h3 id="2-poll">2. poll()</h3>
<pre><code class="language-java">Queue&lt;String&gt; queue = new LinkedList&lt;&gt;();
queue.offer(&quot;A&quot;);
String item = queue.poll(); // &quot;A&quot; 반환 및 제거</code></pre>
<p><strong>설명</strong> : 큐의 <strong>맨 앞 요소를 제거하고 반환</strong>한다. 비어 있으면 <code>null</code> 반환<br><strong>시그니처</strong> : <code>E poll()</code><br><strong>매개변수</strong> : 없음<br><strong>사용 상황</strong> : 큐에서 안전하게 요소를 꺼내고, 비어 있을 경우 <code>null</code> 처리하고 싶을 때</p>
<hr>
<h3 id="3-remove">3. remove()</h3>
<pre><code class="language-java">Queue&lt;String&gt; queue = new LinkedList&lt;&gt;();
queue.offer(&quot;A&quot;);
String item = queue.remove(); // &quot;A&quot; 반환 및 제거</code></pre>
<p><strong>설명</strong> : 큐의 <strong>맨 앞 요소를 제거하고 반환</strong>한다. 비어 있으면 예외 발생
<strong>시그니처</strong> : <code>E remove()</code><br><strong>매개변수</strong> : 없음<br><strong>사용 상황</strong> : 큐가 비어 있지 않다고 확신할 수 있을 때, 예외로 처리하고 싶은 경우</p>
<hr>
<h3 id="4-peek">4. peek()</h3>
<pre><code class="language-java">Queue&lt;String&gt; queue = new LinkedList&lt;&gt;();
queue.offer(&quot;A&quot;);
String front = queue.peek(); // &quot;A&quot; 반환, 큐는 그대로</code></pre>
<p><strong>설명</strong> : 큐의 <strong>맨 앞 요소를 제거하지 않고 반환</strong>한다. 비어 있으면 <code>null</code> 반환
<strong>시그니처</strong> : <code>E peek()</code><br><strong>매개변수</strong> : 없음<br><strong>사용 상황</strong> : 현재 큐의 앞에 있는 값을 미리 확인하고 싶을 때</p>
<hr>
<h3 id="5-element">5. element()</h3>
<pre><code class="language-java">Queue&lt;String&gt; queue = new LinkedList&lt;&gt;();
queue.offer(&quot;A&quot;);
String front = queue.element(); // &quot;A&quot; 반환, 큐는 그대로</code></pre>
<p><strong>설명</strong> : 큐의 <strong>맨 앞 요소를 제거하지 않고 반환</strong>한다. 비어 있으면 예외 발생.<br><strong>시그니처</strong> : <code>E element()</code><br><strong>매개변수</strong> : 없음<br><strong>사용 상황</strong> : 큐가 비어 있지 않을 때, 요소가 반드시 존재해야 할 때</p>
<hr>
<h3 id="6-isempty">6. isEmpty()</h3>
<pre><code class="language-java">Queue&lt;String&gt; queue = new LinkedList&lt;&gt;();
boolean empty = queue.isEmpty(); // true</code></pre>
<p><strong>설명</strong> : 큐가 <strong>비어 있는지 여부를 반환</strong>한다.<br><strong>시그니처</strong> : <code>boolean isEmpty()</code><br><strong>매개변수</strong> : 없음<br><strong>사용 상황</strong> : 큐가 비어있는지 확인하고 처리 분기하고 싶을 때</p>
<hr>
<h3 id="7-size">7. size()</h3>
<pre><code class="language-java">Queue&lt;String&gt; queue = new LinkedList&lt;&gt;();
queue.offer(&quot;A&quot;);
queue.offer(&quot;B&quot;);
int count = queue.size(); // 2</code></pre>
<p><strong>설명</strong> : 큐에 <strong>현재 저장된 요소의 개수</strong>를 반환한다.<br><strong>시그니처</strong> : <code>int size()</code><br><strong>매개변수</strong> : 없음<br><strong>사용 상황</strong> : 큐의 상태(비어있는지/가득 찼는지 등)를 판단하고자 할 때</p>
<hr>
<h2 id="4-queue와-priorityqueue의-차이점">4. Queue와 PriorityQueue의 차이점</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>Queue</th>
<th>PriorityQueue</th>
</tr>
</thead>
<tbody><tr>
<td>처리 기준</td>
<td>순서대로(FIFO)</td>
<td>우선순위 높은 값부터</td>
</tr>
<tr>
<td>정렬 방식</td>
<td>없음 (삽입 순서 유지)</td>
<td>자동 정렬 (작은 값부터 꺼냄, 힙 기반)</td>
</tr>
<tr>
<td>null 허용</td>
<td>구현체에 따라 가능 (<code>LinkedList</code>는 허용)</td>
<td>X (넣으면 예외 발생)</td>
</tr>
<tr>
<td>내부 구조</td>
<td>리스트 구조 (<code>LinkedList</code>, <code>ArrayDeque</code>)</td>
<td>힙(Heap) 구조</td>
</tr>
<tr>
<td>대표 사용처</td>
<td>BFS, 단순 대기열</td>
<td>다익스트라, 작업 우선순위 처리</td>
</tr>
</tbody></table>
<p><strong>Queue</strong>는 요소가 들어온 순서대로(FIFO) 처리되는 반면,<br><strong>PriorityQueue</strong>는 요소의 값에 따라 우선순위가 높은 요소부터 처리된다.</p>
<p><strong>Queue</strong>는 <code>LinkedList</code>로 구현될 경우 <code>null</code> 을 추가할 수 있지만,
<strong>PriorityQueue</strong>는 내부 정렬 로직(Heap 구조) 때문에 <code>null</code>을 추가하면 <strong>NullPointerException</strong>이 발생하므로 주의해야 한다.</p>
<hr>
<h2 id="5-알고리즘-활용-팁">5. 알고리즘 활용 팁</h2>
<h3 id="☑️-queue">☑️ Queue</h3>
<ul>
<li><p><strong>BFS (너비 우선 탐색)</strong>  </p>
<ul>
<li>그래프 탐색 알고리즘에서 노드를 순차적으로 방문할 때 사용  </li>
<li>FIFO 구조 덕분에 레벨 단위 탐색이 가능함  </li>
<li>예시: 미로 탈출, 최소 이동 거리 계산 등  </li>
</ul>
</li>
<li><p><strong>작업 대기열 (Task Queue)</strong>  </p>
<ul>
<li>순차적으로 실행해야 하는 작업을 저장하는 큐  </li>
<li>예: 웹 요청 처리 순서, 비동기 이벤트 큐  </li>
</ul>
</li>
<li><p><strong>Producer-Consumer 패턴</strong>  </p>
<ul>
<li>멀티스레드 환경에서 BlockingQueue로 안전하게 데이터 전달  </li>
<li>예: 로그 수집, 메시지 큐 시스템 구현  </li>
</ul>
</li>
</ul>
<hr>
<h3 id="☑️-priorityqueue">☑️ PriorityQueue</h3>
<ul>
<li><p><strong>다익스트라 알고리즘 (최단 경로)</strong>  </p>
<ul>
<li>거리가 가장 짧은 노드를 우선 처리해야 하므로  </li>
<li>우선순위 큐를 사용해 O(log n)으로 꺼낼 수 있음  </li>
</ul>
</li>
<li><p><strong>힙 정렬 (Heap Sort)</strong>  </p>
<ul>
<li>PriorityQueue에 모두 넣고 하나씩 꺼내면 자동 정렬  </li>
<li>최대 힙: 내림차순 정렬, 최소 힙: 오름차순 정렬  </li>
</ul>
</li>
<li><p><strong>시뮬레이션 문제 (우선순위 처리)</strong>  </p>
<ul>
<li>예: 응급환자 먼저 처리, 문서 인쇄 순서, CPU 스케줄링 등  </li>
<li>값 외에도 우선순위를 정의하고 <code>Comparator</code>로 커스터마이징 가능  </li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 얕은 복사(Shallow Copy) vs 깊은 복사(Deep Copy)]]></title>
            <link>https://velog.io/@cheon-eunjeong/Java-%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%ACShallow-Copy-vs-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%ACDeep-Copy</link>
            <guid>https://velog.io/@cheon-eunjeong/Java-%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%ACShallow-Copy-vs-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%ACDeep-Copy</guid>
            <pubDate>Thu, 27 Mar 2025 05:06:23 GMT</pubDate>
            <description><![CDATA[<p>Java에서 <strong>복사</strong> 가 어떻게 작동하는지 이해하려면,
먼저 변수와 객체가 <strong>메모리 상에 어떻게 저장</strong> 되는지부터 알아야 한다.</p>
<h2 id="☑️-jvm-runtime-data-areas">☑️ <strong>JVM Runtime Data Areas</strong></h2>
<ul>
<li><strong>PC Register</strong>: 각 스레드의 현재 실행 중인 명령어의 주소 저장</li>
<li><strong>JVM Stacks</strong>: 각 스레드의 메서드 호출 시 생성되는 프레임, 지역 변수, <strong>참조 변수 주소</strong> 저장</li>
<li><strong>Heap</strong>: new로 생성된 <strong>실제 객체 인스턴스와 배열</strong> 저장 (GC가 관리)</li>
<li><strong>Method Area</strong>: 클래스 정보, static 변수, 메서드 코드 저장</li>
<li><strong>Run-Time Constant Pool</strong>: 클래스 로딩 시 생성되는 상수 테이블</li>
<li><strong>Native Method Stack</strong>: C/C++ 네이티브 코드 실행 위한 공간</li>
</ul>
<p>여기서 <strong>복사</strong>와 가장 밀접한 부분은 <code>스택(Stack)</code>과 <code>힙(Heap)</code>이다.</p>
<p><code>스택</code>에는 <strong>객체의 참조값(주소)</strong>이 저장되고,<br><code>힙</code>에는 <strong>new로 생성한 실제 객체 인스턴스</strong>가 저장된다.</p>
<blockquote>
<p>즉, JVM 메모리 공간은 <code>참조값(주소)</code> → <code>스택</code>, <code>실제 데이터</code> → <code>힙</code>에 있는 구조를 가지며 
이 구조가 바로 <strong>복사 시 어떤 값이 복사되는지를 결정하는 핵심</strong>이다.</p>
</blockquote>
<hr>
<p><strong>얕은 복사(Shallow Copy)</strong> 는 <code>스택</code>에 있는 <strong>참조값(주소값)만 복사</strong> 하여, 두 변수가 <strong>같은 힙 객체를 공유</strong> 하는 방식이고,
<strong>깊은 복사(Deep Copy)</strong> 는 <code>힙</code>에 있는 <strong>객체를 새롭게 생성</strong>해서 <code>스택</code>에 <strong>새로운 참조값을 저장</strong> 하는 방식이다.</p>
<p>아래 String 형태의 <code>name</code>과 <code>address</code>를 필드로 가지는 <code>Person</code> 클래스가 있다.</p>
<pre><code class="language-java">private static class Person {
    private String name;
    private String address;

    public Person(final String name, final String address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(final String address) {
        this.address = address;
    }
}</code></pre>
<h2 id="✔️-얕은-복사shallow-copy">✔️ 얕은 복사(Shallow Copy)</h2>
<pre><code class="language-java">Person person1 = new Person(&quot;길동&quot;, &quot;서울&quot;);
Person person2 = person1;

person2.setAddress(&quot;부산&quot;);

System.out.println(person1.address);
System.out.println(person2.address);</code></pre>
<p>이름이 &#39;길동&#39;, 주소가 &#39;서울&#39;인 <code>person1</code>을 생성한 후, <code>person1</code>을 <code>person2</code>에 복사했다.</p>
<p>그 후 <code>person2</code>의 주소를 &#39;부산&#39;으로 변경했다.</p>
<pre><code class="language-java">System.out.println(person1.address); // 부산
System.out.println(person2.address); // 부산

System.out.println(person1); // example$Person@2f7a2457
System.out.println(person2); // example$Person@2f7a2457
</code></pre>
<p><code>person2</code>의 주소만 변경했음에도 <code>person1</code>의 주소도 함께 &#39;부산&#39;으로 변경됐다. 또한, 두 객체 모두 <code>Person@2f7a2457</code>이라는 <strong>동일한 주소</strong> 를 가지고 있다는 것을 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/cheon-eunjeong/post/947f1f04-200b-4173-b9a7-dffaf4ad42fb/image.png" alt=""></p>
<p>이렇게 <strong>얕은 복사</strong>는 <strong>주소값만 복사하여 같은 객체를 공유하는 방식</strong>으로
<code>person2</code>는 새로 생성된 것이 아니라, 기존 <code>person1</code>이 가리키는 객체의 주소를 그대로 참조한다. 따라서 <code>person2</code>의 값을 변경하면, 같은 객체를 공유하는 <code>person1</code>의 값도 함께 변경된다.</p>
<blockquote>
<p>얕은 복사는 <strong>하나의 물체에 이름표만 하나 더 붙인 것</strong>이라고 생각하면 이해가 쉽다. 이름표가 늘어나도 물체는 하나뿐이기 때문에, 어떤 이름으로 접근하든 <strong>동일한 물체에 영향을 주게 되는 것</strong>이다.</p>
</blockquote>
<h2 id="✔️-깊은-복사deep-copy">✔️ 깊은 복사(Deep Copy)</h2>
<pre><code class="language-java">Person person1 = new Person(&quot;길동&quot;, &quot;서울&quot;);
Person person2 = new Person(person1.getName(), person1.getAddress());

person2.setAddress(&quot;부산&quot;);</code></pre>
<p>이번에는 <code>person1</code>을 복사할 때 <strong>새로운 Person 객체를 생성</strong>하여 <code>person2</code>에 담았다.
<code>person1</code>의 이름과 주소 값을 생성자에 전달해 새로운 Person 객체 <code>person2</code>를 만들었다.</p>
<p>그 후 이전과 동일하게 <code>person2</code>의 주소를 &#39;부산&#39;으로 변경했다.</p>
<pre><code class="language-java">System.out.println(person1.address); // 서울
System.out.println(person2.address); // 부산

System.out.println(person1); // example$Person@2f7a2457
System.out.println(person2); // example$Person@6d06d69c</code></pre>
<p>이전과 달리 <code>person1</code>의 주소는 여전히 &#39;서울&#39; 그대로이고 <code>person2</code>의 주소만 &#39;부산&#39;으로 변경됐다. 또한 두 객체가 서로 다른 주소값을 가지고 있는 것을 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/cheon-eunjeong/post/e0f71a09-626d-4855-954e-e86bc4f51217/image.png" alt=""></p>
<p>이렇게 <strong>깊은 복사(Deep Copy)</strong> 는 기존 객체의 데이터를 바탕으로 새로운 객체를 완전히 복제하여 생성하는 방식이다.
힙 메모리 상에 새로운 객체 인스턴스를 생성하고, 스택에는 해당 객체의 새로운 참조값이 저장된다. 따라서 하나의 객체를 수정해도, 다른 객체에는 전혀 영향을 주지 않는다.</p>
<blockquote>
<p>깊은 복사는 <strong>같은 설계도</strong>를 가지고 <strong>새로 물체를 하나 더 만든 것</strong>이라고 생각하면 이해가 쉽다.
외형은 같지만, 물리적으로 완전히 다른 물체이기 때문에 하나를 바꾸더라도 다른 쪽에는 영향이 전혀 없다.</p>
</blockquote>
<hr>
<ul>
<li><code>얕은 복사</code>는 <strong>참조값만 복사</strong>해서 <strong>같은 객체를 공유</strong>하는 방식</li>
<li><code>깊은 복사</code>는 <strong>새로운 객체를 생성</strong>해서 <strong>각자 독립된 객체로 관리</strong>하는 방식</li>
</ul>
<p>차이를 이해하지 못하면 의도치 않게 <strong>객체가 공유되어 값이 바뀌는 문제</strong>가 발생할 수 있다.  </p>
<p>결국 복사의 본질의, <strong>객체 간의 독립성</strong> 에 대한 문제다.</p>
<p><strong>참조값만 복사</strong>되면 하나를 바꾸면 둘 다 바뀌고, <strong>객체 자체를 복사</strong>하면 각각 독립적으로 유지된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] BigInteger로 초대형 정수 처리하기]]></title>
            <link>https://velog.io/@cheon-eunjeong/Java-%EC%B4%88%EB%8C%80%ED%98%95-%EC%A0%95%EC%88%98-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@cheon-eunjeong/Java-%EC%B4%88%EB%8C%80%ED%98%95-%EC%A0%95%EC%88%98-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 11 Feb 2025 13:55:00 GMT</pubDate>
            <description><![CDATA[<table>
<thead>
<tr>
<th>자료형</th>
<th>범위 (십진수)</th>
<th>최대 값 크기 (10ⁿ 기준)</th>
</tr>
</thead>
<tbody><tr>
<td><code>int</code></td>
<td><code>-2^31</code> ~ <code>2^31-1</code> (약 ±21억)</td>
<td>n ≤ 9 (10억 이하)</td>
</tr>
<tr>
<td><code>long</code></td>
<td><code>-2^63</code> ~ <code>2^63-1</code> (약 ±9경)</td>
<td>n ≤ 18</td>
</tr>
<tr>
<td><code>BigInteger</code></td>
<td>제한 없음 (메모리가 허용하는 한 무한대)</td>
<td>n &gt; 18</td>
</tr>
</tbody></table>
<h2 id="1-biginteger란">1. BigInteger란?</h2>
<ul>
<li>Java에서 기본 제공하는 정수형 자료형(int, long)으로 표현할 수 없는 <strong>초대형 정수</strong>를 다룰 수 있는 클래스이다</li>
<li>메모리가 허용하는 한 <strong>무한대 크기의 정수</strong>를 저장할 수 있다</li>
<li><strong>불변 객체(Immutable Object)</strong> 로 연산할 때도 기존 값이 변경되지 않고 새로운 <code>BigInteger</code> 객체가 생성된다</li>
<li><code>double</code>과 달리 정확한 정수 연산이 가능해 <strong>부동소수점 오차</strong> 가 없다</li>
<li><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code> 같은 기본 연산자 대신 <strong>메서드로 연산</strong> 해야 한다</li>
</ul>
<hr>
<h2 id="2-사용-예시">2. 사용 예시</h2>
<pre><code class="language-java">import java.math.BigInteger;

public class Main {
    public static void main(String[] args) {
        BigInteger x = new BigInteger(&quot;123456789012345678901234567890&quot;);
        System.out.println(x); // 123456789012345678901234567890
    }
}</code></pre>
<hr>
<h2 id="3-연산-메서드">3. 연산 메서드</h2>
<table>
<thead>
<tr>
<th>연산</th>
<th>메서드</th>
</tr>
</thead>
<tbody><tr>
<td>덧셈</td>
<td><code>add(BigInteger val)</code></td>
</tr>
<tr>
<td>뺄셈</td>
<td><code>subtract(BigInteger val)</code></td>
</tr>
<tr>
<td>곱셈</td>
<td><code>multiply(BigInteger val)</code></td>
</tr>
<tr>
<td>나눗셈</td>
<td><code>divide(BigInteger val)</code></td>
</tr>
<tr>
<td>나머지</td>
<td><code>mod(BigInteger val)</code></td>
</tr>
<tr>
<td>제곱</td>
<td><code>pow(int n)</code></td>
</tr>
<tr>
<td>최대공약수(GCD)</td>
<td><code>gcd(BigInteger val)</code></td>
</tr>
<tr>
<td>비교</td>
<td><code>compareTo(BigInteger val)</code></td>
</tr>
<tr>
<td>절댓값</td>
<td><code>abs()</code></td>
</tr>
</tbody></table>
<h3 id="사용-예시">사용 예시</h3>
<pre><code class="language-java">import java.math.BigInteger;

public class Main {
    public static void main(String[] args) {
        BigInteger num1 = new BigInteger(&quot;987654321987654321987654321&quot;);
        BigInteger num2 = new BigInteger(&quot;123456789123456789123456789&quot;);

        BigInteger sum = num1.add(num2);       // 덧셈
        BigInteger subtract = num1.subtract(num2); // 뺄셈
        BigInteger multiply = num1.multiply(num2); // 곱셈
        BigInteger divide = num1.divide(num2);  // 나눗셈
        BigInteger mod = num1.mod(num2);    // 나머지

        System.out.println(&quot;덧셈: &quot; + sum);
        System.out.println(&quot;뺄셈: &quot; + subtract);
        System.out.println(&quot;곱셈: &quot; + multiply);
        System.out.println(&quot;나눗셈: &quot; + divide);
        System.out.println(&quot;나머지: &quot; + mod);
    }
}</code></pre>
<h2 id="4-주요-메서드">4. 주요 메서드</h2>
<h3 id="✅-요약">✅ 요약</h3>
<table>
<thead>
<tr>
<th>주요 메소드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>compareTo(BigInteger)</code></td>
<td>두 수 크기 비교</td>
</tr>
<tr>
<td><code>gcd(BigInteger)</code></td>
<td>최대공약수(GCD) 계산</td>
</tr>
<tr>
<td><code>mod(BigInteger)</code></td>
<td>나머지 연산</td>
</tr>
<tr>
<td><code>pow(int exponent)</code></td>
<td>거듭제곱 연산</td>
</tr>
<tr>
<td><code>isProbablePrime(int)</code></td>
<td>소수 판별</td>
</tr>
<tr>
<td><code>toString(int radix)</code></td>
<td>특정 진법 문자열 변환</td>
</tr>
<tr>
<td><code>abs()</code></td>
<td>절댓값 반환</td>
</tr>
<tr>
<td><code>negate()</code></td>
<td>부호 반전</td>
</tr>
<tr>
<td><code>bitCount()</code></td>
<td>이진수의 <code>1</code> 개수 반환</td>
</tr>
</tbody></table>
<h3 id="1-comparetobiginteger-val">1. compareTo(BigInteger val)</h3>
<pre><code class="language-java">BigInteger a = new BigInteger(&quot;100&quot;);
BigInteger b = new BigInteger(&quot;200&quot;);

int result = a.compareTo(b); // 결과: -1 (a &lt; b)</code></pre>
<p><strong>설명</strong> : <code>a</code>와 <code>b</code>를 비교하여 결과를 반환<br><strong>시그니처</strong> : <code>public int compareTo(BigInteger val)</code><br><strong>매개변수</strong> : <code>val</code> - 비교할 <code>BigInteger</code> 값<br><strong>사용 상황</strong> : 두 수의 대소 비교가 필요할 때 (<code>a &lt; b</code>, <code>a &gt; b</code>, <code>a == b</code> 판단 가능)  </p>
<h3 id="2-gcdbiginteger-val">2. gcd(BigInteger val)</h3>
<pre><code class="language-java">BigInteger a = new BigInteger(&quot;48&quot;);
BigInteger b = new BigInteger(&quot;18&quot;);

BigInteger result = a.gcd(b); // 결과: 6</code></pre>
<p><strong>설명</strong> : 두 수의 <strong>최대공약수(GCD, Greatest Common Divisor)</strong> 계산<br><strong>시그니처</strong> : <code>public BigInteger gcd(BigInteger val)</code><br><strong>매개변수</strong> : <code>val</code> - 최대공약수를 구할 <code>BigInteger</code> 값<br><strong>사용 상황</strong> : 유클리드 호제법을 사용하여 최대공약수를 구할 때  </p>
<h3 id="3-modbiginteger-m">3. mod(BigInteger m)</h3>
<pre><code class="language-java">BigInteger a = new BigInteger(&quot;10&quot;);
BigInteger b = new BigInteger(&quot;3&quot;);

BigInteger result = a.mod(b); // 결과: 1</code></pre>
<p><strong>설명</strong> : <code>a</code>를 <code>b</code>로 나눈 나머지를 반환<br><strong>시그니처</strong> : <code>public BigInteger mod(BigInteger m)</code><br><strong>매개변수</strong> : <code>m</code> - 나눌 값<br><strong>사용 상황</strong> : 나머지 연산이 필요할 때 (예: 모듈러 연산, 암호학 등)  </p>
<h3 id="4-powint-exponent">4. pow(int exponent)</h3>
<pre><code class="language-java">BigInteger a = new BigInteger(&quot;2&quot;);

BigInteger result = a.pow(10); // 결과: 1024</code></pre>
<p><strong>설명</strong> : <code>a</code>의 <code>exponent</code> 거듭제곱 계산<br><strong>시그니처</strong> : <code>public BigInteger pow(int exponent)</code><br><strong>매개변수</strong> : <code>exponent</code> - 거듭제곱 할 지수<br><strong>사용 상황</strong> : 큰 수의 거듭제곱 연산이 필요할 때  </p>
<h3 id="5-isprobableprimeint-certainty">5. isProbablePrime(int certainty)</h3>
<pre><code class="language-java">BigInteger a = new BigInteger(&quot;17&quot;);

boolean isPrime = a.isProbablePrime(10); // 결과: true</code></pre>
<p><strong>설명</strong> : 주어진 숫자가 <strong>소수인지 확률적으로 판별</strong><br><strong>시그니처</strong> : <code>public boolean isProbablePrime(int certainty)</code><br><strong>매개변수</strong> : <code>certainty</code> - 소수 판별 신뢰도 (값이 클수록 정확함)<br><strong>사용 상황</strong> : 암호학, 소수 판별 문제 등  </p>
<h3 id="6-tostringint-radix">6. toString(int radix)</h3>
<pre><code class="language-java">BigInteger a = new BigInteger(&quot;255&quot;);

String binaryStr = a.toString(2); // 결과: &quot;11111111&quot;
String hexStr = a.toString(16);   // 결과: &quot;ff&quot;</code></pre>
<p><strong>설명</strong> : <code>BigInteger</code>를 특정 진법(2진수, 16진수 등) 문자열로 변환<br><strong>시그니처</strong> : <code>public String toString(int radix)</code><br><strong>매개변수</strong> : <code>radix</code> - 변환할 진법 (예: 2, 8, 16 등)<br><strong>사용 상황</strong> : 숫자를 <strong>이진수, 16진수 등으로 변환할 때</strong>  </p>
<h3 id="7-abs">7. abs()</h3>
<pre><code class="language-java">BigInteger a = new BigInteger(&quot;-100&quot;);

BigInteger absNum = a.abs(); // 결과: 100</code></pre>
<p><strong>설명</strong> : <code>BigInteger</code>의 <strong>절댓값</strong>을 반환<br><strong>시그니처</strong> : <code>public BigInteger abs()</code><br><strong>매개변수</strong> : 없음<br><strong>사용 상황</strong> : 음수를 양수로 변환할 때  </p>
<h3 id="8-negate">8. negate()</h3>
<pre><code class="language-java">BigInteger a = new BigInteger(&quot;100&quot;);

BigInteger negNum = a.negate(); // 결과: -100</code></pre>
<p><strong>설명</strong> : <code>BigInteger</code>의 부호를 반전 (양수 → 음수, 음수 → 양수)<br><strong>시그니처</strong> : <code>public BigInteger negate()</code><br><strong>매개변수</strong> : 없음<br><strong>사용 상황</strong> : 부호를 바꿔야 할 때  </p>
<h3 id="9-bitcount">9. bitCount()</h3>
<pre><code class="language-java">BigInteger a = new BigInteger(&quot;15&quot;); // 1111 (2진수)

int count = a.bitCount(); // 결과: 4</code></pre>
<p><strong>설명</strong> : <code>BigInteger</code>의 <strong>이진수 표현에서 1의 개수</strong> 반환<br><strong>시그니처</strong> : <code>public int bitCount()</code><br><strong>매개변수</strong> : 없음<br><strong>사용 상황</strong> : 이진수 내 <code>1</code>의 개수를 셀 때 (비트마스킹 활용 가능)  </p>
<blockquote>
<h2 id="️-주의할-점">‼️ 주의할 점</h2>
</blockquote>
<ul>
<li>연산할 때마다 <strong>새로운 객체가 생성</strong> 됨 → <strong>연산이 많으면 성능이 저하</strong> 될 수 있다</li>
<li><strong>소수점</strong> 이 필요하면 <code>BigDecimal</code>을 사용해야 한다</li>
<li><code>toString()</code>을 사용하여 출력해야 제대로 된 값을 확인할 수 있다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Java에서 날짜와 시간 처리하기]]></title>
            <link>https://velog.io/@cheon-eunjeong/Java-Java-%EB%82%A0%EC%A7%9C-%EC%8B%9C%EA%B0%84-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@cheon-eunjeong/Java-Java-%EB%82%A0%EC%A7%9C-%EC%8B%9C%EA%B0%84-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Tue, 19 Nov 2024 13:41:12 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Java는 초기부터 날짜와 시간을 다루는 다양한 API를 제공해왔다. 하지만 이런 API들은 사용하기에 여러 불편점과 문제점이 있었다. 이런 불편점들을 점차 보완한 뒤 <strong>Java 8</strong>부터 <code>java.time</code> 패키지가 도입되어 현대적인 날짜와 시간 처리가 가능해졌다 .</p>
</blockquote>
<h2 id="1-java-8-이전의-api들">1. Java 8 이전의 API들</h2>
<h3 id="11-javautildate">1.1 Java.util.Date</h3>
<p>가장 먼저 등장한 클래스는 <code>java.util.Date</code>로 <strong>Java 1.0</strong>부터 도입되었다. 하지만 여러가지 단점이 존재했다.</p>
<ul>
<li><strong>가변 객체</strong>로 설계되어 멀티스레드 환경에서 안전하지 않다.</li>
<li>월(Month)이 0부터 시작하는 비직관적인 설계로 혼란을 유발할 수 있다.</li>
<li>시간대(Time Zone) 처리 기능이 부족하여 글로벌 애플리케이션 개발에 한계가 있다.</li>
</ul>
<h3 id="12-javautilcalendar">1.2 Java.util.Calendar</h3>
<p>이러한 문제를 개선하기 위해 <strong>Java 1.1</strong>부터 도입된 <code>java.util.Calendar</code> 클래스는 다양한 캘린더 시스템을 지원하며, <code>Date</code> 클래스의 단점을 보완하려 했으나 여전히 몇 가지 단점이 남아있었다.</p>
<ul>
<li>여전히 <strong>가변 객체</strong>로 설계되어 멀티스레드 환경에서 안전하지 않다.</li>
<li>복잡한 API 설계로 인해 사용하기 어려웠다.</li>
</ul>
<hr>
<h2 id="2-java-8-이후-javatime-패키지">2. Java 8 이후: java.time 패키지</h2>
<p><strong>Java 8</strong>에서는 이러한 문제를 해결하기 위해 <code>java.time</code> 패키지가 도입다. 
이 패키지는 <em>JSR-310</em> 명세를 기반으로 설계되었으며, _Modern Date-Time API_로 불리며 현재 Java에서 날짜와 시간을 처리하는 표준으로 자리잡았다. </p>
<h3 id="21-javatime-패키지의-주요-특징">2.1 java.time 패키지의 주요 특징</h3>
<ol>
<li><p><strong>불변 객체와 Thread-Safe</strong>
<code>java.time</code>의 모든 클래스는 불변(Immutable) 객체로 설계되어 멀티스레드 환경에서도 안전하게 사용할 수 있다.</p>
</li>
<li><p><strong>직관적이고 간단한 API</strong>
클래스와 메서드 이름이 직관적이어서 쉽게 이해하고 사용할 수 있다.</p>
<ul>
<li>예: <code>LocalDate</code>(날짜), <code>LocalTime</code>(시간), <code>LocalDateTime</code>(날짜와 시간), <code>ZonedDateTime</code>(시간대 포함).</li>
</ul>
</li>
<li><p><strong>시간대(Time Zone) 지원</strong>
글로벌 애플리케이션 개발에 유용한 시간대 처리 기능을 제공한다. <code>ZoneId</code>와 <code>ZonedDateTime</code> 클래스를 통해 명확한 시간대 처리가 가능해졌다.</p>
</li>
<li><p><strong>편리한 날짜와 시간 계산</strong>
<code>plusDays()</code>, <code>minusMonths()</code> 과 같이 직관적인 메서드를 사용해 간단하게 날짜와 시간을 계산할 수 있게 되었다.</p>
</li>
<li><p><strong>포맷팅과 파싱</strong>
<code>DateTimeFormatter</code> 클래스를 사용하여 날짜와 시간을 간단하고 안전하게 포맷하거나 파싱할 수 있다.</p>
</li>
<li><p><strong>다양한 목적의 클래스</strong>
특정 목적에 맞는 클래스를 제공하여 더 명확하고 효과적인 코드를 작성할 수 있다.</p>
<ul>
<li><code>LocalDate</code>: 날짜만 필요할 때</li>
<li><code>LocalTime</code>: 시간만 필요할 때</li>
<li><code>LocalDateTime</code>: 날짜와 시간을 함께 다룰 때</li>
<li><code>Instant</code>: UTC 기준 타임스탬프 표현</li>
</ul>
</li>
</ol>
<h3 id="22-사용-예시">2.2 사용 예시</h3>
<pre><code class="language-java">import java.time.*;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        // 현재 날짜와 시간
        LocalDate date = LocalDate.now();                 // 2024-11-19
        LocalTime time = LocalTime.now();                 // 21:53:07.250832
        LocalDateTime dateTime = LocalDateTime.now();    // 2024-11-19T21:53:07.250857

        // 날짜 계산
        LocalDate nextWeek = date.plusWeeks(1);
        System.out.println(&quot;오늘: &quot; + date);            // 오늘: 2024-11-19
        System.out.println(&quot;1주 후: &quot; + nextWeek);    // 1주 후: 2024-11-26

        // 포맷팅
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd HH:mm:ss&quot;);
        String formattedDate = dateTime.format(formatter);
        System.out.println(&quot;formattedDate);    // 2024-11-19 21:53:07

        // 시간대 포함
        ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of(&quot;Asia/Seoul&quot;));
        System.out.println(&quot;zonedDateTime); 
        // 2024-11-19T21:53:07.281712+09:00[Asia/Seoul]
    }
}</code></pre>
<h3 id="23-주요-클래스">2.3 주요 클래스</h3>
<table>
<thead>
<tr>
<th>클래스</th>
<th>설명</th>
<th>예시 값</th>
</tr>
</thead>
<tbody><tr>
<td><code>LocalDate</code></td>
<td>날짜만 처리 (시간 없음)</td>
<td><code>2024-11-19</code></td>
</tr>
<tr>
<td><code>LocalTime</code></td>
<td>시간만 처리 (날짜 없음)</td>
<td><code>14:30:15</code></td>
</tr>
<tr>
<td><code>LocalDateTime</code></td>
<td>날짜와 시간 모두 처리</td>
<td><code>2024-11-19T14:30:15</code></td>
</tr>
<tr>
<td><code>ZonedDateTime</code></td>
<td>날짜와 시간 + 시간대 정보 포함</td>
<td><code>2024-11-19T14:30:15+09:00[Asia/Seoul]</code></td>
</tr>
<tr>
<td><code>Instant</code></td>
<td>UTC 기준 타임스탬프 (초/나노초 단위)</td>
<td><code>2024-11-19T05:30:15Z</code></td>
</tr>
<tr>
<td><code>Duration</code></td>
<td>두 시간 간의 차이 (초/나노초 단위)</td>
<td><code>PT2H30M</code> (2시간 30분)</td>
</tr>
<tr>
<td><code>Period</code></td>
<td>두 날짜 간의 차이 (연도, 월, 일 단위)</td>
<td><code>P1Y2M10D</code> (1년 2개월 10일)</td>
</tr>
</tbody></table>
<hr>
<h3 id="24-주요-메서드">2.4 주요 메서드</h3>
<pre><code class="language-java">// 현재 날짜 및 시간 가져오기
LocalDate.now();        // 현재 날짜
LocalTime.now();        // 현재 시간
LocalDateTime.now();    // 현재 날짜와 시간
ZonedDateTime.now();    // 현재 날짜와 시간 (시간대 포함)

// 날짜 계산
LocalDate today = LocalDate.now();
today.plusDays(5);       // 5일 추가
today.minusMonths(1);    // 1개월 빼기

// 비교
LocalDate date1 = LocalDate.of(2023, 1, 1);
LocalDate date2 = LocalDate.of(2024, 1, 1);
boolean isBefore = date1.isBefore(date2); // true
boolean isAfter = date1.isAfter(date2);   // false

// 포맷팅
LocalDate date = LocalDate.now();
String formatted = date.format(DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd&quot;));

// 파싱
LocalDate parsedDate = LocalDate.parse(&quot;2024-01-01&quot;, DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd&quot;));</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 스프링 입문 강의 정리 #2]]></title>
            <link>https://velog.io/@cheon-eunjeong/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EA%B0%95%EC%9D%98-%EC%A0%95%EB%A6%AC-2</link>
            <guid>https://velog.io/@cheon-eunjeong/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EA%B0%95%EC%9D%98-%EC%A0%95%EB%A6%AC-2</guid>
            <pubDate>Wed, 30 Oct 2024 15:29:48 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><em>인프런 김영한 님의 <a href="https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8?srsltid=AfmBOopJL-Tlxg25xYeclNRo6Hy27V_2GNpXs__REMpG-aTZa5M1lLvP">스프링 입문 - 코드로 배우는 스프링 부트, 웹, MVC, DB 접근 기술</a> 강의를 보고 정리한 내용입니다.</em></p>
</blockquote>
<hr>
<p>웹 개발은 크게 3가지 방식으로 볼 수 있다.</p>
<ol>
<li>정적 컨텐츠 (파일을 그대로 웹 브라우저에 전달)</li>
<li>MVC와 템플릿 엔진 (서버에서 변형을 해서 전달)</li>
<li>API (json 전달, 서버끼리 통신, …)</li>
</ol>
<hr>
<h1 id="1-정적-컨텐츠">1. 정적 컨텐츠</h1>
<ul>
<li>스프링 부트는 정적 컨텐츠 기능을 자동으로 제공한다.</li>
<li>원하는 html을 추가하면 그대로 view로 출력된다.</li>
</ul>
<h2 id="정적-컨텐츠란-">정적 컨텐츠란 ?</h2>
<ul>
<li><p><a href="https://docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/html/spring-boot-features.html#boot-features-spring-mvc-static-content!%5B%5D(https://velog.velcdn.com/images/cheon-eunjeong/post/af75cf57-4977-4066-90bf-99b7f690fe88/image.png)">Spring.io 링크</a></p>
</li>
<li><p>스프링 부트는 기본적으로 <code>/static</code>(<code>/public</code>, <code>/resources</code>, <code>/META-INF/resources</code>) 경로로부터 정적 콘텐츠 기능을 제공한다.</p>
</li>
<li><p>Spring MVC의 <code>ResourceHttpRequestHandler</code>를 사용하여 정적 리소스를 처리하고, <code>ebMvcConfigurer</code>를 추가해 <code>addResourceHandlers</code> 메서드를 오버라이드하여 동작을 수정할 수 있다.</p>
</li>
<li><p>독립 실행형 web application에서는 기본 서블릿이 활성화되어, 스프링이 요청을 처리하지 않을 경우 <code>ServletContext</code> 의 루트에서 콘텐츠를 제공하지만, 대부분의 경우 스프링이 <code>DispatcherServlet</code>을 통해 모든 요청을 처리한다.</p>
</li>
<li><p>기본적으로 정적 리소스는 <code>/**</code> 경로에 매핑되고, <code>properties</code>에 <code>spring.mvc.static-path-pattern</code> 속성을 사용해 경로를 지정할 수 있다.</p>
<pre><code class="language-java">  spring.mvc.static-path-pattern=/resources/**</code></pre>
</li>
<li><p><code>properties</code>에 <code>spring.resources.static-locations</code> 속성을 사용해 정적 리소스 위치를 커스터마이징할 수 있다.</p>
</li>
</ul>
<h2 id="동작-환경-그림">동작 환경 그림</h2>
<p><img src="https://velog.velcdn.com/images/cheon-eunjeong/post/e1f144b1-b041-4b68-9304-49fda7b6c209/image.png" alt=""></p>
<ol>
<li>웹 브라우저에서 <a href="http://localhost:8080/hello-static.html">localhost:8080/hello-static.html</a> 요청</li>
<li>톰캣 서버가 이 요청을 받아 스프링 컨테이너로 전달</li>
<li>스프링 컨테이너는 해당 요청에 대한 컨트롤러가 있는지 먼저 확인</li>
<li>없을 경우, 스프링 부트가 <code>resources/static</code> 경로에서 <code>hello-static.html</code> 파일을 찾음</li>
<li>파일이 존재하면 해당 정적 컨텐츠 반환</li>
</ol>
<hr>
<h1 id="2-mvc와-템플릿-엔진">2. MVC와 템플릿 엔진</h1>
<blockquote>
<p>MVC: Model, View, Controller</p>
</blockquote>
<ul>
<li>View: 화면을 그리는데 모든 역량을 집중</li>
<li>Controller, Model: 비즈니스 로직, 내부적 처리에 집중</li>
</ul>
<h2 id="동작-환경-그림-1">동작 환경 그림</h2>
<p><img src="https://velog.velcdn.com/images/cheon-eunjeong/post/7e652cd3-ae33-40de-8208-65b507244e8c/image.png" alt=""></p>
<ol>
<li>웹 브라우저에서 <a href="http://localhost:8080/hello-mvc?name=spring">http://localhost:8080/hello-mvc?name=spring</a> 요청</li>
<li>톰캣 서버가 이 요청을 받아 스프링 컨테이너로 전달</li>
<li>스프링 컨테이너는 해당 요청에 대한 컨트롤러가 있는지 확인 후 해당 요청에 대한 메서드 호출</li>
<li>내부 메서드 실행<ol>
<li><code>@RequestParam</code> 값이 있는지 확인<strong>(required = true가 기본값이라)</strong></li>
<li>없을 경우, <code>MissingServletRequestParameterException</code> 반환</li>
<li><code>Model</code>에 <code>RequestParam</code>으로 받은 값 추가 후 반환</li>
</ol>
</li>
<li><code>ViewResolver</code> (뷰를 찾아주고 템플릿 엔진 연결) 스프링 부트가 <code>resources/tempaltes</code> 경로에서 return의 StringName(ViewName) 파일을 찾음</li>
<li>Thymeleaf 템플릿 엔진에게 처리 요청</li>
<li>Thymeleaf 템플릿 엔진이 <strong>렌더링 후 변환된 HTML</strong>을 웹 브라우저에 반환</li>
</ol>
<hr>
<h1 id="3-api">3. API</h1>
<h2 id="responsebody-문자-반환">@ResponseBody 문자 반환</h2>
<pre><code class="language-java">@GetMapping(&quot;hello-string&quot;)
@ResponseBody // http body에 데이터를 직접 넣겠다
public String helloString(@RequestParam(&quot;name&quot;) String name) {
    return &quot;hello &quot; + name;
}</code></pre>
<ul>
<li><p><code>@ResponseBody</code> 를 사용하면 <code>ViewResolver</code>를 사용하지 않음</p>
</li>
<li><p>대신에 <strong>HTTP의 body에 문자 내용을 직접 반환</strong>(HTML body tag를 말하는 것이 아님)</p>
</li>
<li><p><strong>실행 결과</strong></p>
<p>  <img src="https://velog.velcdn.com/images/cheon-eunjeong/post/100d1b58-64ab-45c2-90e0-214e1d70c243/image.png" alt=""></p>
</li>
</ul>
<h2 id="responsebody-객체-반환">@ResponseBody 객체 반환</h2>
<pre><code class="language-java">@GetMapping(&quot;hello-api&quot;)
@ResponseBody
public Hello helloApi(@RequestParam(&quot;name&quot;) String name) {
    Hello hello = new Hello();
    hello.setName(name);
    return hello;
}
static class Hello {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}</code></pre>
<ul>
<li><code>@ResponseBody</code> 를 사용하고, 객체를 반환하면 객체가 JSON으로 변환됨</li>
<li><strong>실행 결과</strong>
<img src="https://velog.velcdn.com/images/cheon-eunjeong/post/157b8f0b-c078-4d9e-a24c-b05600a145f1/image.png" alt=""></li>
</ul>
<h2 id="동작-환경-그림-2">동작 환경 그림</h2>
<p><img src="https://velog.velcdn.com/images/cheon-eunjeong/post/88968390-06dd-47d8-9f62-80685df9a2e7/image.png" alt=""></p>
<ol>
<li>웹 브라우저에서 <a href="http://localhost:8080/hello-api?name=spring">http://localhost:8080/hello-api?name=spring</a> 요청</li>
<li>톰캣 서버가 이 요청을 받아 스프링 컨테이너로 전달</li>
<li>스프링 컨테이너는 해당 요청에 대한 컨트롤러가 있는지 확인 후 해당 요청에 대한 메서드 호출</li>
<li><code>@ResponseBody</code> Annotation을 확인</li>
<li><code>HttpMessageConverter</code>가 작동<ol>
<li>문자일 경우, <code>StringConverter</code>(StringHttpMessageConverter)가 return String Value 그대로 </li>
<li>객체일 경우, <code>JsonConverter</code>(MappingJackson2HttpMessageConverter)가 객체를 json 형식의 데이터로 만듬</li>
</ol>
</li>
<li>HTTP Body로 반환</li>
</ol>
<ul>
<li><code>@ResponseBody</code> 를 사용<ul>
<li>HTTP의 BODY에 문자 내용을 직접 반환</li>
<li><code>viewResolver</code> 대신에 <code>HttpMessageConverter</code>가 동작</li>
<li>기본 문자처리: <code>StringHttpMessageConverter</code></li>
<li>기본 객체처리: <code>MappingJackson2HttpMessageConverter</code></li>
<li>byte 처리 등등 기타 여러 HttpMessageConverter가 기본으로 등록되어 있음</li>
</ul>
</li>
</ul>
<blockquote>
<p>💡 Jackson: 범용적으로 사용되는 객체 → json 스타일 변환 라이브러리</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 스프링 입문 강의 정리 #1]]></title>
            <link>https://velog.io/@cheon-eunjeong/JavaSpring-%EA%B9%80%EC%98%81%ED%95%9C-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EA%B0%95%EC%9D%98-1</link>
            <guid>https://velog.io/@cheon-eunjeong/JavaSpring-%EA%B9%80%EC%98%81%ED%95%9C-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EA%B0%95%EC%9D%98-1</guid>
            <pubDate>Wed, 30 Oct 2024 15:01:34 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><em>인프런 김영한 님의 <a href="https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8?srsltid=AfmBOopJL-Tlxg25xYeclNRo6Hy27V_2GNpXs__REMpG-aTZa5M1lLvP">스프링 입문 - 코드로 배우는 스프링 부트, 웹, MVC, DB 접근 기술</a> 강의를 보고 정리한 내용입니다.</em></p>
</blockquote>
<hr>
<h1 id="1-프로젝트-생성">1. 프로젝트 생성</h1>
<h2 id="프로젝트-생성">프로젝트 생성</h2>
<ol>
<li><p>Java 설치 필수 → oracle jdk (원하는 버전) 검색 후 다운로드</p>
</li>
<li><p>스프링 부트 스타터 사이트에서 스프링 프로젝트 생성</p>
<ul>
<li><a href="https://start.spring.io">https://start.spring.io</a></li>
<li>스프링에서 운영하는 스프링 부트 기반으로 스프링 관련 프로젝트를 생성해주는 사이트</li>
</ul>
</li>
<li><p>프로젝트 선택</p>
<ul>
<li>Gradle(요즘 추세, 스프링 라이브러리 관리 자체도  넘어오는 추세)</li>
<li>Java</li>
<li>Spring Boot Version<ul>
<li>원하는 버전 선택 (SNAPSHOT이 아닌 제일 최근 버전)</li>
</ul>
</li>
<li>Project Metadata<ul>
<li>Group : 기업명, 기업 도메인 명</li>
<li>Artifact : build 나올 때 결과물, 프로젝트 명</li>
<li>Name</li>
<li>Description</li>
<li>Package name</li>
</ul>
</li>
<li>Dependencies<ul>
<li>Spring Web</li>
<li>Thymeleaf : html을 만들어주는 템플릿 엔진</li>
</ul>
</li>
</ul>
</li>
<li><p>다운로드 → intellij open → 다운로드 한 파일의 build.gradle 선택 → open as project</p>
</li>
</ol>
<blockquote>
<p>💡 gradle build가 안될 때</p>
</blockquote>
<ol>
<li>⌘; (File → Project structure) Project의 SDK 버전 다운로드 받은 파일의 버전과 같이 변경</li>
<li>⌘, (Intellij → Settings → Build, Execution, Deployment → Build tools → Gradle) gradle JVM 버전 다운로드 받은 파일의 버전과 같이 변경</li>
</ol>
<h2 id="프로젝트-구조">프로젝트 구조</h2>
<ul>
<li><p>.idea (intellij가 사용하는 설정 파일)</p>
</li>
<li><p>gradle (gradle 관련 파일)</p>
</li>
<li><p>src</p>
<ul>
<li><p>main</p>
<ul>
<li>java</li>
<li>resources (실제 Java 코드 파일을 제외한 xml이나 propertices 설정 파일, html …)</li>
</ul>
</li>
<li><p>test (테스트 코드들)</p>
</li>
<li><p>build.gradle (gradle 설정 파일, 버전 설정하고 라이브러리 땡겨오기)</p>
<pre><code class="language-java">  plugins {  // 버전 관련
      id &#39;java&#39;
      id &#39;org.springframework.boot&#39; version &#39;3.3.5&#39;
      id &#39;io.spring.dependency-management&#39; version &#39;1.1.6&#39;
  }

  group = &#39;hello&#39;
  version = &#39;0.0.1-SNAPSHOT&#39;

  java { // java 버전
      toolchain {
          languageVersion = JavaLanguageVersion.of(17)
      }
  }

  repositories { // 라이브러리를 여기서 다운받아라 라고 설정해두는,,
      mavenCentral()
  }

  dependencies { //라이브러리
      implementation &#39;org.springframework.boot:spring-boot-starter-thymeleaf&#39;
      implementation &#39;org.springframework.boot:spring-boot-starter-web&#39;
      testImplementation &#39;org.springframework.boot:spring-boot-starter-test&#39;
      testRuntimeOnly &#39;org.junit.platform:junit-platform-launcher&#39;
  }

  tasks.named(&#39;test&#39;) {
      useJUnitPlatform()
  }
</code></pre>
</li>
<li><p>.gitignore (git에 올라가면 안되는 파일 관리)</p>
</li>
<li><p>gradlew</p>
</li>
<li><p>gradlew.bat</p>
</li>
<li><p>settings.gradle</p>
</li>
</ul>
</li>
</ul>
<hr>
<h1 id="2-라이브러리-환경-살펴보기">2. 라이브러리 환경 살펴보기</h1>
<h2 id="라이브러리-살펴보기">라이브러리 살펴보기</h2>
<ul>
<li><code>Gradle</code>이 프로젝트를 시작할 때 선택한 <strong>라이브러리와 의존 관계가 있는 라이브러리를 함께 다운로드</strong> 한다.</li>
<li>Intellij의 왼쪽 <code>Gradle</code> 버튼을 클릭하면 라이브러리 간의 의존 관계로 함께 당겨와진 라이브러리들을 확인할 수 있다.</li>
</ul>
<h2 id="주요-라이브러리">주요 라이브러리</h2>
<h3 id="스프링-부트-라이브러리">스프링 부트 라이브러리</h3>
<ul>
<li>spring-boot-starter-web<ul>
<li>spring-boot-starter-tomcat: 톰캣(웹 서버)</li>
<li>spring-webmvc: 스프링 웹 MVC</li>
</ul>
</li>
<li>spring-boot-starter-thymeleaf: 타임리프 템플릿 엔진(View)</li>
<li>spring-boot-starter(공통): 스프링 부트 + 스프링 코어 + 로깅<ul>
<li>spring-boot<ul>
<li>spring-core</li>
</ul>
</li>
<li>spring-boot-starter-logging<ul>
<li>slf4j, logback</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="테스트-라이브러리">테스트 라이브러리</h3>
<ul>
<li>spring-boot-starter-test<ul>
<li>junit: 테스트 프레임워크</li>
<li>mockito: 목 라이브러리</li>
<li>assertj: 테스트 코드를 좀 더 편하게 작성하게 도와주는 라이브러리</li>
<li>spring-test: 스프링 통합 테스트 지원</li>
</ul>
</li>
</ul>
<hr>
<h1 id="3-view-환경-설정">3. View 환경 설정</h1>
<h2 id="welcome-page-만들기">Welcome Page 만들기</h2>
<h3 id="1-정적-페이지">1. 정적 페이지</h3>
<ul>
<li><code>resources/static</code> 경로에 <code>index.html</code> 생성<ul>
<li><strong>홈 화면(Welcome 페이지)</strong>가 된다.</li>
</ul>
</li>
</ul>
<ul>
<li>스프링 부트가 제공하는 Welcome Page 기능 → <a href="https://docs.spring.io/spring-boot/reference/web/servlet.html#web.servlet.spring-mvc.welcome-page">Spring.io Welcome Page 설명</a><ul>
<li><code>static/index.html</code> 을 올려두면 <strong>Welcome page</strong> 기능을 제공한다.</li>
<li>Spring Boot는 정적 및 템플릿 기반의 Welcome Page를 지원한다.<ol>
<li>Spring Boot는 먼저 <code>index.html</code> 파일을 미리 설정된 위치 (<code>resources/static</code>)에서 찾는다.</li>
<li>만약 정적 페이지를 찾지 못하면, 템플릿 엔진(Thymeleaf, Mustache 등)이 사용할 수 있는 <code>index</code> 템플릿을 찾는다.</li>
</ol>
</li>
<li>이 중 하나라도 찾게 되면, 해당 파일이 Application의 <strong>Welcome Page로 설정</strong>된다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>💡 Welcome Page는 Application에 실제로 <code>index</code> 의 <strong>경로가 정의되어 있지 않을 경우</strong>에만 동작한다.
→ Application이 <code>index</code> 라는 경로에 (ex: <code>/index</code>, <code>/</code>)에 대한 명시적인 라우트(route)를 가지고 있다면, 그 라우트가 우선 사용된다. 
없을 경우 index.html 파일이나 index 템플릿을 찾아 Welcome Page로 사용한다.</p>
</blockquote>
<h3 id="2-thymleaf-템플릿-엔진">2. thymleaf 템플릿 엔진</h3>
<blockquote>
<p>thymeleaf 공식 사이트: <a href="https://www.thymeleaf.org/">https://www.thymeleaf.org/</a>
스프링 공식 튜토리얼: <a href="https://spring.io/guides/gs/serving-web-content/">https://spring.io/guides/gs/serving-web-content/</a>
스프링부트 메뉴얼: <a href="https://docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/html/spring-boot-features.html#boot-features-spring-mvc-template-engines">https://docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/html/spring-boot-features.html#boot-features-spring-mvc-template-engines</a></p>
</blockquote>
<h4 id="특징">특징</h4>
<ul>
<li><strong>Thymeleaf</strong>는 자바 기반의 <strong>server-side</strong> 템플릿 엔진으로, HTML, XML, JavaScript, CSS 등의 파일을 서버에서 동적으로 생성하여 클라이언트에 전송할 수 있게 도와준다.</li>
<li>주로 <strong>Spring Boot</strong>와 함께 사용되며, HTML 파일을 템플릿으로 사용하여 데이터 바인딩, 루프 처리, 조건부 렌더링 등을 쉽게 처리할 수 있다.</li>
</ul>
<h4 id="주요-개념">주요 개념</h4>
<ol>
<li><strong>템플릿 엔진</strong>: HTML 문서에서 동적으로 데이터를 삽입하고, 반복 처리나 조건문을 적용할 수 있게 해주는 엔진이다.</li>
<li><strong>스프링과의 통합</strong>: Thymeleaf는 Spring MVC와 통합되어, <code>Model</code> 객체에 담긴 데이터를 템플릿으로 쉽게 전달할 수 있다 (Spring Boot에서는 기본 템플릿 엔진으로 Thymeleaf가 설정되어 있어 쉽게 사용할 수 있음)</li>
<li><strong>표현식</strong>:<ul>
<li><code>${}</code>: 모델에 있는 데이터를 출력할 때 사용 (예: <code>&lt;span&gt;${user.name}&lt;/span&gt;</code>).</li>
<li><code>th:if</code>, <code>th:each</code>: 조건문과 반복문을 HTML 안에서 처리할 수 있게 해줌 (예: <code>&lt;li th:each=&quot;item : ${items}&quot;&gt;${item.name}&lt;/li&gt;</code>).</li>
</ul>
</li>
</ol>
<h4 id="동작-환경-그림">동작 환경 그림</h4>
<p><img src="https://velog.velcdn.com/images/cheon-eunjeong/post/d315adc4-5d46-40d2-932c-0666cf68659d/image.png" alt="동작 환경 그림"></p>
<ol>
<li><strong>Spring Boot는 내장 톰캣 서버를 포함하고 있다.</strong><ul>
<li>Spring Boot 애플리케이션을 실행하면, 내장된 톰캣 서버가 함께 시작되어 HTTP 요청을 수신하고 처리할 수 있다.</li>
</ul>
</li>
<li><strong>웹 브라우저에서</strong> <code>localhost:8080/hello</code> <strong>입력</strong><ul>
<li>사용자가 브라우저를 통해 <code>http://localhost:8080/hello</code>로 접근하면 해당 요청이 애플리케이션으로 전달된다.</li>
</ul>
</li>
<li><strong>요청이 톰캣 서버로 전달됨</strong><ul>
<li>내장 톰캣 서버가 이 요청을 받고, 스프링 컨테이너에 요청을 전달한다.</li>
</ul>
</li>
<li><strong>스프링 컨테이너가</strong> <code>/hello</code> <strong>경로에 매핑된 메서드가 있는지 확인</strong></li>
<li><strong>매핑된 메서드 실행</strong><ul>
<li><strong>모델 생성</strong>: 메서드 내에서 Model 객체가 생성된다.</li>
<li><strong>모델에 데이터 추가 (</strong><code>addAttribute</code><strong>)</strong></li>
<li><strong>ViewName 반환 (</strong><code>return</code><strong>)</strong>: 메서드는 &quot;hello&quot;라는 View 이름을 반환한다. Spring Boot는 이 이름을 사용해 특정 HTML 파일을 찾는다.</li>
</ul>
</li>
<li><strong>ViewResolver가 View를 찾아 렌더링</strong><ul>
<li>기본적으로 Spring Boot는 <code>resources/templates</code> 경로의 ViewName을 찾아서 렌더링 한다.</li>
<li><code>resources:templates/</code> + {ViewName} + <code>.html</code></li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] StringBuilder 사용법 및 주요 메소드]]></title>
            <link>https://velog.io/@cheon-eunjeong/Java-StringBuilder-%EC%82%AC%EC%9A%A9%EB%B2%95-%EB%B0%8F-%EC%A3%BC%EC%9A%94-%EB%A9%94%EC%86%8C%EB%93%9C</link>
            <guid>https://velog.io/@cheon-eunjeong/Java-StringBuilder-%EC%82%AC%EC%9A%A9%EB%B2%95-%EB%B0%8F-%EC%A3%BC%EC%9A%94-%EB%A9%94%EC%86%8C%EB%93%9C</guid>
            <pubDate>Sat, 26 Oct 2024 14:12:01 GMT</pubDate>
            <description><![CDATA[<h2 id="✔️-한-줄-요약">✔️ 한 줄 요약</h2>
<table>
<thead>
<tr>
<th>주요 메소드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>append(String str)</td>
<td>문자열 끝에 문자열 <strong>추가</strong></td>
</tr>
<tr>
<td>insert(int offset, String str)</td>
<td><strong>offset</strong> 위치에 <strong>str</strong> 문자열 <strong>삽입</strong></td>
</tr>
<tr>
<td>delete(int start, int end)</td>
<td><strong>start ~ end-1</strong> 범위 문자열 <strong>삭제</strong></td>
</tr>
<tr>
<td>deleteCharAt(int index)</td>
<td><strong>index</strong> 위치의 문자 <strong>삭제</strong></td>
</tr>
<tr>
<td>replace(int start, int end, String str)</td>
<td><strong>start ~ end - 1</strong> 범위의 문자열 <strong>str</strong>로 <strong>대체</strong></td>
</tr>
<tr>
<td>reverse()</td>
<td>문자열 <strong>역순</strong>으로 변경</td>
</tr>
<tr>
<td>setCharAt(int index, char ch)</td>
<td><strong>index</strong> 위치의 문자 <strong>ch</strong>로 <strong>대체</strong></td>
</tr>
<tr>
<td>charAt(int index)</td>
<td><strong>index</strong> 위치의 문자 <strong>반환</strong></td>
</tr>
<tr>
<td>substring(int start, int end)</td>
<td><strong>start ~ end-1</strong> 범위의 문자열 <strong>반환</strong></td>
</tr>
<tr>
<td>toString()</td>
<td><strong>StringBuilder</strong> 객체 <strong>String</strong>으로 변환</td>
</tr>
</tbody></table>
<h2 id="1-appendstring-str">1. append(String str)</h2>
<pre><code class="language-java">StringBuilder sb = new StringBuilder();
sb.append(&quot;Hello&quot;);
sb.append(&quot; World&quot;);
// sb = Hello World</code></pre>
<p><strong>설명 :</strong> 문자열의 끝에 문자열 추가</p>
<p><strong>시그니처</strong> : <code>public StringBuilder append(String str)</code></p>
<p><strong>매개변수</strong> : str - 추가할 문자열</p>
<p><strong>사용 상황 :</strong> 여러 문자열을 하나로 합치거나, 문자열의 끝에 새로운 문자열을 추가하고 싶을 때 사용</p>
<h2 id="2-insertint-offset-string-str">2. insert(int offset, String str)</h2>
<pre><code class="language-java">StringBuilder sb = new StringBuilder(&quot;Hello&quot;);
sb.insert(5, &quot; World&quot;);
// sb = Hello World</code></pre>
<p><strong>설명 :</strong> 특정 위치에 문자열 삽입</p>
<p><strong>시그니처</strong> : <code>public StringBuilder insert(int offset, String str)</code></p>
<p><strong>매개변수</strong> : offset - 삽입할 위치의 인덱스, str - 삽입할 문자열</p>
<p><strong>사용 상황 :</strong> 특정 위치에 문자열을 삽입해야 할 때 사용</p>
<h2 id="3-deleteint-start-int-end">3. delete(int start, int end)</h2>
<pre><code class="language-java">StringBuilder sb = new StringBuilder(&quot;Hello World&quot;);
sb.delete(5, 11);
// sb = Hello</code></pre>
<p><strong>설명 :</strong> 시작 인덱스에서 끝 인덱스 전까지의 문자열 삭제</p>
<p><strong>시그니처</strong> : <code>public StringBuilder delete(int start, int end)</code></p>
<p><strong>매개변수</strong> : start - 시작 인덱스(포함), end - 끝 인덱스(포함 X)</p>
<p><strong>사용 상황 :</strong> 특정 범위의 문자열을 제거할 때 사용</p>
<h2 id="4-deletecharatint-index">4. deleteCharAt(int index)</h2>
<pre><code class="language-java">StringBuilder sb = new StringBuilder(&quot;Hello World&quot;);
sb.deleteCharAt(5);
// sb = HelloWorld</code></pre>
<p><strong>설명 :</strong> 특정 위치의 문자를 삭제</p>
<p><strong>시그니처</strong> : <code>public StringBuilder deleteCharAt(int index)</code></p>
<p><strong>매개변수</strong> : index - 삭제할 위치의 인덱스</p>
<p><strong>사용 상황 :</strong> 특정 위치의 문자를 삭제할 때 사용</p>
<h2 id="5-replaceint-start-int-end-string-str">5. replace(int start, int end, String str)</h2>
<pre><code class="language-java">StringBuilder sb = new StringBuilder(&quot;Hello World&quot;);
sb.replace(6, 11, &quot;Java&quot;);
// sb = Hello Java</code></pre>
<p><strong>설명 :</strong> 시작 인덱스에서 끝 인덱스까지의 문자열을 원하는 문자열로 대체</p>
<p><strong>시그니처</strong> : <code>public StringBuilder replace(int start, int end, String str)</code></p>
<p><strong>매개변수</strong> : start - 시작 인덱스(포함), end - 끝 인덱스(포함 X), str - 대체할 문자열</p>
<p><strong>사용 상황 :</strong> 특정 범위의 문자열을 다른 문자열로 교체할 때 사용</p>
<h2 id="6-reverse">6. reverse()</h2>
<pre><code class="language-java">StringBuilder sb = new StringBuilder(&quot;Hello&quot;);
sb.reverse();
// sb = olleH</code></pre>
<p><strong>설명 :</strong> 문자열을 역순으로 변경</p>
<p><strong>시그니처</strong> : <code>public StringBuilder reverse()</code></p>
<p><strong>사용 상황 :</strong> 문자열을 뒤집어야 할 때 사용</p>
<h2 id="7-setcharatint-index-char-ch">7. setCharAt(int index, char ch)</h2>
<pre><code class="language-java">StringBuilder sb = new StringBuilder(&quot;Hello&quot;);
sb.setCharAt(1, &#39;a&#39;);
// sb = Hallo</code></pre>
<p><strong>설명 :</strong> 특정 인덱스의 문자를 원하는 문자로 변경</p>
<p><strong>시그니처</strong> : public void setCharAt(int index, char ch)</p>
<p><strong>매개변수</strong> : index - 변경할 문자의 인덱스, ch - 새로 설정할 문자</p>
<p><strong>사용 상황 :</strong> 특정 위치의 문자를 다른 문자로 교체할 때 사용</p>
<h2 id="8-charatint-index">8. charAt(int index)</h2>
<pre><code class="language-java">StringBuilder sb = new StringBuilder(&quot;Hello&quot;);
char ch = sb.charAt(1);
// ch = e</code></pre>
<p><strong>설명 :</strong> 특정 인덱스의 문자 반환</p>
<p><strong>시그니처</strong> : <code>public char charAt(int index)</code></p>
<p><strong>매개변수</strong> : index - 반환할 문자의 인덱스</p>
<p><strong>사용 상황 :</strong> 특정 위치의 문자를 확인할 때 사용</p>
<h2 id="9-substringint-start-int-end">9. substring(int start, int end)</h2>
<pre><code class="language-java">StringBuilder sb = new StringBuilder(&quot;Hello World&quot;);
String sub = sb.substring(0, 5);
// sub = Hello</code></pre>
<p><strong>설명 :</strong> 시작 인덱스에서 끝 인덱스 전까지의 부분 문자열 반환</p>
<p><strong>시그니처</strong> : <code>public String substring(int start, int end)</code></p>
<p><strong>매개변수</strong> : start - 시작 인덱스(포함), end - 끝 인덱스(포함 X)</p>
<p><strong>사용 상황 :</strong> 특정 범위의 문자열을 추출할 때 사용</p>
<h2 id="10-tostring">10. toString()</h2>
<pre><code class="language-java">StringBuilder sb = new StringBuilder(&quot;Hello&quot;);
String str = sb.toString();
// str = Hello</code></pre>
<p><strong>설명 :</strong>  StringBuilder 객체를 String으로 변환</p>
<p><strong>시그니처</strong> : <code>public String toString()</code></p>
<p><strong>사용 상황 :</strong> 최종 문자열을 얻을 때 사용</p>
<hr>
<p>문자열을 조작할 때 특히 알고리즘을 풀이하며 반복하여 문자열을 계속 추가해야 하는 경우나 문자열에서 삽입, 삭제, 변경 등의 작업이 자주 발생하는 경우 불변 객체인 String을 사용하여 새로운 문자열을 계속 생성하는 것보다 내부 배열을 직접 수정하는 StringBuilder를 사용해 성능을 향상시킬 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[
        
        
[Java] String split 메소드의 limit 인자 사용법]]></title>
            <link>https://velog.io/@cheon-eunjeong/Java-String-split-%EB%A9%94%EC%86%8C%EB%93%9C%EC%9D%98-limit-%EC%9D%B8%EC%9E%90-%EC%82%AC%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@cheon-eunjeong/Java-String-split-%EB%A9%94%EC%86%8C%EB%93%9C%EC%9D%98-limit-%EC%9D%B8%EC%9E%90-%EC%82%AC%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Fri, 25 Oct 2024 09:57:49 GMT</pubDate>
            <description><![CDATA[<h2 id="✔️-한-줄-요약">✔️ 한 줄 요약</h2>
<p><code>String[] split(String regex)</code> : regex 구분자를 기준으로 문자열을 분할 (limit = 0 과 같이 작동), 분리된 문자열은 배열로 반환</p>
<p><code>String[] split(String regex, int limit)</code> : regex 구분자를 기준으로 문자열을 분할(= 패턴), 분리된 문자열은 배열로 반환</p>
<ul>
<li><p><code>limit &lt; 0</code> : 패턴이 가능한 한 많이 적용, 마지막 패턴 뒤 빈 문자열이 있다면 결과 배열에 포함</p>
</li>
<li><p><code>limit = 0</code> : 패턴이 가능한 한 많이 적용, 마지막 패턴 뒤 빈 문자열이 있어도 결과 배열에 포함되지 않음</p>
</li>
<li><p><code>limit &gt; 0</code> : 패턴이 최대 limit - 1번 적용되고, 결과 배열의 최대 길이는 limit </p>
</li>
</ul>
<h2 id="splitstring-regex-vs-splitstring-regex-int-limit">split(String regex) vs split(String regex, int limit)</h2>
<p><img src="https://velog.velcdn.com/images/cheon-eunjeong/post/d1dca8bb-9284-4b72-9064-168c21152ee5/image.png" alt=""></p>
<p>문자열을 기준 문자로 분리하려고 할 때 split() 메소드를 자주 사용하게 된다.</p>
<p>java 공식문서에 따르면 split 메소드는 regex만 인자로 가지는 메소드와 regex, limit 두 가지를 인자로 가지는 메소드로 나뉘어져 있다.</p>
<p>좀 더 자세히 알아보자</p>
<p><img src="https://velog.velcdn.com/images/cheon-eunjeong/post/fbd57f1d-888d-42d9-9857-38b55ad264da/image.png" alt=""></p>
<p>java 공식문서의 split 메소드에 대한 설명이다.</p>
<p>두번째 줄에 <strong>&quot;이 메소드는 주어진 표현식(regex)과 limit 인수로 0을 사용하는 두 인자를 받는 split 메소드를 호출</strong> 한 것처럼 동작합니다.&quot; 라는 문장이 있다.</p>
<p>limit 인자를 신경쓰지 않고 사용해왔는데 내부적으로 limit의 인수로 0이 들어간 것처럼 작동되고 있던 것이다.</p>
<p><img src="https://velog.velcdn.com/images/cheon-eunjeong/post/32753fc3-ee1a-417e-8ffc-ae3d65b55f0c/image.png" alt=""></p>
<p>두 가지 인자를 가진 split 메소드는 <strong>regex</strong> (주어진 정규 표현식)와 일치하는 부분을 기준으로 문자열을 분리해 배열로 반환하며, <strong>limit</strong> 는 _regex와 일치하는 부분을 기준으로 문자열을 분리하는 패턴이 적용되는 횟수를 제어하는 매개변수_로 <strong>배열의 길이를 조절하는데 사용</strong> 된다.</p>
<h2 id="1-limit--0">1. limit &gt; 0</h2>
<pre><code class="language-java">String str = &quot;one,two,three,four&quot;;
String[] result = str.split(&quot;,&quot;, 3);
// result = {&quot;one&quot;, &quot;two&quot;, &quot;three,four&quot;}</code></pre>
<p>limit가 양수, 0 이상일 때는 <strong>최대 limit - 1 번</strong> 만큼 regex 구분자를 사용하여 문자열을 분리한다.</p>
<p>결과 배열의 <strong>길이는 최대 limit</strong> 이고, 배열의 마지막 요소는 <strong>마지막 구분자 이후의 모든 문자열</strong> 이 된다.</p>
<h2 id="2-limit--0">2. limit == 0</h2>
<pre><code class="language-java">String str = &quot;one,two,,three,&quot;;
String[] result = str.split(&quot;,&quot;, 0);
// result = {&quot;one&quot;, &quot;two&quot;, &quot;&quot;, &quot;three&quot;}</code></pre>
<p>limit가 0일 때는 그동안 사용해왔던 <strong>split() 메소드</strong> 와 같이 동작한다.</p>
<p>패턴이 가능한 한 많이 적용되며 배열의 최대 길이도 제한이 없지만 분리하려는 <strong>문자열의 끝에 빈 문자열이 있을 경우 제거</strong> 된다.</p>
<h2 id="3-limit--0">3. limit &lt; 0</h2>
<pre><code class="language-java">String str = &quot;one,two,,three,&quot;;
String[] result = str.split(&quot;,&quot;, -1);
// result = {&quot;one&quot;, &quot;two&quot;, &quot;&quot;, &quot;three&quot;, &quot;&quot;}</code></pre>
<p>limit가 음수일 때도 0일 때와 마찬가지로 패턴이 가능한 한 많이 적용되며 배열의 최대 길이 제한도 없지만</p>
<p>0일때와 다른 점은 <strong>빈 문자열도 결과 배열에 포함</strong> 된다는 것이다</p>
<p>마지막 빈 문자열도 결과 배열 안에 포함하고 싶을 때 사용할 수 있다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 배열(Array) 복사, 자르기 방법 정리: 성능, 장단점, 사용 상황]]></title>
            <link>https://velog.io/@cheon-eunjeong/Java-%EB%B0%B0%EC%97%B4Array-%EB%B3%B5%EC%82%AC-%EC%9E%90%EB%A5%B4%EA%B8%B0-%EB%B0%A9%EB%B2%95-%EC%A0%95%EB%A6%AC-%EC%84%B1%EB%8A%A5-%EC%9E%A5%EB%8B%A8%EC%A0%90-%EC%82%AC%EC%9A%A9-%EC%83%81%ED%99%A9</link>
            <guid>https://velog.io/@cheon-eunjeong/Java-%EB%B0%B0%EC%97%B4Array-%EB%B3%B5%EC%82%AC-%EC%9E%90%EB%A5%B4%EA%B8%B0-%EB%B0%A9%EB%B2%95-%EC%A0%95%EB%A6%AC-%EC%84%B1%EB%8A%A5-%EC%9E%A5%EB%8B%A8%EC%A0%90-%EC%82%AC%EC%9A%A9-%EC%83%81%ED%99%A9</guid>
            <pubDate>Thu, 24 Oct 2024 14:03:26 GMT</pubDate>
            <description><![CDATA[<h2 id="한-줄-요약">한 줄 요약</h2>
<table>
<thead>
<tr>
<th align="left">방법</th>
<th align="left">장점</th>
<th align="left">상황</th>
<th align="left">단점</th>
</tr>
</thead>
<tbody><tr>
<td align="left">Arrays.copyOfRange</td>
<td align="left">간단하고 사용하기 쉬움</td>
<td align="left">배열의 <strong>특정 범위를 복사</strong> 할 때</td>
<td align="left">특정 범위 복사에만 사용 가능</td>
</tr>
<tr>
<td align="left">Arrays.copyOf</td>
<td align="left">간단하고 사용하기 쉬움</td>
<td align="left">배열의 <strong>처음부터 일정 길이만큼 복사</strong> 할 때</td>
<td align="left">배열 길이를 명시적으로 지정해야 함</td>
</tr>
<tr>
<td align="left">System.arraycopy</td>
<td align="left">매우 빠르고 효율적</td>
<td align="left"><strong>성능</strong> 이 매우 중요한 경우</td>
<td align="left">복잡한 사용법</td>
</tr>
<tr>
<td align="left">ArrayList</td>
<td align="left">리스트 작업에 유용</td>
<td align="left">리스트 작업이 필요할 때</td>
<td align="left">성능이 배열에 비해 떨어질 수 있음</td>
</tr>
<tr>
<td align="left">Stream</td>
<td align="left">함수형 프로그래밍에 적합</td>
<td align="left">함수형 프로그래밍을 사용할 때</td>
<td align="left">성능이 배열 복사보다 떨어질 수 있음</td>
</tr>
<tr>
<td align="left">for문(수동 복사)</td>
<td align="left">유연성이 높음</td>
<td align="left">특별한 로직이 필요할 때</td>
<td align="left">코드가 길어지고 복잡해질 수 있음</td>
</tr>
</tbody></table>
<p>Java에서 배열을 복사하는 방법에는 여러가지가 있다. 각 방법들의 장단점과 사용법, 쓰이는 상황에 대해 알아보자.</p>
<h2 id="1-arrayscopyofrange">1. Arrays.copyOfRange</h2>
<pre><code class="language-java">int[] originalArray = {1, 2, 3, 4, 5};
int[] copiedArray = Arrays.copyOfRange(originalArray, 1, 4);
// copiedArray는 {2, 3, 4}를 포함</code></pre>
<p><strong>메서드 시그니처</strong>: Arrays.copyOfRange(T[] original, int from, int to)
<strong>사용법</strong>: Arrays.copyOfRange(원본 배열, 시작 인덱스, 종료 인덱스)</p>
<p>Arrays.copyOfRange()는 내부적으로 System.arraycopy() 메소드를 사용해 기본적으로 복사 성능이 빠르다. 하지만 내부적으로 범위 검사와 길이 계산으로 인해 약간의 오버헤드가 발생한다. 
<strong>원본 배열</strong>의 <strong>시작 인덱스</strong>부터 <strong>종료 인덱스-1</strong> 까지 범위를 복사하여 <strong>새로운 배열</strong>을 만드는 메소드로 배열의 특정 범위를 복사하거나 자를 때 유용하다. 
<strong>종료 인덱스가 복사된 배열에 포함되지 않으므로 범위 사용에 주의가 필요</strong>하다 !</p>
<h2 id="2-arrayscopyof">2. Arrays.copyOf</h2>
<pre><code class="language-java">int[] originalArray = {1, 2, 3, 4, 5};
int[] copiedArray = Arrays.copyOf(originalArray, 3);
// copiedArray는 {1, 2, 3}을 포함</code></pre>
<p><strong>메서드 시그니처</strong>: Arrays.copyOf(T[] original, int newLength)
<strong>사용법</strong>: Arrays.copyOf(원본 배열, 복사할 길이)</p>
<p>Arrays.copyOf()도 Arrays.copyOfRange()와 마찬가지로 내부적으로 System.arraycopy() 메소드를 사용해 성능이 빠르다. 
내부적으로 길이를 검사하는 로직으로 인해 약간의 오버헤드가 발생한다. 
<strong>원본 배열</strong>을 <strong>복사할 길이</strong> 만큼 복사한 새로운 배열을 만드는 메소드로 배열의 처음부터 일정길이만큼 복사하거나 자를 때 유용하다.</p>
<h2 id="3-systemarraycopy">3. System.arraycopy</h2>
<pre><code class="language-java">int[] originalArray = {1, 2, 3, 4, 5};
int[] copiedArray = new int[3];
System.arraycopy(originalArray, 1, copiedArray, 0, 3);
// copiedArray는 {2, 3, 4}를 포함</code></pre>
<p><strong>메서드 시그니처</strong>: System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
<strong>사용법</strong>: System.arraycopy(원본 배열, 원본 시작 인덱스, 복사 배열, 복사 시작 인덱스, 복사할 길이)</p>
<p>System.arraycopy()는 <strong>네이티브 메소드 호출</strong>로 인해 배열 복사 시 성능적으로 가장 뛰어나다. 
<strong>원본 배열</strong>의 <strong>시작 인덱스</strong>부터 <strong>복사할 길이</strong>만큼을 <strong>복사 배열</strong>의 <strong>복사 시작 인덱스</strong>에 복사하는 메소드로 사용법이 다른 메소드들과 비교해 다소 복잡하게 느껴질 수 있다. 
원본 배열과 복사 배열의 타입이 호환되지 않거나 타입 변환이 불가능 한 경우, 복사할 인덱스의 길이가 배열의 크기를 초과하는 경우와 같이 잘못된 사용으로 인해 여러가지 예외가 발생할 수 있어 주의해야 한다.</p>
<blockquote>
<p><em>Arrays.copyOfRange()와 Arrays.copyOf()의 내부 코드를 살펴보면 내부적으로 System.arraycopy()를 사용하고 있다.</em></p>
</blockquote>
<pre><code class="language-java">public static int[] copyOfRange(int[] original, int from, int to) {
    int newLength = to - from;
    if (newLength &lt; 0)
        throw new IllegalArgumentException(from + &quot; &gt; &quot; + to);
    int[] copy = new int[newLength];
    System.arraycopy(original, from, copy, 0,
                     Math.min(original.length - from, newLength));
    return copy;
}</code></pre>
<pre><code class="language-java">public static int[] copyOf(int[] original, int newLength) {
    int[] copy = new int[newLength];
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}</code></pre>
<p>때문에 기본적인 복사 성능은 거의 동일하지만, Arrays.copyOfRange()는 범위 검사와 길이 계산에서의 추가 로직이, Arrays.copyOf()는 길이 체크에서의 추가 로직으로 인해 System.arraycopy()보다 약간의 오버헤드가 있을 수 있다.</p>
<h2 id="4-arraylist-생성">4. ArrayList 생성</h2>
<pre><code class="language-java">int[] originalArray = {1, 2, 3, 4, 5};
List&lt;Integer&gt; list = new ArrayList&lt;&gt;();
for (int i = 1; i &lt; 4; i++) {
    list.add(originalArray[i]);
}
Integer[] copiedArray = list.toArray(new Integer[0]);
// copiedArray는 {2, 3, 4}를 포함</code></pre>
<p><strong>사용법</strong>:   <strong>ArrayList</strong>를 생성하여 <strong>add()</strong>를 통해 요소를 추가한 후 <strong>toArray()</strong>로 <strong>배열로 변환</strong></p>
<p>ArrayList를 사용하는 경우 <strong>동적</strong>으로 배열의 크기를 조절할 수 있어 배열의 크기가 정해지지 않은 경우 사용하기에 좋고, 리스트 작업이 필요한 경우 유용하다. 
다만 <strong>오토박싱</strong>과 <strong>언박싱</strong>으로 인한 오버헤드와 배열에 비해 느려 대량의 데이터를 처리할 때 성능 저하가 발생할 수 있으므로 주의하자.</p>
<h2 id="5-stream-사용-java-8-이상">5. Stream 사용 (Java 8 이상)</h2>
<pre><code class="language-java">int[] originalArray = {1, 2, 3, 4, 5};
int[] copiedArray = Arrays.stream(originalArray, 1, 4).toArray();
// copiedArray는 {2, 3, 4}를 포함</code></pre>
<p><strong>사용법</strong>: Arrays.stream(원본 배열, 시작 인덱스, 종료 인덱스).toArray()</p>
<p>Arrays.stream()은 Java 8부터 제공되는 <strong>Stream</strong>을 사용해 <strong>원본 배열</strong>의 <strong>시작 인덱스</strong>부터 <strong>종료 인덱스-1</strong> 까지 범위를 복사하여 <strong>새로운 배열</strong>을 만드는 메소드다. 
스트림을 사용해서 병렬 처리 등 다양한 스트림 기능들을 사용할 수 있다. 
스트림에 익숙한 사람이라면 코드를 짧고 간결하게 작성하며 사용할 수 있겠지만, 익숙하지 않으면 사용하고 이해하는데 어려움을 겪을 수 있으며 성능적으로도 배열 복사보다 떨어질 수 있다.</p>
<h2 id="6-for문-사용수동-복사">6. for문 사용(수동 복사)</h2>
<pre><code class="language-java">int[] originalArray = {1, 2, 3, 4, 5};
int[] copiedArray = new int[3];
for (int i = 1; i &lt; 4; i++) {
    copiedArray[i - 1] = originalArray[i];
}
// copiedArray는 {2, 3, 4}를 포함</code></pre>
<p><strong>사용법</strong>: for 루프를 사용하여 원본 배열에서 원하는 범위를 복사</p>
<p>가장 간단하고 원시적인 방법으로 for문을 사용해 복사하면 특정 로직을 추가하기 쉬워 유연성이 높은 코드를 작성할 수 있다. 
직접 복사로 인해 성능도 준수한 편이다. 다만 코드가 길어지고 복잡해질 수 있으며 인덱스를 직접 관리해야하니 주의하자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[인터프리터 언어 vs 컴파일 언어]]></title>
            <link>https://velog.io/@cheon-eunjeong/%EC%9D%B8%ED%84%B0%ED%94%84%EB%A6%AC%ED%84%B0-%EC%96%B8%EC%96%B4-vs-%EC%BB%B4%ED%8C%8C%EC%9D%BC-%EC%96%B8%EC%96%B4</link>
            <guid>https://velog.io/@cheon-eunjeong/%EC%9D%B8%ED%84%B0%ED%94%84%EB%A6%AC%ED%84%B0-%EC%96%B8%EC%96%B4-vs-%EC%BB%B4%ED%8C%8C%EC%9D%BC-%EC%96%B8%EC%96%B4</guid>
            <pubDate>Wed, 23 Oct 2024 07:19:12 GMT</pubDate>
            <description><![CDATA[<h2 id="✔️-한-줄-요약">✔️ 한 줄 요약</h2>
<p><code>인터프리터 언어(Interpreter Language)</code> : 소스 코드를 한 줄씩 읽고, 즉시 실행하는 언어
<code>컴파일 언어(Compiled Language)</code> : 소스 코드를 실행하기 전에 한 번에 기계어로 컴파일하여 실행 파일을 생성하는 언어
 </p>
<h2 id="인터프리터-언어">인터프리터 언어</h2>
<p><strong>인터프리터(Interpreter)</strong> 가 프로그램이 실행될 때 소스 코드를 한 줄씩 읽고 해석하여 즉시 실행하는 언어다.
대표적인 언어로는 <strong>파이썬(Python), 자바스크립트(JavaScript), 루비(Ruby)</strong> 가 있다.
 </p>
<h3 id="특징">특징</h3>
<ol>
<li>소스 코드를 한 줄씩 읽고 해석하며 실행하므로 별도의 컴파일 과정 없이 즉시 실행할 수 있다. 빠른 프로토타이핑과 테스트가 가능하다. API 엔드포인트를 빠르게 수정하고 결과를 즉시 확인할 수 있다.</li>
<li>오류 발생 시 해당 줄에서 멈추기 때문에, 디버깅에 용이하다. 런타임 에러 발생 시 스택 트레이스를 통한 트러블 슈팅에 용이하다.</li>
<li>프로그램을 실행할 때마다 소스 코드를 해석해야 해서 실행 속도가 비교적 느리다. 요청 처리 속도가 중요한 경우, 성능상 불리하다.
 <h2 id="컴파일-언어">컴파일 언어</h2>
소스 코드를 실행하기 전 한 번에 기계어로 컴파일하여 실행 파일을 생성하는 언어이다.
대표적인 언어로는 <strong>C, C++, 자바(Java)</strong> 등이 있다.
 <h3 id="특징-1">특징</h3>
</li>
<li>소스 코드가 기계어로 컴파일 된 실행 파일로 실행하므로, 실행 속도가 빠르다. 높은 성능을 요구하는 애플리케이션에 적합하다. ex) 고속 트랜잭션 처리, 실시간 데이터 처리</li>
<li>코드 수정 후 새로 실행할 때, 수정된 코드를 새로 컴파일 하는 과정이 필요하다. 개발 속도가 느려질 수 있다.</li>
<li>컴파일 시 모든 코드를 한 번에 처리하기 때문에, 컴파일 과정에서 오류를 미리 발견할 수 있다. 타입 안정성과 컴파일 시점의 오류 검출로, 런타임 오류를 줄일 수 있다.
 <h2 id="인터프리터-언어-vs-컴파일-언어">인터프리터 언어 vs 컴파일 언어</h2>
</li>
</ol>
<table>
<thead>
<tr>
<th align="center"></th>
<th align="center">인터프리터 언어</th>
<th align="center">컴파일 언어</th>
</tr>
</thead>
<tbody><tr>
<td align="center">실행 속도</td>
<td align="center">느리다</td>
<td align="center">빠르다</td>
</tr>
<tr>
<td align="center">실행 방식</td>
<td align="center">소스 코드를 한 줄씩 해석하고 실행</td>
<td align="center">소스 코드를 한 번에 컴파일하여 실행 파일을 생성하여 진행</td>
</tr>
<tr>
<td align="center">테스트</td>
<td align="center">빠르다</td>
<td align="center">느리다(재컴파일이 필요</td>
</tr>
<tr>
<td align="center">트러블 슈팅</td>
<td align="center">디버깅 시점에서 빠른 트러블 슈팅 가능</td>
<td align="center">컴파일 시점에 오류를 검출하므로, 런타임 오류를 줄일 수 있다</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] IntStream, LongStream의 range() vs rangeClosed()]]></title>
            <link>https://velog.io/@cheon-eunjeong/Java-IntStream-LongStream%EC%9D%98-range-vs-rangeClosed-0yrzgobp</link>
            <guid>https://velog.io/@cheon-eunjeong/Java-IntStream-LongStream%EC%9D%98-range-vs-rangeClosed-0yrzgobp</guid>
            <pubDate>Tue, 22 Oct 2024 11:15:13 GMT</pubDate>
            <description><![CDATA[<h2 id="한-줄-요약">한 줄 요약</h2>
<p><code>range(시작 인덱스, 종료 인덱스)</code> → 시작 인덱스부터 종료 인덱스 - 1 까지
<code>rangeClosed(시작 인덱스, 종료 인덱스)</code> → 시작 인덱스 부터 종료 인덱스 까지 (end_index 포함)
 </p>
<h2 id="예시-및-출력">예시 및 출력</h2>
<pre><code class="language-java">int[] array1 = IntStream.range(0, 6)
        .toArray();

int[] array2 = IntStream.rangeClosed(0, 6)
        .toArray();
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]</code></pre>
<h2 id="내부-코드">내부 코드</h2>
<pre><code class="language-java">public static IntStream range(int startInclusive, int endExclusive) {
    if (startInclusive &gt;= endExclusive) {
        return empty();
    } else {
        return StreamSupport.intStream(
                new Streams.RangeIntSpliterator(startInclusive, endExclusive, false), false);
    }
}

public static IntStream rangeClosed(int startInclusive, int endInclusive) {
    if (startInclusive &gt; endInclusive) {
        return empty();
    } else {
        return StreamSupport.intStream(
                new Streams.RangeIntSpliterator(startInclusive, endInclusive, true), false);
    }
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>