<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hong-seo.log</title>
        <link>https://velog.io/</link>
        <description>곧 성공할 개발자입니다.</description>
        <lastBuildDate>Mon, 13 Apr 2026 05:16:56 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hong-seo.log</title>
            <url>https://velog.velcdn.com/images/hong-seo/profile/b658d685-1e0f-4f55-b0a4-e2f13bd507ed/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hong-seo.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hong-seo" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[java] 스택(Stack) 완벽 구현: 배열 덮어쓰기 vs Stack 클래스]]></title>
            <link>https://velog.io/@hong-seo/java-%EC%8A%A4%ED%83%9DStack-%EC%99%84%EB%B2%BD-%EA%B5%AC%ED%98%84-%EB%B0%B0%EC%97%B4-%EB%8D%AE%EC%96%B4%EC%93%B0%EA%B8%B0-vs-Stack-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@hong-seo/java-%EC%8A%A4%ED%83%9DStack-%EC%99%84%EB%B2%BD-%EA%B5%AC%ED%98%84-%EB%B0%B0%EC%97%B4-%EB%8D%AE%EC%96%B4%EC%93%B0%EA%B8%B0-vs-Stack-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Mon, 13 Apr 2026 05:16:56 GMT</pubDate>
            <description><![CDATA[<p>알고리즘 문제를 풀다 보면 <strong>&quot;가장 마지막에 넣은 데이터를 먼저 빼야 하는&quot;</strong> 상황이 자주 발생합니다. (예: 괄호 짝 맞추기, 뒤로 가기 버튼, 최근 숫자 지우기 등)</p>
<p>이럴 때 사용하는 자료구조가 바로 <strong>스택(Stack)</strong>, 즉 <strong>LIFO(Last In, First Out)</strong> 구조입니다. 오늘은 자바에서 스택 로직을 구현할 때 흔히 하는 실수부터, 코딩 테스트를 통과하기 위한 최적화 방법, 그리고 자바 내장 클래스 활용법까지 3단계로 나누어 완벽하게 정리해 보겠습니다.</p>
<hr>
<h3 id="1단계-초보자의-접근-배열-크기-직접-조절하기">1단계: 초보자의 접근 (배열 크기 직접 조절하기)</h3>
<p>가장 먼저 떠올릴 수 있는 방법은 기본 배열(<code>int[]</code>)을 만들고, 데이터가 들어오거나 나갈 때마다 배열의 크기를 늘렸다 줄였다 하는 것입니다.</p>
<pre><code class="language-jsx">public int[] makeStack(int[] arr) {
    int[] stk = {}; // 빈 배열

    for(int num : arr) {
        // 넣을 때: 기존 배열을 복사해서 1칸 더 큰 배열을 만듦
        stk = Arrays.copyOf(stk, stk.length + 1);
        stk[stk.length - 1] = num; // 마지막 방(길이 - 1)에 넣기

        // 뺄 때: 마지막 칸을 제외하고 복사해서 배열을 줄임
        // stk = Arrays.copyOfRange(stk, 0, stk.length - 1); 
    }
    return stk;
}</code></pre>
<ul>
<li><strong>문제점:</strong> 논리적으로는 완벽하지만, <strong>코딩 테스트에서는 100% &#39;시간 초과&#39;가 발생합니다.</strong> * <strong>이유:</strong> <code>Arrays.copyOf</code>는 단순히 크기만 바꾸는 게 아니라, 매번 새로운 배열을 메모리에 만들고 기존 데이터를 하나씩 다 옮겨 적는 무거운 작업이기 때문입니다. (마치 짐을 하나 추가할 때마다 더 큰 집으로 이사를 가는 것과 같습니다.)</li>
</ul>
<hr>
<h3 id="2단계-고수들의-퍼포먼스-인덱스-포인터-활용">2단계: 고수들의 퍼포먼스 (인덱스 포인터 활용)</h3>
<p>배열을 매번 새로 만들지 않고 속도를 극한으로 끌어올리려면 어떻게 해야 할까요?
바로 &quot;처음부터 가장 큰 집을 구해놓고, 손가락(인덱스)으로 현재 위치만 가리키는 방식&quot;을 사용해야 합니다.</p>
<pre><code class="language-jsx">public int[] fastStack(int[] arr) {
    // 1. 처음부터 원본 길이만큼 넉넉한 배열을 딱 1번만 만듭니다.
    int[] stk = new int[arr.length]; 

    // 2. 현재 스택의 꼭대기를 가리키는 손가락(top 포인터)
    int top = 0; 

    for (int num : arr) {
        if (top == 0 || stk[top - 1] != num) { 
            // 다르면 넣는다 (현재 손가락 위치에 덮어쓰고 1칸 전진)
            stk[top] = num; 
            top++;          
        } else {
            // 같으면 뺀다 (손가락을 1칸 뒤로 무름 -&gt; 다음에 알아서 덮어씌워짐)
            top--;          
        }
    }

    // 3. 마지막에 손가락이 가리키는 곳까지만 딱 1번 잘라서 반환!
    return Arrays.copyOf(stk, top); 
}</code></pre>
<ul>
<li><strong>장점:</strong> 배열 복사를 맨 마지막에 딱 1번만 하므로 속도가 압도적으로 빠릅니다. 코딩 테스트에서 실행 속도를 줄이고 싶을 때 강력 추천하는 방식입니다.</li>
</ul>
<hr>
<h3 id="3단계-자바의-정석-stack-클래스-활용">3단계: 자바의 정석 (Stack 클래스 활용)</h3>
<p>사실 자바에는 이미 이 모든 것을 알아서 해주는 <code>Stack</code> 클래스가 존재합니다! 크기가 알아서 늘어나고 줄어들기 때문에, 우리는 <code>push</code>(넣기), <code>pop</code>(빼기), <code>peek</code>(맨 위 확인)이라는 직관적인 단어만 사용하면 됩니다.</p>
<pre><code class="language-jsx">import java.util.Stack;
import java.util.Arrays;

public int[] standardStack(int[] arr) {
    Stack&lt;Integer&gt; stack = new Stack&lt;&gt;(); 

    for (int num : arr) {
        // 스택이 비어있지 않고, 맨 위 숫자(peek)가 현재 숫자와 같으면 뺀다(pop)!
        if (!stack.isEmpty() &amp;&amp; stack.peek() == num) {
            stack.pop();
        } 
        // 아니면 넣는다(push)!
        else {
            stack.push(num);
        }
    }

    // (꿀팁) 만들어진 Stack을 int 배열로 한 줄에 변환하기!
    return stack.stream().mapToInt(i -&gt; i).toArray();
}</code></pre>
<ul>
<li><strong>장점:</strong> 코드가 마치 사람이 말하는 것처럼 직관적으로 읽히며, 자잘한 인덱스 에러(IndexOutOfBounds)에서 완전히 해방됩니다!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] 불규칙한 띄어쓰기 완벽하게 자르기: trim()과 split("\\s+")]]></title>
            <link>https://velog.io/@hong-seo/java-%EB%B6%88%EA%B7%9C%EC%B9%99%ED%95%9C-%EB%9D%84%EC%96%B4%EC%93%B0%EA%B8%B0-%EC%99%84%EB%B2%BD%ED%95%98%EA%B2%8C-%EC%9E%90%EB%A5%B4%EA%B8%B0-trim%EA%B3%BC-splits</link>
            <guid>https://velog.io/@hong-seo/java-%EB%B6%88%EA%B7%9C%EC%B9%99%ED%95%9C-%EB%9D%84%EC%96%B4%EC%93%B0%EA%B8%B0-%EC%99%84%EB%B2%BD%ED%95%98%EA%B2%8C-%EC%9E%90%EB%A5%B4%EA%B8%B0-trim%EA%B3%BC-splits</guid>
            <pubDate>Sat, 11 Apr 2026 13:22:31 GMT</pubDate>
            <description><![CDATA[<p>사용자가 입력한 데이터나 외부 파일을 읽어올 때, 띄어쓰기가 아주 예쁘게 한 칸씩만 되어있다면 얼마나 좋을까요? 하지만 현실은 그렇지 않습니다.</p>
<pre><code class="language-jsx">&quot;  사과   바나나    포도 &quot;</code></pre>
<p>위 문자열처럼 맨 앞에 공백이 있거나, 단어 사이의 띄어쓰기 칸 수가 제멋대로인 문자열을 단순히 <code>split(&quot; &quot;)</code>으로 자르면 대참사가 발생합니다. 빈 문자열(<code>&quot;&quot;</code>)들이 배열에 불청객처럼 마구 끼어들기 때문이죠.</p>
<p>오늘은 이런 불규칙한 공백들을 단 한 줄의 코드로 완벽하게 제압하는 마법의 조합, <code>trim()</code>과 정규표현식(<code>[ ]+</code>, <code>\\s+</code>)에 대해 파헤쳐 보겠습니다.</p>
<hr>
<h3 id="1단계-trim---앞뒤-쓰레기-공백-청소기">1단계: <code>trim()</code> - 앞뒤 쓰레기 공백 청소기</h3>
<p><code>trim()</code> 메서드는 문자열의 맨 앞(Leading)과 맨 뒤(Trailing)에 있는 의미 없는 공백들을 싹 지워주는 역할을 합니다. (단, 단어와 단어 &#39;사이&#39;에 있는 공백은 건드리지 않습니다.)</p>
<pre><code class="language-jsx">String text = &quot;  안녕 하세요  &quot;;
System.out.println(text.trim()); 
// 결과: &quot;안녕 하세요&quot;</code></pre>
<p><strong>왜 <code>split</code>을 하기 전에 <code>trim()</code>을 써야 할까요?</strong>
자바의 <code>split</code>은 문자열 맨 앞에 구분자(공백)가 있으면, *&quot;어? 공백 앞에도 뭔가 글자가 있었나 본데?&quot;* 하고 착각하여 배열의 첫 번째 방에 빈 문자열(<code>&quot;&quot;</code>)을 집어넣는 고질적인 특징이 있습니다.
따라서 <code>split</code>을 하기 전에 <code>.trim()</code>으로 맨 앞뒤 공백을 방어막처럼 미리 깎아내 주는 것이 안전합니다.</p>
<hr>
<h3 id="2단계-split----스페이스바-마스터">2단계: <code>split(&quot;[ ]+&quot;)</code> - 스페이스바 마스터</h3>
<p>앞뒤 공백을 잘라냈다면, 이제 단어 사이에 있는 &#39;제멋대로인 띄어쓰기&#39;를 하나의 칼날로 잘라낼 차례입니다. 이때 사용하는 것이 바로 정규표현식(Regex)입니다.</p>
<pre><code class="language-jsx">String text = &quot;사과   바나나  포도&quot;;
String[] arr = text.split(&quot;[ ]+&quot;);</code></pre>
<ul>
<li><strong><code>[ ]</code> (대괄호):</strong> &quot;이 안에 있는 글자를 찾아라!&quot;라는 뜻입니다. 여기서는 스페이스바(공백) 한 칸이 들어있습니다.</li>
<li><strong><code>+</code> (더하기):</strong> 정규표현식의 핵심 기호로, &quot;앞의 글자가 1번 이상 연속으로 무한히 나올 수 있다&quot;는 뜻입니다.</li>
</ul>
<p>즉, <code>&quot;[ ]+&quot;</code>의 진짜 의미는 &quot;스페이스바가 1칸이든, 3칸이든, 10칸이든 상관없이 하나로 뭉뚱그려서 잘라내라!&quot;가 됩니다. 이 코드를 쓰면 빈 문자열 없이 딱 3개의 과일만 배열에 예쁘게 담깁니다.</p>
<hr>
<h3 id="3단계-splits---모든-공백의-지배자-종결자">3단계: <code>split(&quot;\\s+&quot;)</code> - 모든 공백의 지배자 (종결자)</h3>
<ul>
<li><code>[ ]+</code>도 훌륭하지만, 실무나 까다로운 코딩 테스트에서는 스페이스바 외에도 엔터(줄바꿈, <code>\n</code>)나 <strong>탭(Tab, <code>\t</code>)</strong> 키가 섞여 들어오는 경우가 아주 많습니다.
이때 <code>[ ]+</code>는 오직 &#39;스페이스바&#39;만 잡을 수 있기 때문에 탭이나 엔터를 만나면 자르지 못하고 에러를 유발합니다.</li>
</ul>
<p>이 모든 상황을 평정하는 끝판왕이 바로 <strong><code>\\s+</code></strong> 입니다.</p>
<pre><code class="language-jsx">// 스페이스바, 탭(\t), 엔터(\n)가 대환장 파티를 벌이는 문자열
String text = &quot;사과 \t 바나나 \n\n 포도&quot;;
String[] arr = text.split(&quot;\\s+&quot;);</code></pre>
<ul>
<li><strong><code>\s</code> (소문자 s):</strong> 스페이스바, 탭, 엔터 등 &#39;눈에 보이지 않는 모든 종류의 공백(Whitespace)&#39;을 의미하는 정규표현식 특수기호입니다. (자바에서는 역슬래시를 표현하기 위해 <code>\\s</code>로 두 번 적어줍니다.)</li>
<li><strong><code>+</code> (더하기):</strong> 역시 1번 이상 연속됨을 의미합니다.</li>
</ul>
<p>즉, <code>split(&quot;\\s+&quot;)</code>는 &quot;스페이스바든, 탭이든, 줄바꿈이든 섞여서 몇 칸이 있든 전부 다 하나의 공백으로 취급해서 잘라버려라!&quot;라는 무적의 코드가 됩니다.</p>
<hr>
<h3 id="최종-요약-이것만-기억하세요">최종 요약 (이것만 기억하세요!)</h3>
<ul>
<li><strong><code>split(&quot; &quot;)</code></strong>: 띄어쓰기가 무조건 딱 1칸씩만 있을 때 쓴다.</li>
<li><strong><code>trim().split(&quot;[ ]+&quot;)</code></strong>: 스페이스바 띄어쓰기가 여러 칸으로 불규칙할 때 쓴다.</li>
<li><strong><code>trim().split(&quot;\\s+&quot;)</code></strong>: 스페이스바, 탭, 엔터 등 <strong>모든 종류의 공백이 섞여 있을 때</strong> 쓰는 가장 완벽한 마법의 1줄 코드!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] 문자열 자르기의 함정: StringTokenizer vs split(-1) 완벽 비교]]></title>
            <link>https://velog.io/@hong-seo/java-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%9E%90%EB%A5%B4%EA%B8%B0%EC%9D%98-%ED%95%A8%EC%A0%95-StringTokenizer-vs-split-1-%EC%99%84%EB%B2%BD-%EB%B9%84%EA%B5%90</link>
            <guid>https://velog.io/@hong-seo/java-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%9E%90%EB%A5%B4%EA%B8%B0%EC%9D%98-%ED%95%A8%EC%A0%95-StringTokenizer-vs-split-1-%EC%99%84%EB%B2%BD-%EB%B9%84%EA%B5%90</guid>
            <pubDate>Fri, 10 Apr 2026 12:10:25 GMT</pubDate>
            <description><![CDATA[<p><a href="https://velog.io/@hong-seo/java-split-%EB%92%A4%EC%97%90-%EB%B6%99%EB%8A%94-%EC%88%AB%EC%9E%90%EC%9D%98-%EB%B9%84%EB%B0%80-limit-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EC%9D%98-3%EA%B0%80%EC%A7%80-%EB%A7%88%EB%B2%95">split() 뒤에 붙는 숫자의 비밀: limit 파라미터의 3가지 마법</a>
블로그 시작에 앞서 split()에 대해 잘 모른다면 위의 블로그를 먼저 보고 오시는거 추천드려요!</p>
<p>코딩 테스트에서 문자열을 특정 기호(구분자)로 잘라 배열로 만들어야 하는 문제는 단골로 출제됩니다. 이때 많은 자바 입문자들이 습관적으로 <code>StringTokenizer</code>를 사용했다가 &#39;오답&#39; 판정을 받곤 합니다.
예를 들어, <code>&quot;oxooxoxxox&quot;</code>라는 문자열을 <code>&quot;x&quot;</code>를 기준으로 잘라서 <strong>각 조각의 길이</strong>를 구해야 한다고 가정해 봅시다.
(원하는 정답 배열: <code>[1, 2, 1, 0, 1, 0]</code>)
분명 완벽하게 코드를 짠 것 같은데 왜 틀렸을까요? 자바가 문자열을 자르는 3가지 방식의 차이를 정확히 알아야 합니다.</p>
<h3 id="1-stringtokenizer의-배신-빈-공간-무시"><strong>1. <code>StringTokenizer</code>의 배신 (빈 공간 무시)</strong></h3>
<p><code>StringTokenizer</code>는 애초에 문자열에서 &#39;의미 있는 토큰(조각)&#39;만 뽑아내기 위해 만들어진 아주 오래된 클래스입니다.
• <strong>동작 방식:</strong> 구분자(<code>&quot;x&quot;</code>)가 연속으로 나오거나 맨 앞/뒤에 있으면, 그 사이의 빈 공간을 완전히 무시(스킵)해 버립니다.
• <strong>결과:</strong> <code>&quot;oxooxoxxox&quot;</code> ➔ <code>[&quot;o&quot;, &quot;oo&quot;, &quot;o&quot;, &quot;o&quot;]</code> (길이: 4)
• <strong>문제점:</strong> 우리가 원했던 &#39;연속된 x 사이의 길이가 0인 빈 문자열&#39;을 아예 배열에 담아주지 않습니다.</p>
<h3 id="2-splitx의-반쪽짜리-진실-후행-빈-문자열-제거"><strong>2. <code>split(&quot;x&quot;)</code>의 반쪽짜리 진실 (후행 빈 문자열 제거)</strong></h3>
<p>&quot;그럼 <code>split</code>을 쓰면 되잖아?&quot; 하고 <code>split(&quot;x&quot;)</code>를 사용하면 함정을 절반만 피한 것입니다.
• <strong>동작 방식:</strong> 중간에 있는 빈 문자열은 배열에 잘 담아줍니다. <strong>하지만, 맨 마지막에 남는 빈 문자열들은 싹 다 버려버립니다.</strong>
• <strong>결과:</strong> <code>&quot;oxooxoxxox&quot;</code> ➔ <code>[&quot;o&quot;, &quot;oo&quot;, &quot;o&quot;, &quot;&quot;, &quot;o&quot;]</code> (길이: 5)
• <strong>문제점:</strong> 문자열 맨 끝에 <code>&quot;x&quot;</code>로 끝나면서 생기는 마지막 빈 공간을 잘라내 버립니다. (정답 길이가 6이어야 하는데 5가 나옴)</p>
<h3 id="3-완벽한-해결책-splitx--1-리미트-해제"><strong>3. 완벽한 해결책: <code>split(&quot;x&quot;, -1)</code> (리미트 해제)</strong></h3>
<p>이 모든 문제를 해결하고 빈 공간을 하나도 빠짐없이 배열에 담으려면, <code>split</code> 메서드의 두 번째 파라미터인 <strong>limit(제한)</strong> 값을 조작해야 합니다.
• <strong>동작 방식:</strong> <code>split(구분자, limit)</code>에서 limit 자리에 음수(<code>-1</code>)를 넣으면, 자바에게 &quot;배열의 크기 제한을 없애고, 맨 끝에 남는 빈 문자열까지 모조리 다 배열에 담아라!&quot;라는 강력한 명령을 내리게 됩니다.
• <strong>결과:</strong> <code>&quot;oxooxoxxox&quot;</code> ➔ <code>[&quot;o&quot;, &quot;oo&quot;, &quot;o&quot;, &quot;&quot;, &quot;o&quot;, &quot;&quot;]</code> (길이: 6)
• <strong>결론:</strong> 빈 문자열까지 정확하게 카운트해야 하는 코딩 테스트 문제에서는 무조건 <code>split(&quot;구분자&quot;, -1)</code>을 사용해야 완벽한 정답을 받을 수 있습니다.</p>
<p>(대상 문자열: <code>&quot;A,,B,,,&quot;</code> / 구분자: <code>&quot;,&quot;</code>)</p>
<table>
<thead>
<tr>
<th><strong>사용 메서드</strong></th>
<th><strong>결과 배열</strong></th>
<th><strong>배열 길이</strong></th>
<th><strong>특징</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong><code>StringTokenizer</code></strong></td>
<td><code>[&quot;A&quot;, &quot;B&quot;]</code></td>
<td>2</td>
<td>연속된 구분자, 끝 구분자 모두 무시 (알맹이만 뽑음)</td>
</tr>
<tr>
<td><strong><code>split(&quot;,&quot;)</code></strong></td>
<td><code>[&quot;A&quot;, &quot;&quot;, &quot;B&quot;]</code></td>
<td>3</td>
<td>중간 빈 문자열은 살리지만, <strong>맨 끝 빈 문자열들은 버림</strong></td>
</tr>
<tr>
<td><strong><code>split(&quot;,&quot;, -1)</code></strong></td>
<td><code>[&quot;A&quot;, &quot;&quot;, &quot;B&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;]</code></td>
<td>6</td>
<td><strong>중간이든 끝이든 모든 빈 문자열을 배열에 포함! (코테 정석)</strong></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] split() 뒤에 붙는 숫자의 비밀: limit 파라미터의 3가지 마법]]></title>
            <link>https://velog.io/@hong-seo/java-split-%EB%92%A4%EC%97%90-%EB%B6%99%EB%8A%94-%EC%88%AB%EC%9E%90%EC%9D%98-%EB%B9%84%EB%B0%80-limit-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EC%9D%98-3%EA%B0%80%EC%A7%80-%EB%A7%88%EB%B2%95</link>
            <guid>https://velog.io/@hong-seo/java-split-%EB%92%A4%EC%97%90-%EB%B6%99%EB%8A%94-%EC%88%AB%EC%9E%90%EC%9D%98-%EB%B9%84%EB%B0%80-limit-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EC%9D%98-3%EA%B0%80%EC%A7%80-%EB%A7%88%EB%B2%95</guid>
            <pubDate>Fri, 10 Apr 2026 12:07:45 GMT</pubDate>
            <description><![CDATA[<p>자바에서 문자열을 자를 때 가장 많이 쓰는 메서드는 단연 <code>split()</code>입니다. 보통은 <code>split(&quot;,&quot;)</code> 처럼 구분자만 넣어서 사용하죠.</p>
<p>그런데 다른 사람의 코드를 보다 보면 <strong><code>split(&quot;,&quot;, 3)</code></strong> 이나 <strong><code>split(&quot;,&quot;, -1)</code></strong> 처럼 뒤에 정체모를 숫자가 붙어있는 것을 종종 보게 됩니다.</p>
<p>이 두 번째 파라미터의 정체는 바로 <code>limit</code>(제한)입니다. 이 숫자가 양수일 때, 0일 때, 음수일 때 완전히 다른 3가지 마법을 부리는데요. 오늘 이 3가지 차이점을 완벽하게 정리해 드리겠습니다.</p>
<p>테스트를 위해 끝에 쉼표가 2개 더 붙어있는 아래 문자열을 예시로 들어보겠습니다.
<code>String text = &quot;사과,배,포도,귤,수박,,&quot;;</code></p>
<hr>
<h3 id="1-양수-예-3-➔-최대-n조각까지만-내라">1. 양수 (예: 3) ➔ &quot;최대 N조각까지만 내라!&quot;</h3>
<p>양수는 &quot;결과 배열의 방을 최대 몇 개까지만 만들 것인가?&quot;를 뜻합니다.</p>
<pre><code class="language-jsx">String text = &quot;사과,배,포도,귤,수박,,&quot;;
String[] arr = text.split(&quot;,&quot;, 3);

System.out.println(Arrays.toString(arr));
// 결과: [&quot;사과&quot;, &quot;배&quot;, &quot;포도,귤,수박,,&quot;]</code></pre>
<p><strong>💡 자바의 속마음:*</strong>&quot;아, 최대 3조각까지만 내라고? 알겠어. 첫 번째 쉼표 자르고, 두 번째 쉼표 자르고... 앗! 벌써 방이 2개 찼네? <strong>그럼 나머지는 더 이상 자르지 말고 마지막 3번째 방에 몽땅 때려 넣어!*</strong>&quot;</p>
<ul>
<li><strong>언제 쓸까? (실무 꿀팁):</strong> 로그(Log) 파일이나 긴 문장을 처리할 때 아주 유용합니다. 앞의 몇 개 정보(날짜, 이름 등)만 떼어내고, 뒤에 있는 긴 내용은 자르지 않고 원본 그대로 보존하고 싶을 때 사용합니다.</li>
</ul>
<hr>
<h3 id="2-숫자-0-기본값-➔-다-자르되-뒤에-남는-쓰레기빈-칸는-버려라">2. 숫자 0 (기본값) ➔ &quot;다 자르되, 뒤에 남는 쓰레기(빈 칸)는 버려라!&quot;</h3>
<p>사실 우리가 평소에 쓰는 <code>split(&quot;,&quot;)</code>은 자바 내부적으로 <code>split(&quot;,&quot;, 0)</code>과 완벽하게 똑같이 동작합니다. limit을 아예 적지 않으면 자바가 알아서 0을 넣어서 계산하기 때문입니다.</p>
<pre><code class="language-jsx">String text = &quot;사과,배,포도,귤,수박,,&quot;;
String[] arr = text.split(&quot;,&quot;, 0); // text.split(&quot;,&quot;)과 완벽히 동일

System.out.println(Arrays.toString(arr));
// 결과: [&quot;사과&quot;, &quot;배&quot;, &quot;포도&quot;, &quot;귤&quot;, &quot;수박&quot;] </code></pre>
<p><strong>자바의 속마음:*</strong>&quot;구분자가 보일 때마다 전부 다 자를게! 어? 그런데 맨 끝에 쉼표가 남아서 빈 문자열(<code>&quot;&quot;</code>)이 생기네? <strong>의미 없는 빈 칸은 쓰레기니까 내가 알아서 버려줄게!*</strong>&quot;</p>
<ul>
<li><strong>특징:</strong> 우리가 가장 익숙하게 아는 방식입니다. 최대한 다 자르지만, 맨 끝에 남는 후행 빈 문자열들은 배열에 포함시키지 않고 날려버립니다.</li>
</ul>
<hr>
<h3 id="3-음수-예--1-➔-제한-해제-끝까지-다-자르고-빈-칸도-전부-살려라">3. 음수 (예: -1) ➔ &quot;제한 해제! 끝까지 다 자르고 빈 칸도 전부 살려라!&quot;</h3>
<p>음수(보통 <code>-1</code>을 씁니다)가 들어가면 자바는 <strong>&quot;limit 무한대(제한 없음)&quot;</strong> 모드로 돌입합니다.</p>
<pre><code class="language-jsx">String text = &quot;사과,배,포도,귤,수박,,&quot;;
String[] arr = text.split(&quot;,&quot;, -1);

System.out.println(Arrays.toString(arr));
// 결과: [&quot;사과&quot;, &quot;배&quot;, &quot;포도&quot;, &quot;귤&quot;, &quot;수박&quot;, &quot;&quot;, &quot;&quot;] </code></pre>
<p><strong>자바의 속마음:*</strong>&quot;제한 해제! 중간이든 맨 끝이든 쉼표가 보이면 무조건 다 자른다. <strong>그 결과로 생기는 빈 문자열(&quot;&quot;)조차도 하나의 소중한 데이터로 인정해서 배열에 모조리 담아줄게!*</strong>&quot;</p>
<ul>
<li><strong>언제 쓸까? (코딩테스트 필수):</strong> 빈 문자열도 꼬박꼬박 개수에 포함시켜야 하는 알고리즘 문제나, 엑셀/CSV 데이터처럼 빈칸 데이터가 누락되면 안 되는 상황에서 <strong>무조건</strong> 사용해야 하는 정석 코드입니다.</li>
</ul>
<table>
<thead>
<tr>
<th><strong>split 코드</strong></th>
<th><strong>파라미터 의미</strong></th>
<th><strong>결과 배열 형태</strong></th>
</tr>
</thead>
<tbody><tr>
<td><code>split(&quot;,&quot;, 3)</code></td>
<td><strong>양수</strong> (제한)</td>
<td><code>[&quot;사과&quot;, &quot;배&quot;, &quot;포도,귤,수박,,&quot;]</code></td>
</tr>
<tr>
<td><code>split(&quot;,&quot;, 0)</code></td>
<td><strong>0</strong> (기본값)</td>
<td><code>[&quot;사과&quot;, &quot;배&quot;, &quot;포도&quot;, &quot;귤&quot;, &quot;수박&quot;]</code> (뒤에 빈칸 버림)</td>
</tr>
<tr>
<td><code>split(&quot;,&quot;, -1)</code></td>
<td><strong>음수</strong> (무제한)</td>
<td><code>[&quot;사과&quot;, &quot;배&quot;, &quot;포도&quot;, &quot;귤&quot;, &quot;수박&quot;, &quot;&quot;, &quot;&quot;]</code> (빈칸 모두 살림)</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] Integer.compare와 IntStream.sum 완벽 정리]]></title>
            <link>https://velog.io/@hong-seo/java-Integer.compare%EC%99%80-IntStream.sum-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@hong-seo/java-Integer.compare%EC%99%80-IntStream.sum-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 09 Apr 2026 13:50:17 GMT</pubDate>
            <description><![CDATA[<p>자바(Java)로 알고리즘 문제를 풀거나 실무 코드를 작성하다 보면, &quot;두 숫자의 크기 비교하기&quot;와 &quot;배열 안의 숫자 모두 더하기&quot;는 숨 쉬듯 자주 마주치는 패턴입니다.</p>
<p>매번 <code>if-else</code>문과 <code>for</code>문을 쓰다 보면 코드가 길어지고 지저분해지기 마련이죠. 오늘은 이 두 가지 노가다(?) 작업을 단 한 줄로 깔끔하게 끝내주는 자바의 핵심 도우미 메서드 2가지를 소개합니다.</p>
<hr>
<h3 id="1-integercomparea-b--비교-결과를-숫자로-딱-정해줄게">1. <code>Integer.compare(A, B)</code> : &quot;비교 결과를 숫자로 딱 정해줄게!&quot;</h3>
<p>코딩 테스트를 풀다 보면 &quot;A가 B보다 크면 1, 같으면 0, 작으면 -1을 반환하라&quot;는 요구사항을 정말 자주 봅니다. 보통은 아래와 같이 코드를 작성하게 됩니다.</p>
<p><strong>기존의 방식 (길고 장황함)</strong></p>
<pre><code class="language-jsx">int a = 10;
int b = 5;

if (a &gt; b) {
    return 1;
} else if (a &lt; b) {
    return -1;
} else {
    return 0;
}</code></pre>
<p><strong>세련된 방식 (단 한 줄!)</strong></p>
<pre><code class="language-jsx">return Integer.compare(a, b);</code></pre>
<p>이 코드는 앞선 7줄짜리 <code>if-else</code>문과 <strong>완벽하게 똑같이 동작</strong>합니다.</p>
<p><strong>왜 이 메서드를 알아야 할까요?</strong>
자바에서 <code>1, 0, -1</code>을 반환하는 것은 값을 비교할 때 사용하는 <strong>가장 표준적인 약속</strong>입니다. 자바를 만든 사람들은 이 규칙을 매번 작성하는 것이 번거로울 것을 알고, 아예 <code>Integer</code> 클래스 안에 <code>compare</code>라는 함수로 만들어 두었습니다.
나중에 객체를 정렬(Sorting)할 때 쓰이는 <code>Comparator</code>나 <code>Comparable</code>을 다룰 때도 이 원리가 똑같이 적용되므로 무조건 외워두시는 것이 좋습니다!</p>
<hr>
<h3 id="2-intstreamof배열sum--for문-안-돌려도-내가-다-더해줄게">2. <code>IntStream.of(배열).sum()</code> : &quot;for문 안 돌려도 내가 다 더해줄게!&quot;</h3>
<p>배열 안에 있는 숫자들을 전부 더할 때, 우리는 무의식적으로 <code>sum</code>이라는 변수를 0으로 만들고 <code>for</code>문을 돌립니다.</p>
<p><strong>기존의 방식 (전통적인 for문)</strong></p>
<pre><code class="language-jsx">int[] arr = {1, 2, 3, 4, 5};
int sum = 0;

for (int i = 0; i &lt; arr.length; i++) {
    sum += arr[i];
}
return sum;</code></pre>
<p><strong>세련된 방식 (Stream API 활용)</strong>
자바 8부터 도입된 스트림(Stream)을 사용하면 이 과정을 한 줄로 우아하게 끝낼 수 있습니다.</p>
<pre><code class="language-jsx">int[] arr = {1, 2, 3, 4, 5};
return IntStream.of(arr).sum();</code></pre>
<p><strong>어떻게 작동하는 걸까요?</strong>
이 코드는 공장의 &#39;컨베이어 벨트&#39;를 상상하면 쉽습니다.</p>
<ol>
<li><strong><code>IntStream.of(arr)</code></strong>: 배열(<code>arr</code>)에 있는 숫자들을 작업하기 편하도록 컨베이어 벨트 위로 쫙 일렬로 올려놓습니다. <em>(참고로 <code>Arrays.stream(arr)</code>이라고 써도 완벽하게 똑같이 작동합니다!)</em></li>
<li><strong><code>.sum()</code></strong>: 벨트 맨 끝에 서서, 지나가는 숫자들을 남김없이 싹쓸이해서 더한 뒤 최종 결괏값을 툭 뱉어냅니다.</li>
</ol>
<p><code>sum()</code> 외에도 가장 큰 값을 찾는 <code>.max()</code>, 평균을 구하는 <code>.average()</code> 등 다양한 통계 기능을 기본으로 제공하므로 배열을 다룰 때 아주 강력한 무기가 됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] char 배열을 String으로 변환하기: new String()과 toString()의 차이]]></title>
            <link>https://velog.io/@hong-seo/java-char-%EB%B0%B0%EC%97%B4%EC%9D%84-String%EC%9C%BC%EB%A1%9C-%EB%B3%80%ED%99%98%ED%95%98%EA%B8%B0-new-String%EA%B3%BC-toString%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@hong-seo/java-char-%EB%B0%B0%EC%97%B4%EC%9D%84-String%EC%9C%BC%EB%A1%9C-%EB%B3%80%ED%99%98%ED%95%98%EA%B8%B0-new-String%EA%B3%BC-toString%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Tue, 07 Apr 2026 14:00:45 GMT</pubDate>
            <description><![CDATA[<p>알고리즘 문제를 풀거나 문자열을 특정 인덱스 단위로 수정해야 할 때, 문자열을 문자 배열(<code>char[]</code>)로 쪼갠 뒤 다시 합치는 작업을 자주 하게 됩니다. 이 과정에서 많은 자바 입문자들이 <code>toString()</code>을 사용했다가 엉뚱한 출력값을 보고 당황하곤 합니다.</p>
<p>오늘은 <code>char[]</code>을 <code>String</code>으로 변환하는 정석적인 방법과, 왜 다른 방식들이 실패하는지 그 이유를 명확히 정리해 보겠습니다.</p>
<hr>
<h3 id="1-new-stringarr-사용하기">1. <code>new String(arr)</code> 사용하기</h3>
<p>자바에서 가장 정석적이고 빠르게 문자 배열을 문자열로 변환하는 방법은 <strong><code>String</code> 클래스의 생성자</strong>를 사용하는 것입니다.</p>
<pre><code class="language-jsx">String myString = &quot;apple&quot;;

// 1. 문자열을 낱개 글자 배열(char[])로 분리
char[] arr = myString.toCharArray(); 

// (배열의 내용 수정 작업 진행...)
arr[0] = &#39;A&#39;;

// 2. 수정된 문자 배열을 다시 하나의 문자열로 병합
String result = new String(arr); 

System.out.println(result); // 출력: Apple</code></pre>
<p><strong>동작 원리:</strong>
자바에서 <code>String</code> 객체는 내부적으로 문자들의 배열(<code>char[]</code>) 형태로 데이터를 관리합니다.
따라서 <code>new String(arr)</code>처럼 생성자에 문자 배열을 넘겨주면, 자바는 해당 배열의 요소들을 순서대로 읽어 완벽한 형태의 새로운 <code>String</code> 객체로 재조립하여 반환해 줍니다.</p>
<hr>
<h3 id="2-왜-기존-방식에서는-주소값이나-이상한-형태가-나왔을까">2. 왜 기존 방식에서는 &#39;주소값&#39;이나 &#39;이상한 형태&#39;가 나왔을까?</h3>
<p>문자열로 바꾸기 위해 무작정 <code>.toString()</code>을 호출하거나 <code>Arrays.toString()</code>을 사용했다면 다음과 같은 실패를 겪게 됩니다. 이는 두 메서드의 본래 목적이 다르기 때문입니다.</p>
<h3 id="케이스-a-arrtostring을-쓴-경우-메모리-주소값-출력">케이스 A: <code>arr.toString()</code>을 쓴 경우 (메모리 주소값 출력)</h3>
<pre><code class="language-jsx">char[] arr = {&#39;a&#39;, &#39;p&#39;, &#39;p&#39;, &#39;l&#39;, &#39;e&#39;};
System.out.println(arr.toString()); 

// 실제 출력: [C@15db9742 (해시코드)</code></pre>
<p>배열 객체에 직접 <code>.toString()</code>을 호출하면 배열 내부의 글자들이 합쳐지는 것이 아닙니다. 자바에서 배열은 객체(Object)이므로, 최상위 클래스인 <code>Object</code>의 기본 <code>toString()</code>이 동작하여 &quot;이 객체가 위치한 메모리 주소(해시코드)&quot;를 문자열로 반환하게 됩니다.</p>
<h3 id="케이스-b-arraystostringarr을-쓴-경우-디버깅용-출력">케이스 B: <code>Arrays.toString(arr)</code>을 쓴 경우 (디버깅용 출력)</h3>
<pre><code class="language-jsx">char[] arr = {&#39;a&#39;, &#39;p&#39;, &#39;p&#39;, &#39;l&#39;, &#39;e&#39;};
System.out.println(Arrays.toString(arr)); 

// 실제 출력: [a, p, p, l, e]</code></pre>
<p><code>Arrays.toString()</code>은 배열 안의 데이터를 확인하기 위해 자바가 제공하는 <strong>배열 상태 확인용(디버깅용) 유틸리티</strong>입니다.
따라서 우리가 원하는 매끄러운 단어 형태(&quot;apple&quot;)가 아니라, 배열의 구조를 그대로 보여주는 대괄호(<code>[]</code>)와 쉼표(<code>,</code>)가 포함된 형태의 문자열을 만들어 버립니다. 알고리즘 문제의 정답(순수 문자열)으로는 사용할 수 없습니다.</p>
<hr>
<h3 id="보너스-꿀팁-실수소수-입력받기">보너스 꿀팁: 실수(소수) 입력받기</h3>
<p>문자열이나 알고리즘 문제에서 콘솔 입력을 받을 때, 데이터 타입에 맞는 파싱(Parsing) 메서드를 사용하는 것도 매우 중요합니다.</p>
<p>정수를 받을 때는 <code>Integer.parseInt()</code>를 사용하지만, 소수점이 포함된 실수 값(예: 3.14)을 입력받아야 할 때는 반드시 <code>Double</code> 클래스를 사용해야 에러(NumberFormatException)가 발생하지 않습니다.</p>
<pre><code class="language-jsx">BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

// 정수를 받을 때
int num1 = Integer.parseInt(br.readLine());

// 실수를 받을 때 (double 타입)
double num2 = Double.parseDouble(br.readLine());</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] 배열(Array)과 스트림(Stream)의 완벽한 차이점 및 관계 정리]]></title>
            <link>https://velog.io/@hong-seo/java-%EB%B0%B0%EC%97%B4Array%EA%B3%BC-%EC%8A%A4%ED%8A%B8%EB%A6%BCStream%EC%9D%98-%EC%99%84%EB%B2%BD%ED%95%9C-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EB%B0%8F-%EA%B4%80%EA%B3%84-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@hong-seo/java-%EB%B0%B0%EC%97%B4Array%EA%B3%BC-%EC%8A%A4%ED%8A%B8%EB%A6%BCStream%EC%9D%98-%EC%99%84%EB%B2%BD%ED%95%9C-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EB%B0%8F-%EA%B4%80%EA%B3%84-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Mon, 06 Apr 2026 06:06:12 GMT</pubDate>
            <description><![CDATA[<p>자바 8부터 도입된 Stream API를 처음 접하게 되면 가장 먼저 드는 의문이 있습니다.
*&quot;이미 배열(Array)이나 리스트(List)로 데이터를 잘 다루고 있었는데, 왜 굳이 스트림(Stream)이라는 것을 또 써야 할까? 둘 다 여러 개의 데이터를 다루는 것 아닌가?&quot;*</p>
<p>이 두 가지 개념을 헷갈리는 이유는 &#39;데이터를 다루는 목적&#39;이 완전히 다르다는 점을 간과하기 때문입니다. 결론부터 말씀드리면, <strong>배열은 데이터의 &#39;저장소&#39;이며 스트림은 데이터의 &#39;가공 파이프라인&#39;입니다.</strong> 오늘은 이 두 가지의 명확한 차이점과 상호보완적인 관계를 자바의 동작 원리를 통해 기술적으로 정리해 보겠습니다.</p>
<hr>
<h3 id="1-배열과-컬렉션-데이터의-보관">1. 배열과 컬렉션 (데이터의 보관)</h3>
<p>배열(<code>Array</code>)이나 자바 컬렉션 프레임워크(<code>List</code>, <code>Set</code>, <code>Map</code>)의 근본적인 목적은 <strong>메모리 상에 데이터를 안전하게 구조화하여 &#39;저장&#39;하고 &#39;유지&#39;하는 것</strong>입니다.</p>
<ul>
<li><strong>물리적인 공간 할당:</strong> 배열은 생성될 때 메모리에 물리적인 연속된 공간을 차지합니다.</li>
<li><strong>상태 유지:</strong> 데이터의 추가, 삭제, 수정 등 &#39;상태(State)&#39;를 관리하는 것이 주된 역할입니다.</li>
<li><strong>데이터의 보존:</strong> 프로그램이 종료되거나 가비지 컬렉터(GC)에 의해 소멸하기 전까지 데이터는 그 자리에 계속 남아있습니다.</li>
</ul>
<hr>
<h3 id="2-스트림-데이터의-연산과-가공">2. 스트림 (데이터의 연산과 가공)</h3>
<p>반면 스트림(<code>Stream</code>)은 데이터를 물리적으로 저장하는 자료구조가 아닙니다. 배열이나 컬렉션에 저장된 데이터를 가져와서 개발자가 원하는 대로 조작(필터링, 매핑, 정렬 등)하기 위한 &#39;연산의 흐름&#39;을 제공하는 API입니다.</p>
<ul>
<li><strong>저장하지 않음:</strong> 스트림은 요소를 저장하지 않습니다. 단지 원본 데이터(배열)에서 요소를 하나씩 소비하며 연산을 수행할 뿐입니다.</li>
<li><strong>원본의 불변성 (Immutability):</strong> 스트림은 연산 과정에서 원본 배열의 데이터를 절대 변경하지 않습니다. 가공된 새로운 결과물만 반환합니다.</li>
<li><strong>일회용 (Consumable):</strong> 스트림은 한 번 연산(최종 연산)이 끝나면 닫히며 재사용할 수 없습니다. 필요하다면 원본 배열에서 새로운 스트림을 다시 열어야 합니다.</li>
</ul>
<hr>
<h3 id="3-배열과-스트림의-관계-상호-협력">3. 배열과 스트림의 관계 (상호 협력)</h3>
<p>배열과 스트림은 경쟁 관계나 대체제가 아닙니다. &quot;배열(소스)을 기반으로 스트림(연산)을 생성하여 데이터를 가공한다&quot;는 완벽한 협력 관계를 맺고 있습니다.</p>
<p>이를 가장 명확하게 보여주는 것이 반복 방식의 차이입니다.</p>
<h3 id="외부-반복-external-iteration---배열-중심">외부 반복 (External Iteration) - 배열 중심</h3>
<p>기존의 배열 처리 방식입니다. 개발자가 직접 <code>for</code>문이나 <code>Iterator</code>를 사용하여 배열의 요소를 하나씩 꺼내오고(Pull), 그 안에서 데이터를 지지고 볶는 로직을 모두 구현해야 합니다.</p>
<pre><code class="language-jsx">// 원본 배열(소스)
List&lt;Integer&gt; numbers = Arrays.asList(1, 2, 3, 4, 5);
List&lt;Integer&gt; evenNumbers = new ArrayList&lt;&gt;();

// 외부 반복: 개발자가 직접 배열을 순회하며 제어함
for (Integer num : numbers) {
    if (num % 2 == 0) {
        evenNumbers.add(num);
    }
}</code></pre>
<h3 id="내부-반복-internal-iteration---스트림-중심">내부 반복 (Internal Iteration) - 스트림 중심</h3>
<p>스트림을 사용한 방식입니다. 개발자는 데이터 가공 로직(조건식)만 제공하고, 반복과 처리는 스트림 내부에서 알아서 수행합니다(Push)</p>
<pre><code class="language-jsx">// 원본 배열(소스)
List&lt;Integer&gt; numbers = Arrays.asList(1, 2, 3, 4, 5);

// 내부 반복: 배열에서 스트림을 생성하여 데이터 가공을 위임함
List&lt;Integer&gt; evenNumbers = numbers.stream()
                                   .filter(num -&gt; num % 2 == 0)
                                   .toList(); // (Java 16+)</code></pre>
<table>
<thead>
<tr>
<th><strong>구분</strong></th>
<th><strong>배열 및 컬렉션 (Array / Collection)</strong></th>
<th><strong>스트림 (Stream)</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>목적</strong></td>
<td>데이터의 <strong>저장</strong> 및 상태 관리</td>
<td>데이터의 <strong>연산 및 가공</strong></td>
</tr>
<tr>
<td><strong>데이터 공간</strong></td>
<td>물리적 메모리 공간을 차지함</td>
<td>저장 공간을 가지지 않음</td>
</tr>
<tr>
<td><strong>원본 변경</strong></td>
<td>요소를 직접 추가/삭제/수정할 수 있음</td>
<td>원본 데이터를 절대 변경하지 않음 (Read-only)</td>
</tr>
<tr>
<td><strong>반복 방식</strong></td>
<td><code>for</code>, <code>while</code> 등을 이용한 <strong>외부 반복</strong></td>
<td>스트림 API 내부에서 처리하는 <strong>내부 반복</strong></td>
</tr>
<tr>
<td><strong>수명</strong></td>
<td>참조가 끊어지기 전까지 영구적</td>
<td>한 번 소비되면 끝나는 일회용</td>
</tr>
</tbody></table>
<h3 id="결론">결론</h3>
<p>배열과 스트림을 혼동하지 않는 가장 좋은 방법은 역할을 완벽히 분리하는 것입니다.
데이터를 &#39;담아두고 관리&#39;해야 할 때는 배열을 고민하고, 담겨있는 데이터를 조건에 맞게 &#39;뽑아내거나 변환&#39;해야 할 때는 주저 없이 스트림 파이프라인을 구축하세요. 이 두 가지를 적절히 조화시킬 때 자바 프로그래밍의 효율성과 코드의 가독성은 극대화됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] Stream API .mapToInt(i -> i) 완벽 이해하기]]></title>
            <link>https://velog.io/@hong-seo/java-Stream-API-.mapToInti-i-%EC%99%84%EB%B2%BD-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@hong-seo/java-Stream-API-.mapToInti-i-%EC%99%84%EB%B2%BD-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 05 Apr 2026 13:08:49 GMT</pubDate>
            <description><![CDATA[<p>자바(Java)로 알고리즘 문제를 풀거나 스트림(Stream) API를 다루다 보면, 컬렉션(<code>List</code> 등)을 원시 타입 배열(<code>int[]</code>)로 변환할 때 <code>.mapToInt(i -&gt; i)</code>라는 코드를 매우 자주 사용하게 됩니다.</p>
<pre><code class="language-jsx">List&lt;Integer&gt; list = List.of(1, 2, 3);
int[] arr = list.stream().mapToInt(i -&gt; i).toArray();</code></pre>
<p>처음 이 문법을 접하면 *&quot;이게 정확히 무슨 뜻이지?&quot;<em>, *&quot;i는 Integer에서 int로 바뀌는 건가?&quot;</em>, *&quot;i 대신 다른 변수나 식을 써도 되나?&quot;* 와 같은 의문이 들 수 있습니다. 오늘은 자바 8부터 도입된 람다식(Lambda Expression)을 바탕으로 이 코드의 정확한 동작 원리와 활용법을 정리해 보겠습니다.</p>
<hr>
<h3 id="1-i---i-의-정확한-의미와-오토-언박싱-auto-unboxing">1. <code>i -&gt; i</code> 의 정확한 의미와 오토 언박싱 (Auto-Unboxing)</h3>
<p><code>i -&gt; i</code>는 자바의 람다식 문법으로, <code>입력값(Input) -&gt; 반환값(Output)</code>의 구조를 띱니다.</p>
<p><code>List&lt;Integer&gt;</code>와 같은 컬렉션에서 생성된 스트림(<code>Stream&lt;Integer&gt;</code>)을 통과하는 데이터들은 기본형 <code>int</code>가 아닌 래퍼 클래스(Wrapper Class)인 <strong><code>Integer</code> 객체</strong>입니다. <code>.mapToInt()</code> 메서드는 이 객체 스트림을 원시 타입 스트림인 <code>IntStream</code>으로 변환(매핑)하는 역할을 합니다.</p>
<ul>
<li><strong>왼쪽의 <code>i</code> (입력값):</strong> 스트림에서 전달되는 <code>Integer</code> 타입의 객체입니다.</li>
<li><strong>오른쪽의 <code>i</code> (반환값):</strong> 매핑의 결과로 반환할 값입니다. <code>.mapToInt()</code>를 사용했기 때문에 자바 컴파일러는 최종 반환 타입이 기본형 <code>int</code>여야 함을 알고 있습니다.</li>
</ul>
<p>따라서 자바 컴파일러는 들어온 <code>Integer</code> 객체를 그대로 반환할 때, 내부적으로 객체에서 원시 타입 값을 추출하는 오토 언박싱(Auto-Unboxing)을 수행하여 <code>int</code> 값으로 변환해 내보냅니다.</p>
<hr>
<h3 id="2-변수명은-자유롭게-지정-가능">2. 변수명은 자유롭게 지정 가능</h3>
<p>람다식에서 사용된 <code>i</code>는 특수한 키워드가 아니라 단순한 <strong>매개변수(Parameter) 이름</strong>일 뿐입니다. <code>for (int i = 0; i &lt; 10; i++)</code>에서 사용하는 <code>i</code>와 동일한 역할입니다.</p>
<p>따라서 코드의 가독성을 높이기 위해 개발자가 원하는 이름으로 자유롭게 변경하여 사용할 수 있으며, 모두 완벽하게 동일하게 동작합니다.</p>
<pre><code class="language-jsx">// 아래 코드는 모두 100% 동일하게 작동합니다.
.mapToInt(i -&gt; i)
.mapToInt(num -&gt; num)
.mapToInt(x -&gt; x)
.mapToInt(value -&gt; value)</code></pre>
<hr>
<h3 id="3-maptoint의-실무-및-응용-활용법">3. <code>mapToInt</code>의 실무 및 응용 활용법</h3>
<p>단순히 들어온 값을 그대로 통과시키는 것 외에도, 람다식을 조작하여 스트림 요소의 값을 입맛대로 가공하거나 추출할 수 있습니다.</p>
<h3 id="①-값에-연산-적용하기">① 값에 연산 적용하기</h3>
<p>스트림을 통과하는 데이터에 즉각적으로 수학적 연산을 적용하여 매핑할 수 있습니다. 예를 들어 모든 요소의 값을 2배로 만들고 싶다면 아래와 같이 작성합니다.</p>
<pre><code class="language-jsx">// 들어온 x를 2배(x * 2)로 연산하여 IntStream으로 반환
int[] arr = list.stream().mapToInt(x -&gt; x * 2).toArray();</code></pre>
<h3 id="②-메서드-참조-method-reference-사용">② 메서드 참조 (Method Reference) 사용</h3>
<p><code>i -&gt; i</code>를 통한 오토 언박싱에 의존하는 대신, <code>Integer</code> 클래스가 가진 <code>intValue()</code> 메서드를 직접 호출하라고 명시할 수 있습니다. 이 방식은 자바의 <strong>메서드 참조(Method Reference)</strong> 문법으로, 실무에서 더 명확하고 정석적인 코딩 스타일로 권장됩니다.</p>
<pre><code class="language-jsx">// i -&gt; i 와 동일하게 동작하며, 더 명시적인 표현 방식입니다.
int[] arr = list.stream().mapToInt(Integer::intValue).toArray();</code></pre>
<h3 id="③-다른-타입의-데이터에서-int-값-추출하기">③ 다른 타입의 데이터에서 <code>int</code> 값 추출하기</h3>
<p>스트림의 원본 데이터가 <code>Integer</code>가 아닌 전혀 다른 객체(<code>String</code> 등)일 때도 유용하게 사용됩니다. 객체 내부의 특정 값을 추출하거나 변환하여 <code>IntStream</code>을 생성할 수 있습니다.</p>
<p><strong>예시 A: 문자열 리스트를 정수 배열로 변환</strong></p>
<pre><code class="language-jsx">List&lt;String&gt; strList = List.of(&quot;10&quot;, &quot;20&quot;, &quot;30&quot;);

// 문자열 객체(str)를 받아 파싱(Integer.parseInt) 후 int로 반환
int[] parsedArr = strList.stream().mapToInt(str -&gt; Integer.parseInt(str)).toArray();
// 결과: [10, 20, 30]</code></pre>
<p><strong>예시 B: 문자열 객체에서 &#39;길이&#39; 데이터만 추출</strong></p>
<pre><code class="language-jsx">List&lt;String&gt; words = List.of(&quot;apple&quot;, &quot;banana&quot;, &quot;kiwi&quot;);

// 문자열 객체(word)를 받아 길이(length)를 int로 반환
int[] lengths = words.stream().mapToInt(word -&gt; word.length()).toArray();
// 결과: [5, 6, 4]</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] 배열 출력(Arrays.toString)과 리스트 변환(toArray)의 동작 원리 이해하기]]></title>
            <link>https://velog.io/@hong-seo/java-%EB%B0%B0%EC%97%B4-%EC%B6%9C%EB%A0%A5Arrays.toString%EA%B3%BC-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EB%B3%80%ED%99%98toArray%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@hong-seo/java-%EB%B0%B0%EC%97%B4-%EC%B6%9C%EB%A0%A5Arrays.toString%EA%B3%BC-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EB%B3%80%ED%99%98toArray%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 05 Apr 2026 12:10:03 GMT</pubDate>
            <description><![CDATA[<p>자바에서 배열(Array)과 리스트(ArrayList)를 다룰 때 자주 마주치는 두 가지 현상이 있습니다. 배열을 출력할 때 발생하는 해시코드 출력 문제와, <code>ArrayList</code>를 배열로 변환할 때 <code>new String[0]</code>을 인자로 넘기는 이유입니다.</p>
<p>오늘은 이 두 가지 문법의 정확한 동작 원리를 자바의 내부 메커니즘을 통해 설명하겠습니다.</p>
<hr>
<h3 id="1-배열-출력-시-arraystostring을-사용하는-이유">1. 배열 출력 시 Arrays.toString()을 사용하는 이유</h3>
<p>배열을 생성하고 <code>System.out.println()</code>으로 직접 출력하면 배열의 요소가 아닌 식별할 수 없는 문자열이 출력됩니다.</p>
<pre><code class="language-jsx">String[] arr = {&quot;apple&quot;, &quot;banana&quot;, &quot;cherry&quot;};
System.out.println(arr); 

// 출력 결과: [Ljava.lang.String;@15db9742</code></pre>
<p><strong>동작 원리:</strong>
자바에서 배열은 원시 타입(Primitive type)이 아닌 객체(Object)로 취급됩니다. 따라서 <code>System.out.println()</code> 메서드에 배열 객체를 넘기면 내부적으로 최상위 클래스인 <code>Object</code>의 <code>toString()</code> 메서드가 호출됩니다.
<code>Object.toString()</code>은 기본적으로 <code>[객체의 타입 시그니처 + @ + 메모리 주소(해시코드)]</code> 형태의 문자열을 반환하도록 구현되어 있습니다. 따라서 위와 같은 결과가 나오는 것입니다.</p>
<p><strong>해결 방법:</strong>
배열 내부에 존재하는 실제 데이터 요소들을 확인하려면 <code>java.util.Arrays</code> 클래스의 <strong><code>Arrays.toString()</code></strong> 메서드를 사용해야 합니다.</p>
<pre><code class="language-jsx">System.out.println(Arrays.toString(arr)); 
// 출력 결과: [apple, banana, cherry]</code></pre>
<p><code>Arrays.toString()</code>은 내부적으로 <code>for</code>문을 돌며 배열의 각 요소(element)에 접근하여 하나의 조합된 문자열(String)로 반환해주기 때문에, 우리가 원하는 데이터를 직관적으로 확인할 수 있습니다.</p>
<hr>
<h3 id="2-arraylisttoarray에-new-string0을-넘기는-이유">2. ArrayList.toArray()에 new String[0]을 넘기는 이유</h3>
<p><code>ArrayList</code>를 일반 배열로 변환할 때, 단순히 <code>toArray()</code> 메서드만 호출하지 않고 특정 타입의 빈 배열(<code>new String[0]</code>)을 매개변수로 전달하는 방식을 주로 사용합니다.</p>
<pre><code class="language-jsx">ArrayList&lt;String&gt; list = new ArrayList&lt;&gt;();
list.add(&quot;A&quot;);
list.add(&quot;B&quot;);

// ArrayList를 배열로 변환
String[] arr = list.toArray(new String[0]);</code></pre>
<p>이 코드가 작성되는 이유는 크게 두 가지 기술적 배경을 갖습니다.</p>
<h3 id="1-제네릭generic의-타입-소거type-erasure">1) 제네릭(Generic)의 타입 소거(Type Erasure)</h3>
<p>자바의 제네릭은 컴파일 타임에만 타입 안정성을 검사하고, <strong>런타임(실행 시간)에는 타입 정보가 지워지는 &#39;타입 소거&#39;</strong> 특징을 가집니다.
즉, <code>ArrayList&lt;String&gt;</code>은 컴파일이 끝나면 내부적으로 데이터를 <code>Object</code> 타입으로 관리합니다. 따라서 매개변수 없이 <code>list.toArray()</code>를 호출하면 반환되는 배열의 타입은 <code>String[]</code>이 아닌 <code>Object[]</code>가 되어버립니다.
이를 해결하기 위해 <code>new String[0]</code>이라는 <strong>타입 지정용 인스턴스</strong>를 넘겨주어, 반환받을 배열의 타입이 <code>String</code>임을 명시하는 것입니다.</p>
<h3 id="2-왜-하필-크기가-0인-배열new-string0인가">2) 왜 하필 크기가 0인 배열(new String[0])인가?</h3>
<p>인자로 넘긴 배열의 크기가 리스트의 실제 데이터 크기보다 작을 경우, 자바의 <code>toArray()</code> 메서드는 내부적으로 다음과 같이 동작합니다.</p>
<ol>
<li>전달받은 배열의 크기가 부족하므로 해당 배열을 사용하지 않는다.</li>
<li>전달받은 배열의 &#39;타입&#39;만 참조하여, 리스트의 <code>size</code>와 동일한 크기의 새로운 배열을 내부적으로 메모리에 할당한다.</li>
<li>데이터를 새로운 배열에 복사하여 반환한다.</li>
</ol>
<p>과거에는 메모리 할당 비용을 줄이기 위해 <code>list.toArray(new String[list.size()])</code>처럼 리스트의 크기를 직접 계산해서 넘기는 방식이 권장되었습니다.
하지만 <strong>최신 JVM(Java 6 이후)에서는 길이가 0인 배열을 전달하는 것이 오히려 성능상 더 유리하도록 최적화</strong>되었습니다. 사전에 크기를 명시하는 방식은 리플렉션(Reflection) 비용과 동기화 오버헤드가 발생할 수 있기 때문에, 빈 배열(<code>new String[0]</code>)을 넘겨 JVM이 내부적으로 최적화된 방식으로 새 배열을 생성하도록 위임하는 것이 현재의 표준 컨벤션입니다.</p>
<h4 id="plus">Plus</h4>
<ul>
<li><strong><code>Arrays.toString(배열)</code></strong>: <strong>1차원 배열</strong>의 내용물을 깔끔하게 보여준다.</li>
<li><strong><code>Arrays.deepToString(배열)</code></strong>: 2차원 배열뿐만 아니라, <strong>3차원, 4차원 등 모든 다차원 배열</strong>의 내부 값을 보여준다.</li>
</ul>
<p>2차원 배열이상에서 행의 길이를 알고 싶으면 arr[i].length;로 사용한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] ArrayList를 int[] 배열로 변환하는 가장 깔끔한 방법]]></title>
            <link>https://velog.io/@hong-seo/java-ArrayList%EB%A5%BC-int-%EB%B0%B0%EC%97%B4%EB%A1%9C-%EB%B3%80%ED%99%98%ED%95%98%EB%8A%94-%EA%B0%80%EC%9E%A5-%EA%B9%94%EB%81%94%ED%95%9C-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@hong-seo/java-ArrayList%EB%A5%BC-int-%EB%B0%B0%EC%97%B4%EB%A1%9C-%EB%B3%80%ED%99%98%ED%95%98%EB%8A%94-%EA%B0%80%EC%9E%A5-%EA%B9%94%EB%81%94%ED%95%9C-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sat, 04 Apr 2026 12:58:07 GMT</pubDate>
            <description><![CDATA[<p>알고리즘 문제를 풀다 보면 결과값의 크기를 미리 알 수 없어 동적 배열인 <code>ArrayList</code>에 데이터를 담아두는 경우가 많습니다. 하지만 문제의 반환 타입(Return Type)이 기본형 배열인 <code>int[]</code>로 고정되어 있다면 타입 불일치 문제가 발생합니다.</p>
<pre><code class="language-jsx">public static int[] solution(int[] num_list, int n) {
    ArrayList&lt;Integer&gt; list = new ArrayList&lt;&gt;();

    for(int i = 0; i &lt; num_list.length; i += n) {
        list.add(num_list[i]);
    }

    // 컴파일 에러: ArrayList&lt;Integer&gt;를 int[]로 바로 반환할 수 없음
    return list; 
}</code></pre>
<p><code>ArrayList</code>의 <code>toArray()</code> 메서드를 사용하더라도 <code>Integer[]</code>나 <code>Object[]</code>로만 변환될 뿐, 원시 타입(Primitive Type)인 <code>int[]</code>로는 바로 변환되지 않습니다.</p>
<p>이때 자바 8부터 도입된 <strong>Stream API</strong>를 사용하면 이 형변환 과정을 단 한 줄의 코드로 우아하게 처리할 수 있습니다.</p>
<pre><code class="language-jsx">`return list.stream().mapToInt(i -&gt; i).toArray();`</code></pre>
<p>이 코드가 내부적으로 어떻게 동작하여 <code>ArrayList&lt;Integer&gt;</code>를 <code>int[]</code>로 변환하는지 3단계로 나누어 살펴보겠습니다.</p>
<h3 id="stream-api-변환-파이프라인-분석">Stream API 변환 파이프라인 분석</h3>
<h3 id="1-stream--객체-스트림-생성"><strong>1. <code>.stream()</code> : 객체 스트림 생성</strong></h3>
<p>가장 먼저 컬렉션(<code>ArrayList</code>)을 스트림으로 변환합니다.</p>
<ul>
<li><code>list.stream()</code>을 호출하면 <code>ArrayList</code>에 담긴 데이터들을 순차적으로 처리할 수 있는 <code>Stream&lt;Integer&gt;</code> 타입의 객체 스트림이 생성됩니다.</li>
<li>이 단계에서는 여전히 데이터가 래퍼 클래스(Wrapper Class)인 <code>Integer</code> 객체 형태로 존재합니다.</li>
</ul>
<h3 id="2-maptointi---i--intstream-변환-및-오토-언박싱-auto-unboxing"><strong>2. <code>.mapToInt(i -&gt; i)</code> : IntStream 변환 및 오토 언박싱 (Auto-Unboxing)</strong></h3>
<p>스트림의 요소를 기본형 스트림으로 변환하는 핵심 단계입니다.</p>
<ul>
<li><code>mapToInt()</code> 메서드는 기존의 <code>Stream&lt;Integer&gt;</code>를 원시 타입 스트림인 <code>IntStream</code>으로 매핑(Mapping)합니다.</li>
<li>매개변수로 전달된 람다식 <code>i -&gt; i</code>는 들어온 <code>Integer</code> 객체를 그대로 반환하라는 의미입니다.</li>
<li>이때, 자바 컴파일러는 내부적으로 <code>Integer</code> 객체에서 기본형 <code>int</code> 값을 추출하는 오토 언박싱(Auto-Unboxing)을 수행합니다.</li>
<li><em>(참고: 람다식 대신 메서드 참조인 <code>Integer::intValue</code>를 사용하면 언박싱 과정을 더 명시적으로 표현할 수 있습니다.)</em></li>
</ul>
<h3 id="3-toarray--배열로-수집-종단-연산"><strong>3. <code>.toArray()</code> : 배열로 수집 (종단 연산)</strong></h3>
<p>변환된 스트림 데이터를 최종적으로 배열로 묶어냅니다.</p>
<ul>
<li>스트림 파이프라인의 최종 연산(Terminal Operation)입니다.</li>
<li>언박싱되어 <code>IntStream</code>을 통과한 순수 <code>int</code> 값들을 모아, 새로운 <code>int[]</code> 배열을 메모리에 할당하고 값을 복사한 뒤 이를 반환합니다.</li>
</ul>
<h3 id="요약">요약</h3>
<p><code>list.stream().mapToInt(i -&gt; i).toArray()</code>는 단순한 마법이 아니라, <strong>스트림 생성 ➔ 객체의 언박싱 매핑 ➔ 원시 타입 배열로의 수집</strong>이라는 명확한 자바의 동작 방식을 따르고 있습니다.</p>
<p>반복문을 직접 작성하여 배열로 옮겨 담는 것(<code>for</code>문 사용)보다 성능 오버헤드는 아주 미세하게 존재할 수 있으나, 가독성과 유지보수성이 압도적으로 뛰어나기 때문에 실무와 코딩 테스트에서 가장 널리 권장되는 방식입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] for (char c : str.toCharArray()) 숨겨진 작동 원리 알고 쓰기]]></title>
            <link>https://velog.io/@hong-seo/java-for-char-c-str.toCharArray-%EC%88%A8%EA%B2%A8%EC%A7%84-%EC%9E%91%EB%8F%99-%EC%9B%90%EB%A6%AC-%EC%95%8C%EA%B3%A0-%EC%93%B0%EA%B8%B0</link>
            <guid>https://velog.io/@hong-seo/java-for-char-c-str.toCharArray-%EC%88%A8%EA%B2%A8%EC%A7%84-%EC%9E%91%EB%8F%99-%EC%9B%90%EB%A6%AC-%EC%95%8C%EA%B3%A0-%EC%93%B0%EA%B8%B0</guid>
            <pubDate>Thu, 02 Apr 2026 09:31:24 GMT</pubDate>
            <description><![CDATA[<p>자바(Java)로 알고리즘 문제를 풀거나 문자열을 다룰 때, 문자열 안의 글자를 하나씩 꺼내서 확인해야 하는 경우가 정말 많습니다. 아마 자바를 처음 배우셨다면 아래와 같은 코드가 가장 익숙하실 겁니다.</p>
<p><strong>기존 방식 (<code>charAt</code> 사용)</strong></p>
<pre><code class="language-jsx">String str = &quot;hello&quot;;
for (int i = 0; i &lt; str.length(); i++) {
    char c = str.charAt(i);
    System.out.println(c);
}</code></pre>
<p>물론 이 코드도 훌륭하게 작동하지만, 매번 <code>length()</code>를 부르고 <code>i</code> 값을 관리하며 <code>charAt(i)</code>를 쓰는 과정이 조금 번거롭고 코드가 길어집니다.</p>
<p>하지만 자바에는 이 과정을 아주 우아하게 단 한 줄로 끝내버리는 마법 같은 문법이 있습니다.</p>
<p><strong>향상된 방식 (<code>toCharArray</code> 사용)</strong></p>
<pre><code class="language-jsx">String str = &quot;hello&quot;;
for (char c : str.toCharArray()) {
    System.out.println(c);
}</code></pre>
<p>코드가 정말 깔끔해지지 않았나요? 오늘은 이 한 줄의 코드가 내부적으로 어떻게 작동하는지 두 단계로 쪼개서 아주 쉽게 파헤쳐 보겠습니다.</p>
<hr>
<h3 id="1단계-tochararray의-역할">1단계: <code>toCharArray()</code>의 역할</h3>
<p>자바에서 <code>String</code> (문자열)은 단순한 글자의 나열이 아니라, 꽁꽁 포장된 거대한 객체(상자)입니다. 그래서 &quot;상자 안에 있는 글자를 하나씩 차례대로 꺼내줘!&quot;라는 명령을 곧바로 내릴 수가 없습니다.</p>
<p>이때 <strong><code>toCharArray()</code></strong> 메서드를 사용하면, 자바가 문자열 객체의 포장을 뜯어서 안에 들어있던 낱개 글자들을 새로운 문자 배열(<code>char[]</code>)로 만들어 줍니다.</p>
<ul>
<li><code>str = &quot;hello&quot;;</code> (포장된 문자열 객체)</li>
<li><code>str.toCharArray()</code> 실행 ➔ <code>[&#39;h&#39;, &#39;e&#39;, &#39;l&#39;, &#39;l&#39;, &#39;o&#39;]</code> 라는 <strong>배열 탄생!</strong></li>
</ul>
<hr>
<h3 id="2단계-향상된-for문-for-each-작동-원리">2단계: 향상된 for문 (for-each) 작동 원리</h3>
<p>이제 코드는 이렇게 변한 것과 같습니다.
<code>for (char c : [&#39;h&#39;, &#39;e&#39;, &#39;l&#39;, &#39;l&#39;, &#39;o&#39;])</code></p>
<p>자바 5부터 도입된 이 문법은 &quot;향상된 for문(Enhanced for loop)&quot;이라고 부릅니다. 배열이나 리스트 같은 바구니 안의 내용물을 처음부터 끝까지 아주 편하게 꺼내줍니다.</p>
<blockquote>
<p><strong>작동 규칙:</strong> <code>for ( 담을_변수 : 털어낼_바구니(배열) )</code></p>
</blockquote>
<ol>
<li>자바가 오른쪽 배열에서 첫 번째 값인 <code>&#39;h&#39;</code>를 꺼냅니다.</li>
<li>왼쪽의 <code>char c</code> 변수에 <code>&#39;h&#39;</code>를 쏙 집어넣고 블록(<code>{ }</code>) 안의 코드를 실행합니다.</li>
<li>코드가 끝나면 다시 올라와서 두 번째 값인 <code>&#39;e&#39;</code>를 꺼내 <code>c</code>에 넣고 실행합니다.</li>
<li>배열에 더 이상 꺼낼 글자가 없을 때까지 알아서 반복한 뒤 종료합니다.</li>
</ol>
<hr>
<h3 id="컴퓨터는-속으로-무슨-생각을-할까-진실">컴퓨터는 속으로 무슨 생각을 할까? (진실)</h3>
<p>우리가 저렇게 짧고 예쁘게 코드를 쓰면, 자바 컴파일러(번역기)가 컴퓨터가 알아들을 수 있도록 코드를 몰래 옛날 방식으로 풀어버립니다. 즉, 향상된 for문은 개발자를 편하게 해주는 Syntactic Sugar입니다.</p>
<p><strong>실제 자바가 내부적으로 실행하는 코드:</strong></p>
<pre><code class="language-jsx">char[] tempArray = str.toCharArray(); // 1. 배열을 하나 새로 만든다.
for (int i = 0; i &lt; tempArray.length; i++) { // 2. 길이를 계산해서 0부터 끝까지 돈다.
    char c = tempArray[i]; // 3. 인덱스 번호로 하나씩 꺼내서 변수에 담아준다.
    System.out.println(c);
}</code></pre>
<hr>
<h3 id="장점과-단점-언제-써야-할까">장점과 단점 (언제 써야 할까?)</h3>
<p>이 완벽해 보이는 코드에도 상황에 따라 장단점이 존재합니다.</p>
<p><strong>장점</strong></p>
<ol>
<li><strong>가독성 극대화:</strong> <code>i</code> 같은 인덱스 변수를 쓰지 않아서 코드가 훨씬 깔끔하고 읽기 좋습니다.</li>
<li><strong>에러 원천 차단:</strong> 인덱스 계산 실수를 할 일이 없으므로 무서운 <code>ArrayIndexOutOfBoundsException</code> 에러를 만날 일이 없습니다.</li>
</ol>
<p><strong>단점 (주의할 점)</strong></p>
<ol>
<li><strong>현재 위치(<code>i</code>)를 모름:</strong> 반복문을 돌다가 &quot;지금이 몇 번째 글자지?&quot;를 알아야 하는 로직이라면 사용할 수 없습니다. (이때는 기존의 기본 <code>for</code>문을 써야 합니다.)</li>
<li><strong>미세한 메모리 사용:</strong> <code>toCharArray()</code>가 내부적으로 새로운 배열을 생성하기 때문에, 극한의 메모리 최적화가 필요한 환경에서는 주의해야 합니다. (하지만 일반적인 실무나 코딩 테스트에서는 무시해도 될 수준입니다!)</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] 문자열 제어 최적화: if문 vs switch문 vs 배열 매핑]]></title>
            <link>https://velog.io/@hong-seo/java-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%A0%9C%EC%96%B4-%EC%B5%9C%EC%A0%81%ED%99%94-if%EB%AC%B8-vs-switch%EB%AC%B8-vs-%EB%B0%B0%EC%97%B4-%EB%A7%A4%ED%95%91</link>
            <guid>https://velog.io/@hong-seo/java-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%A0%9C%EC%96%B4-%EC%B5%9C%EC%A0%81%ED%99%94-if%EB%AC%B8-vs-switch%EB%AC%B8-vs-%EB%B0%B0%EC%97%B4-%EB%A7%A4%ED%95%91</guid>
            <pubDate>Thu, 02 Apr 2026 09:27:37 GMT</pubDate>
            <description><![CDATA[<p>자바(Java)로 알고리즘 문제를 풀거나 실무를 하다 보면, 문자열에 포함된 특정 문자(예: &#39;w&#39;, &#39;a&#39;, &#39;s&#39;, &#39;d&#39;)에 따라 변수의 값을 다르게 조작해야 하는 경우가 자주 발생합니다.</p>
<p>가장 먼저 떠오르는 방법은 <code>if-else</code>문이겠지만, 상황에 따라 <strong>가독성을 높이거나 실행 속도를 극한으로 끌어올리는 다양한 방법</strong>이 있습니다. 오늘은 문자열 제어문을 처리하는 4가지 단계를 소개합니다.</p>
<hr>
<h2 id="1-기본-중의-기본-if-else문-활용">1. 기본 중의 기본: <code>if-else</code>문 활용</h2>
<p>가장 직관적이고 기본적인 방법입니다. 문자열의 길이만큼 반복문을 돌면서 하나씩 조건을 검사합니다.</p>
<pre><code class="language-jsx">public int solution(int n, String control) {
    int count = control.length();
    for (int i = 0; i &lt; count; i++) {
        if (control.charAt(i) == &#39;w&#39;) {
            n += 1;
        } else if (control.charAt(i) == &#39;s&#39;) {
            n -= 1;
        } else if (control.charAt(i) == &#39;d&#39;) {
            n += 10;
        } else if (control.charAt(i) == &#39;a&#39;) {
            n -= 10;
        }
    }
    return n;
}</code></pre>
<p>동작에는 전혀 문제가 없지만, 조건이 많아질수록 코드가 길어지고 <code>else if</code>를 계속 타야 하므로 미세한 성능 저하가 발생할 수 있습니다.</p>
<hr>
<h2 id="2-성능과-가독성을-한-번에-향상된-switch문">2. 성능과 가독성을 한 번에: 향상된 <code>switch</code>문</h2>
<p><code>if-else</code>문보다 미세하지만 더 효율적이고 가독성도 훨씬 좋은 것이 바로 <code>switch</code>문입니다. 특히 Java 14부터 지원하는 화살표(<code>-&gt;</code>) 문법을 사용하면 코드가 예술적으로 깔끔해집니다.</p>
<pre><code class="language-jsx">public int solution(int n, String control) {
    for (int i = 0; i &lt; control.length(); i++) {
        switch (control.charAt(i)) {
            case &#39;w&#39; -&gt; n += 1;
            case &#39;s&#39; -&gt; n -= 1;
            case &#39;d&#39; -&gt; n += 10;
            case &#39;a&#39; -&gt; n -= 10;
        }
    }
    return n;
}</code></pre>
<p><strong>왜 더 빠를까요?</strong>
자바에서 <code>switch</code>문은 컴파일될 때 내부적으로 &#39;해당 위치로 바로 점프&#39;하는 방식(<code>tableswitch</code> 또는 <code>lookupswitch</code>)으로 최적화됩니다. 따라서 위에서부터 아래로 조건을 하나씩 다 검사해야 하는 <code>if-else</code>문보다 조건이 많을수록 더 빠른 성능을 보여줍니다.</p>
<hr>
<h2 id="3-실무코테-추천-스타일-tochararray--향상된-for문">3. 실무/코테 추천 스타일: <code>toCharArray()</code> + 향상된 <code>for</code>문</h2>
<p>인덱스 <code>i</code>를 써서 <code>charAt(i)</code>로 접근하는 대신, 문자열을 문자 배열(<code>char[]</code>)로 바꿔서 <strong>향상된 for문</strong>을 쓰면 코드가 훨씬 읽기 편해집니다.</p>
<pre><code class="language-jsx">public int solution(int n, String control) {
    for (char c : control.toCharArray()) {
        switch (c) {
            case &#39;w&#39; -&gt; n += 1;
            case &#39;s&#39; -&gt; n -= 1;
            case &#39;d&#39; -&gt; n += 10;
            case &#39;a&#39; -&gt; n -= 10;
        }
    }
    return n;
}</code></pre>
<p>가장 권장하는 스타일입니다. 코딩 테스트에서 작성 속도도 빠르고, 다른 개발자가 읽기에도 가장 직관적입니다.</p>
<hr>
<h2 id="4-극한의-성능-최적화-배열-매핑-조건문-없애기">4. 극한의 성능 최적화: 배열 매핑 (조건문 없애기)</h2>
<p>만약 <code>control</code> 문자열의 길이가 1억 개쯤 되어서 &quot;0.001초라도 실행 속도를 더 줄이고 싶다!&quot;면 어떻게 해야 할까요?
이럴 때는 아예 <code>if</code>나 <code>switch</code> 같은 <strong>조건문 자체를 없애버리는 방법</strong>을 쓸 수 있습니다. 문자가 내부적으로는 아스키코드(숫자)라는 점을 이용하는 것입니다.</p>
<pre><code class="language-jsx">public int solution(int n, String control) {
    // 알파벳 소문자 아스키코드의 최대값(z=122)을 덮을 수 있는 넉넉한 크기의 배열 생성
    int[] move = new int[128]; 

    // 각 문자에 해당하는 위치에 변화량을 미리 적어둡니다.
    move[&#39;w&#39;] = 1;
    move[&#39;s&#39;] = -1;
    move[&#39;d&#39;] = 10;
    move[&#39;a&#39;] = -10;

    // 조건문(분기) 없이 배열 인덱스로 접근해 그냥 값을 더해버립니다!
    for (int i = 0; i &lt; control.length(); i++) {
        n += move[control.charAt(i)];
    }
    return n;
}</code></pre>
<p><strong>이게 왜 압도적으로 빠를까요?</strong>
CPU는 코드 실행 중 <code>if</code>나 <code>switch</code> 같은 조건문을 만날 때마다 &quot;다음엔 어느 쪽으로 갈까?&quot; 하고 예측(분기 예측, Branch Prediction)을 하느라 시간을 씁니다. 하지만 이 방식은 그런 고민 없이 <strong>배열에서 값을 바로 꺼내 더하기만 하므로</strong> 압도적으로 빠른 속도를 자랑합니다. 알고리즘 고수들이 종종 쓰는 테크닉입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] StringTokenizer의 함정과 문자열 처리 꿀팁]]></title>
            <link>https://velog.io/@hong-seo/java-StringTokenizer%EC%9D%98-%ED%95%A8%EC%A0%95%EA%B3%BC-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%B2%98%EB%A6%AC-%EA%BF%80%ED%8C%81</link>
            <guid>https://velog.io/@hong-seo/java-StringTokenizer%EC%9D%98-%ED%95%A8%EC%A0%95%EA%B3%BC-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%B2%98%EB%A6%AC-%EA%BF%80%ED%8C%81</guid>
            <pubDate>Wed, 01 Apr 2026 16:32:09 GMT</pubDate>
            <description><![CDATA[<p>자바(Java)로 알고리즘 문제를 풀거나 문자열을 다루다 보면, 로직은 완벽한 것 같은데 이상하게 에러가 나거나 결과가 중간에 잘리는 경험을 하곤 합니다. 오늘은 자바 입문자들이 가장 많이 겪는 <strong>문자열 처리 관련 3가지 실수와 올바른 해결법</strong>을 정리해 보았습니다.</p>
<h3 id="1-stringtokenizer의-함정-counttokens는-고정값이-아니다">1. <code>StringTokenizer</code>의 함정: <code>countTokens()</code>는 고정값이 아니다!</h3>
<p>토큰의 개수만큼 배열을 만들고, 반복문을 돌려 값을 채워 넣는 아래 코드를 볼까요?</p>
<p> <strong>잘못된 방식</strong></p>
<pre><code class="language-jsx">BufferedReader br = new BufferedReader(new InputStreamReader([System.in](http://system.in/)));
StringTokenizer st = new StringTokenizer(br.readLine().replace(&quot;\&quot;&quot;, &quot;&quot;), &quot;, &quot;);
String[] arr = new String[st.countTokens()];
// 함정 발생 구간!
for(int i = 0; i &lt; st.countTokens(); i++){
    arr[i] = st.nextToken();
}</code></pre>
<p>언뜻 보면 문제없어 보이지만, 이 코드는 배열을 끝까지 채우지 못하고 중간에 멈춰버립니다.</p>
<p>이유는 <strong><code>st.nextToken()</code>을 호출할 때마다 남아있는 토큰이 줄어들면서 <code>st.countTokens()</code>의 값도 계속 작아지기 때문</strong>입니다. (처음엔 3개여서 통과 ➔ 다음 바퀴엔 2개 ➔ 1개... 결국 반복문이 일찍 종료됩니다.)</p>
<p><strong>올바른 방식</strong></p>
<pre><code class="language-jsx">int count = st.countTokens(); // 변수에 미리 개수를 고정해둔다!
String[] arr = new String[count];

for(int i = 0; i &lt; count; i++){
    arr[i] = st.nextToken();
}</code></pre>
<p>반드시 <code>count</code>라는 변수에 초기 토큰 개수를 미리 저장해두고, 그 고정된 숫자를 기준으로 반복문을 돌려야 합니다.</p>
<hr>
<h3 id="2-stringjoin의-올바른-사용법">2. <code>String.join</code>의 올바른 사용법</h3>
<p>배열에 있는 문자열들을 하나로 합치고 싶을 때, 굳이 반복문을 돌릴 필요가 없습니다.</p>
<p><strong>잘못된 방식 (반복문 사용)</strong></p>
<pre><code class="language-jsx">String answer = &quot;&quot;;
for(int i = 0; i &lt; arr.length; i++){
    answer = String.join(arr[i]); // 이렇게 쓰면 안 됩니다!
}</code></pre>
<p><strong>올바른 방식 (한 줄로 끝내기)</strong></p>
<pre><code class="language-jsx">return String.join(&quot;&quot;, arr);</code></pre>
<p><code>String.join</code>은 반복문 없이 배열 전체를 한 번에 합쳐주는 마법 같은 메서드입니다. 첫 번째 인자로 들어가는 <code>&quot;&quot;</code>는 <strong>구분자</strong>입니다. 빈 문자열(<code>&quot;&quot;</code>)을 주면 글자 사이에 아무것도 넣지 않고(<code>&quot;abc&quot;</code>) 다닥다닥 예쁘게 붙여줍니다.</p>
<hr>
<h3 id="3-홑따옴표-vs-쌍따옴표-완벽-구분">3. 홑따옴표(<code>&#39;&#39;</code>) vs 쌍따옴표(<code>&quot;&quot;</code>) 완벽 구분</h3>
<p>파이썬이나 자바스크립트와 달리, 자바는 따옴표의 종류에 아주 엄격합니다.</p>
<table>
<thead>
<tr>
<th><strong>구분</strong></th>
<th><strong>홑따옴표 (&#39;w&#39;)</strong></th>
<th><strong>쌍따옴표 (&quot;w&quot;)</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>데이터 타입</strong></td>
<td><code>char</code> (기본형)</td>
<td><code>String</code> (참조형/객체)</td>
</tr>
<tr>
<td><strong>의미</strong></td>
<td>딱 <strong>한 글자</strong>의 &#39;문자&#39;</td>
<td>글자들의 모음인 <strong>&#39;문자열&#39;</strong></td>
</tr>
<tr>
<td><strong>비교 방법</strong></td>
<td><code>==</code> 연산자 사용</td>
<td><code>.equals()</code> 메서드 사용</td>
</tr>
</tbody></table>
<h3 id="왜-charat3--w는-컴파일-에러가-날까">왜 <code>charAt(3) == &quot;w&quot;</code>는 컴파일 에러가 날까?</h3>
<p><code>string.charAt(3)</code>은 문자열에서 3번 인덱스에 있는 딱 한 글자(<code>char</code>)만 쏙 뽑아옵니다.</p>
<ul>
<li><p><strong>왼쪽:</strong> <code>string.charAt(3)</code> ➔ <code>char</code> 타입</p>
</li>
<li><p><strong>오른쪽:</strong> <code>&quot;w&quot;</code> ➔ <code>String</code> 타입</p>
<p>  자바 입장에서는 <strong>&quot;가벼운 기본형 문자(<code>char</code>)와 무거운 객체(<code>String</code>)는 태생부터 달라서 비교할 수 없어!&quot;</strong> 라며 에러를 냅니다.</p>
</li>
</ul>
<h3 id="올바른-비교-방법">올바른 비교 방법</h3>
<p><strong>1. 같은 <code>char</code> 타입으로 비교하기 (추천)</strong></p>
<pre><code class="language-jsx">if (string.charAt(3) == &#39;w&#39;) { // 둘 다 char 타입이므로 == 사용 가능
    // ...
}</code></pre>
<p><strong>2. 굳이 쌍따옴표(<code>String</code>)와 비교하고 싶다면?</strong></p>
<pre><code class="language-jsx">// char를 String으로 바꾼 뒤, .equals()로 비교해야 합니다.
String 뽑은글자 = String.valueOf(string.charAt(3));

if (뽑은글자.equals(&quot;w&quot;)) {
    System.out.println(&quot;w가 맞습니다!&quot;);
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] 문자열(String) 초기화부터 StringBuilder 최적화까지]]></title>
            <link>https://velog.io/@hong-seo/java-%EB%AC%B8%EC%9E%90%EC%97%B4String-%EC%B4%88%EA%B8%B0%ED%99%94%EB%B6%80%ED%84%B0-StringBuilder-%EC%B5%9C%EC%A0%81%ED%99%94%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@hong-seo/java-%EB%AC%B8%EC%9E%90%EC%97%B4String-%EC%B4%88%EA%B8%B0%ED%99%94%EB%B6%80%ED%84%B0-StringBuilder-%EC%B5%9C%EC%A0%81%ED%99%94%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Tue, 31 Mar 2026 11:46:06 GMT</pubDate>
            <description><![CDATA[<p>자바에서 문자열(String)은 정말 자주 사용하지만, 은근히 실수하기 쉬운 부분들이 많습니다. 오늘은 문자열 자르기부터 올바른 초기화 방법, 그리고 메모리를 효율적으로 사용하는 <code>StringBuilder</code>까지 정리해 보겠습니다.</p>
<h3 id="1-문자열-자르기의-기본-substring">1. 문자열 자르기의 기본: <code>substring()</code></h3>
<p>문자열의 특정 부분만 잘라내고 싶을 때는 <code>substring()</code>을 사용합니다.</p>
<p><code>my_string.substring(0, n)</code></p>
<p>위와 같이 작성하면 인덱스 <strong>0번째부터 n-1번째까지</strong>의 문자열을 출력해 줍니다. (시작 인덱스는 포함하고, 끝 인덱스는 포함하지 않는다는 점을 기억하세요!)</p>
<hr>
<h3 id="2-string-선언과-초기화-빈-문자열-vs-null">2. String 선언과 초기화: 빈 문자열(<code>&quot;&quot;</code>) vs <code>null</code></h3>
<p>문자열 변수를 선언할 때 <code>String st;</code>라고만 선언하면 변수에 아무런 값도 들어가지 않아 사용할 때 에러가 발생할 수 있습니다. 따라서 <strong><code>String st = &quot;&quot;;</code> 처럼 빈 문자열로 초기화</strong>해 주는 것이 좋습니다.</p>
<blockquote>
<p><strong>주의! 초기화할 때 <code>null</code>의 함정</strong>
만약 <code>String st = null;</code>이라고 초기화한 뒤 <code>st += 1;</code>을 하면 어떻게 될까요?
결과는 <code>&quot;1&quot;</code>이 아니라 <code>&quot;null1&quot;</code>이 되어버립니다. <code>null</code>이라는 글자 뒤에 숫자가 그대로 붙어버리기 때문입니다. <strong>반드시 쌍따옴표(<code>&quot;&quot;</code>)로 초기화하는 습관</strong>을 들입시다!</p>
</blockquote>
<p>참고로 문자열에 숫자를 더할 때, <code>st += String.valueOf(num);</code> 처럼 명시적으로 바꿔줘도 되지만, <strong><code>st += num;</code></strong> 이라고만 써줘도 자바가 알아서 숫자를 문자로 바꿔서 더해줍니다.</p>
<hr>
<h3 id="3-문자열-더하기-연산-string--vs-stringbuilder">3. 문자열 더하기 연산: <code>String +=</code> vs <code>StringBuilder</code></h3>
<p>배열에 있는 홀수와 짝수를 각각 이어 붙이는 상황을 가정해 봅시다.</p>
<p><strong>비효율적인 방식 (<code>String +=</code> 사용)</strong></p>
<p>위 코드처럼 <code>odd += ...</code> 형태로 문자열을 더해주는 방식은 <strong>매우 비효율적</strong>입니다. 자바에서 String은 값이 변하지 않는(불변) 객체이기 때문에, <code>+=</code> 연산을 할 때마다 기존 메모리를 버리고 <strong>새로운 메모리 공간을 계속해서 생성</strong>하게 됩니다. 데이터가 많아질수록 성능이 크게 떨어집니다.</p>
<p><strong>효율적인 방식 (<code>StringBuilder</code> 사용)</strong></p>
<pre><code class="language-jsx">public static int solution(int[] num_list) {
    StringBuilder odd = new StringBuilder();
    StringBuilder even = new StringBuilder();

    for (int num : num_list) {
        if (num % 2 == 0) {
            even.append(num);
        } else {
            odd.append(num);
        }
    }
    return Integer.parseInt(odd.toString()) + Integer.parseInt(even.toString());
}</code></pre>
<p><code>StringBuilder</code>를 사용하면 기존 메모리 공간을 재활용하여 문자열을 이어 붙이기(<code>append</code>) 때문에 <strong>메모리 낭비 없이 훨씬 빠르고 효율적으로</strong> 작업할 수 있습니다. 반복문 안에서 문자열을 더할 일이 있다면 무조건 <code>StringBuilder</code>를 사용하는 것이 좋습니다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] arraycopy, copyOfRange]]></title>
            <link>https://velog.io/@hong-seo/java-arraycopy-copyOfRange</link>
            <guid>https://velog.io/@hong-seo/java-arraycopy-copyOfRange</guid>
            <pubDate>Mon, 30 Mar 2026 11:16:05 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-java">public static int[] solution(int[] num_list, int n) {
        int j=0;
        int[] arr = new int[num_list.length-n+1];
        for(int i=n-1; i&lt;num_list.length; i++){
            arr[j]=num_list[i];
            j++;
        }
        return arr;
    }</code></pre>
<p>먼저 int 배열을 받은 것을 n번째부터 배열 끝까지 출력하기 위해 for문을 사용해서 출력해줬다. 하지만 이 방법보다 더 효율적인 방법이 있다.</p>
<p>바로 <code>System.arraycopy</code> (성능 최적화),  <code>Arrays.copyOfRange</code> (가독성 최적화) 이다.</p>
<h4 id="1-for문-대신-systemarraycopy">1. <code>for</code>문 대신 <code>System.arraycopy</code></h4>
<pre><code class="language-jsx">public static int[] solution(int[] num_list, int n) {
int length = num_list.length - n + 1;
int[] arr = new int[length];
// 원본배열, 시작위치, 복사본배열, 복사본시작위치, 복사할길이
System.arraycopy(num_list, n - 1, arr, 0, length);
return arr;
}</code></pre>
<p>arr을 설정해주고 arraycopy를 사용해서 기존의 num_list에서 복사해주면 된다.</p>
<p>원본배열, 시작위치, 복사본배열, 복사본시작위치, 복사할길이 순서대로 입력해주면 된다.</p>
<h4 id="2-arrayscopyofrange-가독성-최적화">2. <code>Arrays.copyOfRange</code> (가독성 최적화)</h4>
<pre><code class="language-jsx">public static int[] solution(int[] num_list, int n) {
// n-1 인덱스부터 num_list.length 인덱스 &quot;전&quot;까지 복사
return Arrays.copyOfRange(num_list, n - 1, num_list.length);
}</code></pre>
<p>바로 활용할 수 있는 방법으로  n-1 인덱스부터 num_list.length 인덱스 &quot;전&quot;까지 복사한다.</p>
<h4 id="마지막으로-배열-vs-arraylist을-구분해보자">마지막으로 배열 vs ArrayList을 구분해보자</h4>
<table>
<thead>
<tr>
<th><strong>구분</strong></th>
<th>int[] (배열)</th>
<th>ArrayList<Integer></th>
</tr>
</thead>
<tbody><tr>
<td><strong>크기</strong></td>
<td>고정 (한번 정하면 못 바꿈)</td>
<td>가변 (알아서 늘어남)</td>
</tr>
<tr>
<td><strong>속도</strong></td>
<td>매우 빠름</td>
<td>상대적으로 느림</td>
</tr>
<tr>
<td><strong>메모리</strong></td>
<td>효율적 (필요한 만큼만)</td>
<td>비효율적 (여유 공간 필요)</td>
</tr>
<tr>
<td><strong>데이터 타입</strong></td>
<td><code>int</code> (기본형)</td>
<td><code>Integer</code> (객체형)</td>
</tr>
</tbody></table>
<p><code>num_list.length - n + 1</code>이라는 명확한 크기 계산식이 나올 때는 배열(<code>int[]</code>)을 쓰는 것이 메모리 효율과 속도 측면에서 더 좋다고 한다</p>
<p>ArrayList는 <strong>입력되는 데이터가 몇 개일지 도저히 모를 때, 중간에 데이터를 넣거나 빼야 할 때</strong>(배열은 삭제가 힘들지만, <code>ArrayList</code>는 메서드 하나로 해결) 사용하는게 좋다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] int 배열받기]]></title>
            <link>https://velog.io/@hong-seo/java-int-%EB%B0%B0%EC%97%B4%EB%B0%9B%EA%B8%B0</link>
            <guid>https://velog.io/@hong-seo/java-int-%EB%B0%B0%EC%97%B4%EB%B0%9B%EA%B8%B0</guid>
            <pubDate>Sun, 29 Mar 2026 12:37:26 GMT</pubDate>
            <description><![CDATA[<p><strong><code>int[] answer = {};</code></strong> : 메모리에 <code>answer</code>라는 이름의 이름표는 붙였지만, 실제 데이터를 담을 공간(Index)이 0개가 된다.  이후 <strong><code>answer[0] = ...</code></strong>를 선언해주면 0번째 칸에 값을 넣으려고 시도합니다.</p>
<p><strong>→</strong> 에러 발생 : 크기가 0이라 값을 넣을 수 없어 에러</p>
<p><strong>배열 생성 시:</strong> 반드시 <code>new int[크기]</code> 처럼 숫자를 넣어줘야 값을 담을 공간이 생긴다.</p>
<p><strong>반복문 주의:</strong> <code>st.countTokens()</code>처럼 값이 변하는 메서드는 변수에 담아서 사용</p>
<p><strong>출력:</strong> <code>int[]</code> 객체를 그냥 출력하면 주소값이 나오니, 출력할 때 <code>Arrays.toString()</code>사용</p>
<h4 id="핵심으로-들어가서-int-배열을-받기-위해서는">핵심으로 들어가서 int 배열을 받기 위해서는</h4>
<pre><code class="language-java">                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int count =st.countTokens();
        int[] arr = new int[count];
        for(int i=0; i&lt;count; i++){
            arr[i]=Integer.parseInt(st.nextToken());
        }</code></pre>
<p>위와 같이 StringTokenizer을 사용해서 countTokens로 배열의 공간 확보, string을 받은 뒤 nextToken으로 배열에 넣어주면 된다.</p>
<h4 id="고정된-크기가-없을-때-arraylist-활용">고정된 크기가 없을 때: ArrayList 활용</h4>
<pre><code class="language-jsx">StringTokenizer st = new StringTokenizer(br.readLine());
ArrayList&lt;Integer&gt; list = new ArrayList&lt;&gt;();
while (st.hasMoreTokens()) {
list.add(Integer.parseInt(st.nextToken()));</code></pre>
<p>입력되는 숫자가 몇 개인지 미리 알 수 없을 때(배열 크기를 정할 수 없을 때) 사용한다</p>
<pre><code class="language-java">public static int[] solution(int[] num_list, int n) {
        int[] answer = new int[n];
        for(int i=0; i&lt;n; i++){
            answer[i]=num_list[i];
        }
        return answer;
    }</code></pre>
<p>여기서 return answer을 해주면 answer의 주소 반환해준다.</p>
<h4 id="arraystostringresult">Arrays.toString(result)</h4>
<p>그런데 이때, <code>result</code>가 배열 전체를 잘 받았더라도, 그냥 <code>System.out.println(result);</code>라고 하면 우리가 원하는 <code>[1, 2, 3]</code> 같은 모양이 나오지 않는다.</p>
<ul>
<li><strong>그냥 출력 시:</strong> <code>[I@6d06d69c</code> 같은 이상한 메모리 주소값이 나온다.</li>
<li><strong>내용물을 보려면:</strong> <code>Arrays.toString(result)</code>를 써야 배열의 값이 다 출력된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] int형 문자열로 취급 - valueOf]]></title>
            <link>https://velog.io/@hong-seo/java-int%ED%98%95-%EB%AC%B8%EC%9E%90%EC%97%B4%EB%A1%9C-%EC%B7%A8%EA%B8%89-valueOf</link>
            <guid>https://velog.io/@hong-seo/java-int%ED%98%95-%EB%AC%B8%EC%9E%90%EC%97%B4%EB%A1%9C-%EC%B7%A8%EA%B8%89-valueOf</guid>
            <pubDate>Fri, 27 Mar 2026 11:09:08 GMT</pubDate>
            <description><![CDATA[<p><strong>문자열 접합(<code>+</code>):</strong> <code>String.valueOf(a) + String.valueOf(b)</code>라고 써도 되지만,</p>
<p>int ba = Integer.parseInt(&quot;&quot; + b + a); 처럼 빈 문자열을 앞에 두면 자바가 알아서 뒤의 숫자들을 문자열로 취급해 붙여준다. (이때 a,b는 int형이고 “”를 통해 문자열로 취급한다.)</p>
<pre><code>public static int solution(int a, int b) {
        int ab = Integer.parseInt(&quot;&quot; + a + b);
        int ba = Integer.parseInt(&quot;&quot; + b + a);
        return (ab &gt;= ba) ? ab : ba;
    }</code></pre><p><strong>Math.max():</strong> 삼항 연산자 <code>(a &gt; b) ? a : b</code> 대신 자바 표준 라이브러리인 <code>Math.max(ab, ba)</code>를 쓰면 코드가 훨씬 더 직관적이게 된다.</p>
<pre><code>public int solution(int a, int b) {
        String strA = String.valueOf(a);
        String strB = String.valueOf(b);
        String strSum1 = strA + strB;
        String strSum2 = strB + strA;
        return Math.max(Integer.valueOf(strSum1), Integer.valueOf(strSum2));
    }</code></pre><pre><code>public int solution(int a, int b) {
        int ab = Integer.parseInt(Integer.toString(a) + Integer.toString(b));
        int ba = Integer.parseInt(Integer.toString(b) + Integer.toString(a));
        return ab &gt;= ba ? ab : ba;
    }</code></pre><h3 id="stringvalueofa-vs-integertostringa"><code>String.valueOf(a)</code> vs <code>Integer.toString(a)</code></h3>
<p>둘 다 숫자를 문자열로 바꾸는 역할이지만 내부적인 작동 방식에 약간의 차이 존재</p>
<ul>
<li><strong><code>String.valueOf(a)</code></strong>: 내부적으로 <code>Integer.toString(a)</code>을 호출합니다. 즉, <code>Integer.toString</code>을 한 번 더 감싸놓은 형태로 만약 입력값이 <code>null</code>이라면 <code>&quot;null&quot;</code>이라는 문자열을 반환하는 안전장치가 존재</li>
<li><strong><code>Integer.toString(a)</code></strong>: 정수(int)를 직접 문자열로 변환하는 가장 직접적인 메서드</li>
</ul>
<p>숫자를 문자로<strong>:</strong> <code>&quot;&quot; + a</code>  또는 <code>String.valueOf(a)</code></p>
<h3 id="integervalueof-vs-integerparseint"><code>Integer.valueOf()</code> vs <code>Integer.parseInt()</code></h3>
<p>이 둘도 비슷하지만 <strong>반환하는 타입</strong>이 다릅니다.</p>
<ul>
<li><strong><code>Integer.parseInt(s)</code></strong>: 결과값으로 기본형(<code>int</code>)을 반환 (산술 연산에 최적화)</li>
<li><strong><code>Integer.valueOf(s)</code></strong>: 결과값으로 객체형(<code>Integer</code>)을 반환합니다.</li>
</ul>
<blockquote>
<p><strong>그럼 왜 <code>parseInt</code> 대신 <code>valueOf</code>를 써도 돌아가나요?</strong>
자바에는 <strong>Auto-boxing/Unboxing</strong>이라는 기능이 있어서, 객체(<code>Integer</code>)를 숫자(<code>int</code>)가 필요한 곳에 넣으면 자바가 알아서 꺼내서 사용한다. 하지만 단순히 숫자 비교나 연산을 위해서라면 메모리 효율상 <code>parseInt</code>를 쓰는 것이 정석이다.</p>
</blockquote>
<h3 id="integer-이나-string을-앞에-붙여야-하는-이유"><code>Integer.</code> 이나 <code>String.</code>을 앞에 붙여야 하는 이유</h3>
<p>자바는 모든 메서드가 특정 <strong>클래스</strong> 안에 소속되어 있어야 합니다. 이때 &#39;Static 메서드(정적 메서드)&#39;라는 개념이 등장합니다.</p>
<ul>
<li><strong>도구함 개념:</strong> <code>Integer</code>라는 클래스는 &quot;정수와 관련된 유용한 도구들의 집합소&quot;</li>
<li>우리가 망치가 필요할 때 <code>공구함.꺼내기(망치)</code> 하듯이, 문자열을 숫자로 바꾸는 도구가 <code>Integer</code>라는 공구함 안에 들어있기 때문에 <code>Integer.parseInt()</code>라고 부르는 것입니다.</li>
<li>마찬가지로 문자열 관련 도구는 <code>String</code> 공구함에 들어있어 <code>String.valueOf()</code>라고 씁니다.</li>
</ul>
<hr>
<h3 id="integer-vs-int-대문자와-소문자의-차이"><code>Integer</code> vs <code>int</code> (대문자와 소문자의 차이)</h3>
<ol>
<li><strong><code>int</code> (기본형, Primitive Type):</strong> 단순히 숫자 값만 저장<ul>
<li><code>int a = 10;</code> 처럼 쓰며, 별도의 기능(메서드)이 없습니다. (<code>a.parseInt()</code> 이런 게 안됨.)</li>
</ul>
</li>
<li><strong><code>Integer</code> (래퍼 클래스, Wrapper Class):</strong><ul>
<li>기본형인 <code>int</code>를 객체로 감싸서 다양한 기능(메서드)을 제공</li>
<li>그래서 &quot;문자열을 숫자로 바꾸는 기능&quot; 같은 복잡한 로직은 소문자 <code>int</code>가 아니라 대문자 <strong><code>Integer</code></strong> 클래스가 가지고 있는 것입니다.</li>
</ul>
</li>
</ol>
<hr>
<h3 id="최종-요약">최종 요약</h3>
<ul>
<li><strong><code>valueOf(a)</code></strong> 를 쓰면 <code>Integer.toString(a)</code>을 호출해 a의 값이 null(즉 아무값도 없으면) 이를 String.valueof(a)라 하면 “null”로 출력된다. 아래 표 참조!!</li>
</ul>
<table>
<thead>
<tr>
<th><strong>케이스</strong></th>
<th><strong>상태</strong></th>
<th><strong>String.valueOf(a) 결과</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>참조조차 안 됨</strong></td>
<td><code>String a = null;</code></td>
<td><strong><code>&quot;null&quot;</code></strong> (글자 그대로 출력)</td>
</tr>
<tr>
<td><strong>빈 문자열 입력</strong></td>
<td><code>String a = &quot;&quot;;</code></td>
<td><strong><code>&quot;&quot;</code></strong> (눈에 보이지 않는 빈 공간 출력)</td>
</tr>
<tr>
<td>- <code>valueOf</code>는 특정 타입 전용이 아니라, 그 클래스의 타입으로 변환하겠다는 뜻</td>
<td></td>
<td></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] 대소문자, 공백, 문자열 찾기]]></title>
            <link>https://velog.io/@hong-seo/java-%EB%8C%80%EC%86%8C%EB%AC%B8%EC%9E%90-%EA%B3%B5%EB%B0%B1-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%B0%BE%EA%B8%B0</link>
            <guid>https://velog.io/@hong-seo/java-%EB%8C%80%EC%86%8C%EB%AC%B8%EC%9E%90-%EA%B3%B5%EB%B0%B1-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%B0%BE%EA%B8%B0</guid>
            <pubDate>Sun, 22 Mar 2026 09:21:29 GMT</pubDate>
            <description><![CDATA[<p>String.trim() : 공백제거</p>
<p>String.toLowerCase() : 모두 소문자로 변환</p>
<p>String.toUpperCase() : 모두 대문자로 변환</p>
<p>public static String solution(String myString) {
return myString.toUpperCase(); // 대문자로 변환된 &quot;새로운 문자열&quot;을 바로 반환
}</p>
<p>public static String solution(String myString) {
myString.toUpperCase(); // 새로운 대문자 문자열이 만들어졌지만, 아무데도 저장 안 함 (공중에 사라짐)
return myString;        // 바뀌지 않은 &quot;원본&quot; 소문자 문자열을 반환
}</p>
<p>→ 첫 번째는 대문자로 변환한 것을 바로 return해주고 두 번째는 대문자로 변환해주지만 이를 저장소에 저장하지 않아서 원래 문자가 나온다.</p>
<p><strong>문자에 포함되어 있는지 찾기</strong></p>
<p><strong><code>contains()</code></strong>: 단순히 포함 여부만 궁금할 때 → boolean 형태</p>
<p>my_string.contains(target)</p>
<p><strong><code>indexOf()</code></strong>: 포함 여부는 물론, <strong>어느 위치</strong>에 있는지 알아야 할 때 → int 형태로 포함안되어있으면 -1 반환</p>
<p>my_string.indexOf(target)</p>
<pre><code class="language-java">for(int i=0; i&lt;=n-m; i++){
            boolean match = true;
            for(int j=0; j&lt;m; j++){
                if(my_string.charAt(i+j)!=target.charAt(j)){
                    match=false;
                    break;
                }
            }
            if(match){
                return 1;
            }
        }</code></pre>
<p>이중 for문에서 안의 for문에서 break를 하면 가장 가까운 반복문으로 나오고 </p>
<p>완전히 프로그램이나 함수를 끝내고 싶다면 <code>break</code> 대신 <code>return</code>을 사용</p>
<h3 id="boolean-사용법"><code>boolean</code> 사용법</h3>
<p>&quot;모든 조건이 만족했는가?&quot;를 확인할 때는 <code>boolean isMatch = true;</code>로 시작해서, 하나라도 틀리면 <code>false</code>로 바꾸는 방식이 가장 안전하다! 요구하는 것에 따라서 true, false 구분 잘하기</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] Tokenizer 배열받기]]></title>
            <link>https://velog.io/@hong-seo/java-Tokenizer-%EB%B0%B0%EC%97%B4%EB%B0%9B%EA%B8%B0</link>
            <guid>https://velog.io/@hong-seo/java-Tokenizer-%EB%B0%B0%EC%97%B4%EB%B0%9B%EA%B8%B0</guid>
            <pubDate>Sat, 21 Mar 2026 14:59:44 GMT</pubDate>
            <description><![CDATA[<p><code>StringTokenizer</code>의 구분자 문자열은 각 문자를 개별적인 구분자로 취급합니다.</p>
<ul>
<li><code>new StringTokenizer(문자열, &quot;, &quot;)</code>는 <code>문자열</code> 안에서 <strong>쉼표</strong>를 만나도 자르고, <strong>공백</strong>을 만나도 자른다.</li>
<li><code>StringTokenizer</code>는 기본적으로 <strong>빈 문자열(비어있는 토큰)은 무시</strong>하기 때문에, 결과적으로 숫자들만 깔끔하게 가져오게 됩니다</li>
</ul>
<p>입력값이 <code>16,6, 5 12</code> (쉼표만 있는 경우, 쉼표+공백, 공백만 있는 경우 섞임)일 때:</p>
<table>
<thead>
<tr>
<th><strong>구분자 설정</strong></th>
<th><strong>결과 (토큰들)</strong></th>
<th><strong>설명</strong></th>
</tr>
</thead>
<tbody><tr>
<td><code>&quot;,&quot;</code></td>
<td><code>16</code>, <code>6</code>,  <code>5 12</code></td>
<td>공백을 구분 못 해서 숫자 앞에 공백이 포함됨</td>
</tr>
<tr>
<td><code>&quot; &quot;</code></td>
<td><code>16,</code>, <code>6,</code>, <code>5</code>, <code>12</code></td>
<td>쉼표를 구분 못 해서 숫자 뒤에 쉼표가 붙음</td>
</tr>
<tr>
<td><strong><code>&quot;, &quot;</code></strong></td>
<td><strong><code>16</code>, <code>6</code>, <code>5</code>, <code>12</code></strong></td>
<td>쉼표와 공백 모두 제거하고 숫자만 추출</td>
</tr>
</tbody></table>
<p>만약 &quot;쉼표+공백&quot;이 꼭 붙어있는 경우에만 자르고 싶다면 split 사용</p>
<pre><code class="language-jsx">String[] parts = br.readLine().split(&quot;, &quot;);</code></pre>
<p><strong><code>my_string.charAt(index_list[i])</code> :</strong> Java에서 String은 배열이 아니므로 반드시 .charAt() 메소드 사용</p>
<p><code>String[]</code> 배열이 아니라 하나의 <code>String</code>이어야 합니다. 여러 문자를 합칠 때는 <code>StringBuilder</code> 사용</p>
<ul>
<li><code>StringBuffer</code>는 여러 사람이 동시에 하나의 일기를 쓰는 상황을 대비해 &quot;누가 쓰고 있으면 나머지는 기다려!&quot;라고 문을 잠그는 기능(동기화)이 들어있습니다. 이 과정에서 오버헤드(비용)가 발생해 속도가 느려집니다.</li>
<li><em><code>StringBuilder</code>는 혼자서 일기를 쓰는 상황이라 문을 잠글 필요가 없습니다. 그래서 거추장스러운 절차 없이 훨씬 *</em>빠르게** 동작합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java] br, sanner 객체]]></title>
            <link>https://velog.io/@hong-seo/java-br-sanner-%EA%B0%9D%EC%B2%B4</link>
            <guid>https://velog.io/@hong-seo/java-br-sanner-%EA%B0%9D%EC%B2%B4</guid>
            <pubDate>Fri, 20 Mar 2026 15:22:43 GMT</pubDate>
            <description><![CDATA[<p>BufferedReader와 Scanner 모두 클래스를 기반으로 만든 <strong>&#39;객체(인스턴스)&#39;</strong></p>
<p>자바에서는 어떤 기능을 사용하기 위해 new 키워드를 사용하여 메모리에 그 기능을 할당하는데, 이를 객체 생성이라고 한다.</p>
<h3 id="bufferedreader-방식"><strong>[BufferedReader 방식]</strong></h3>
<p><code>BufferedReader br = new BufferedReader(new InputStreamReader(System.in));</code></p>
<ol>
<li><strong><code>System.in</code></strong>: 바이트 단위로 입력을 받는 기본 객체</li>
<li><strong><code>new InputStreamReader(...)</code></strong>: 바이트를 문자(char)로 바꿔주는 다리 역할 객체</li>
<li><strong><code>new BufferedReader(...)</code></strong>: 문자를 버퍼에 담아 한 번에 읽게 해주는 최종 객체 (<strong><code>br</code></strong>)</li>
</ol>
<h3 id="scanner-방식"><strong>[Scanner 방식]</strong></h3>
<p><code>Scanner sc = new Scanner(System.in);</code></p>
<ol>
<li><strong><code>System.in</code></strong>: 입력을 받는 기본 객체를 통째로 넘겨받습니다.</li>
<li><strong><code>new Scanner(...)</code></strong>: 이 입력값을 분석(Parsing)해서 숫자나 문자열로 요리해주는 객체 (<strong><code>sc</code></strong>)를 생성합니다.</li>
</ol>
<p><code>br</code>이나 <code>sc</code> 모두 <code>System.in</code>을 사용할 경우 프로그램 종료 시 GC가 정리해주긴 하지만, 자바의 정석은 <code>close()</code>를 명시해줘야 한다!</p>
<h3 id="scanner의-주요-메서드"><code>Scanner</code>의 주요 메서드</h3>
<p><strong><code>next()</code> :</strong> 공백(Space)이나 줄바꿈 전까지의 문자열을 읽음.</p>
<p><code>nextLine()</code> : 한 줄 전체를 읽음 (엔터 키를 칠 때까지).</p>
<p><strong><code>nextInt()</code></strong> : 정수를 읽음.</p>
<p><strong><code>nextDouble()</code></strong> : 실수를 읽음.</p>
<h3 id="예외-처리"><strong>예외 처리</strong></h3>
<ul>
<li><strong>BufferedReader:</strong> <code>readLine()</code>을 쓸 때 반드시 <code>throws IOException</code>을 선언하거나 <code>try-catch</code>로 감싸야 합니다. (컴파일러가 강제함)</li>
<li><strong>Scanner:</strong> 예외 처리를 강제하지 않아 코드가 짧아 보이지만, 잘못된 타입 입력 시 <code>InputMismatchException</code>이 발생할 수 있습니다.</li>
</ul>
<h3 id="동기화-thread-safe"><strong>동기화 (Thread-safe)</strong></h3>
<ul>
<li><strong>BufferedReader:</strong> 여러 스레드가 동시에 접근해도 안전합니다.</li>
<li><strong>Scanner:</strong> 멀티스레드 환경에서 안전하지 않습니다.</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>