<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>baek-dev 님의 블로그</title>
    <link>https://baek-dev.tistory.com/</link>
    <description>baek-dev 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Sat, 11 Apr 2026 15:02:07 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>baek-dev</managingEditor>
    <item>
      <title>배포 시 생각 못한 문제점 (TimeZone)</title>
      <link>https://baek-dev.tistory.com/242</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제상황&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2에 springboot, mysql, redis를 docker로 실행중.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스의 게시글 작성시간이 한국기준(KST)이 아닌 UTC+0 기준으로 나오는걸 확인.&lt;br /&gt;하지만, DB상에는 KST로 저장되어 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;원인분석&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든곳에 date를 찍어본 결과,&lt;br /&gt;EC2와 springboot 는 UTC.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mysql과 redis는 생성시 타임존(Asia/seoul)을 명시해줬기 때문에 KST 로 나오는걸 확인.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾아본 결과,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS리전이 서울(ap-northeast-2)이라고 해도, EC2의 OS 타임존이 KST가 되는것은 아님.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제해결&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글로벌 서비스로 확장할 것을 고려한다면, 모두 UTC로 맞춘 뒤 프론트에서 지역에 따라 시간을 변환하는 것을 권장.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 국내 서비스만 고려중이기 때문에, 내 EC2와 springboot를 KST로 맞추기로 결정.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2에서 timezone 변경&lt;/p&gt;
&lt;pre id=&quot;code_1772201642819&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo timedatectl set-timezone Asia/Seoul&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;springboot 에서 timezone 변경 (springboot 실행 파일에 추가)&lt;/p&gt;
&lt;pre id=&quot;code_1772201682369&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@PostConstruct
public void init() {
    TimeZone.setDefault(TimeZone.getTimeZone(&quot;Asia/Seoul&quot;));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Etc./개인공부</category>
      <category>EC2</category>
      <category>java</category>
      <category>springboot</category>
      <category>timezone</category>
      <author>baek-dev</author>
      <guid isPermaLink="true">https://baek-dev.tistory.com/242</guid>
      <comments>https://baek-dev.tistory.com/242#entry242comment</comments>
      <pubDate>Fri, 27 Feb 2026 23:27:07 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스 / Java] [level 1] 숫자 짝꿍</title>
      <link>https://baek-dev.tistory.com/241</link>
      <description>&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 설명&lt;/h3&gt;
&lt;a id=&quot;user-content-문제-설명&quot; style=&quot;color: #0969da;&quot; href=&quot;https://github.com/bsh52/AlgorithmCodeTest/blob/main/Java/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4/1/131128.%E2%80%85%EC%88%AB%EC%9E%90%E2%80%85%EC%A7%9D%EA%BF%8D/README.md#%EB%AC%B8%EC%A0%9C-%EC%84%A4%EB%AA%85&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;두 정수&lt;span&gt;&amp;nbsp;&lt;/span&gt;X,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y의 임의의 자리에서 공통으로 나타나는 정수 k(0 &amp;le; k &amp;le; 9)들을 이용하여 만들 수 있는 가장 큰 정수를 두 수의 짝꿍이라 합니다(단, 공통으로 나타나는 정수 중 서로 짝지을 수 있는 숫자만 사용합니다).&lt;span&gt;&amp;nbsp;&lt;/span&gt;X,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y의 짝꿍이 존재하지 않으면, 짝꿍은 -1입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;X,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y의 짝꿍이 0으로만 구성되어 있다면, 짝꿍은 0입니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어,&lt;span&gt;&amp;nbsp;&lt;/span&gt;X&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 3403이고&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 13203이라면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;X와&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y의 짝꿍은&lt;span&gt;&amp;nbsp;&lt;/span&gt;X와&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y에서 공통으로 나타나는 3, 0, 3으로 만들 수 있는 가장 큰 정수인 330입니다. 다른 예시로&lt;span&gt;&amp;nbsp;&lt;/span&gt;X&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 5525이고&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 1255이면&lt;span&gt;&amp;nbsp;&lt;/span&gt;X와&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y의 짝꿍은&lt;span&gt;&amp;nbsp;&lt;/span&gt;X와&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y에서 공통으로 나타나는 2, 5, 5로 만들 수 있는 가장 큰 정수인 552입니다(X에는 5가 3개,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y에는 5가 2개 나타나므로 남는 5 한 개는 짝 지을 수 없습니다.)&lt;br /&gt;두 정수&lt;span&gt;&amp;nbsp;&lt;/span&gt;X,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y가 주어졌을 때,&lt;span&gt;&amp;nbsp;&lt;/span&gt;X,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y의 짝꿍을 return하는 solution 함수를 완성해주세요.&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;제한사항&lt;a id=&quot;user-content-제한사항&quot; style=&quot;color: #0969da;&quot; href=&quot;https://github.com/bsh52/AlgorithmCodeTest/blob/main/Java/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4/1/131128.%E2%80%85%EC%88%AB%EC%9E%90%E2%80%85%EC%A7%9D%EA%BF%8D/README.md#%EC%A0%9C%ED%95%9C%EC%82%AC%ED%95%AD&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;3 &amp;le;&lt;span&gt;&amp;nbsp;&lt;/span&gt;X,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y의 길이(자릿수) &amp;le; 3,000,000입니다.&lt;/li&gt;
&lt;li&gt;X,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y는 0으로 시작하지 않습니다.&lt;/li&gt;
&lt;li&gt;X,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y의 짝꿍은 상당히 큰 정수일 수 있으므로, 문자열로 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;입출력 예&lt;a id=&quot;user-content-입출력-예&quot; style=&quot;color: #0969da;&quot; href=&quot;https://github.com/bsh52/AlgorithmCodeTest/blob/main/Java/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4/1/131128.%E2%80%85%EC%88%AB%EC%9E%90%E2%80%85%EC%A7%9D%EA%BF%8D/README.md#%EC%9E%85%EC%B6%9C%EB%A0%A5-%EC%98%88&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&quot;100&quot;&lt;/td&gt;
&lt;td&gt;&quot;2345&quot;&lt;/td&gt;
&lt;td&gt;&quot;-1&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&quot;100&quot;&lt;/td&gt;
&lt;td&gt;&quot;203045&quot;&lt;/td&gt;
&lt;td&gt;&quot;0&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&quot;100&quot;&lt;/td&gt;
&lt;td&gt;&quot;123450&quot;&lt;/td&gt;
&lt;td&gt;&quot;10&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td&gt;&quot;12321&quot;&lt;/td&gt;
&lt;td&gt;&quot;42531&quot;&lt;/td&gt;
&lt;td&gt;&quot;321&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td&gt;&quot;5525&quot;&lt;/td&gt;
&lt;td&gt;&quot;1255&quot;&lt;/td&gt;
&lt;td&gt;&quot;552&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;입출력 예 설명&lt;a id=&quot;user-content-입출력-예-설명&quot; style=&quot;color: #0969da;&quot; href=&quot;https://github.com/bsh52/AlgorithmCodeTest/blob/main/Java/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4/1/131128.%E2%80%85%EC%88%AB%EC%9E%90%E2%80%85%EC%A7%9D%EA%BF%8D/README.md#%EC%9E%85%EC%B6%9C%EB%A0%A5-%EC%98%88-%EC%84%A4%EB%AA%85&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;입출력 예 #1&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;X,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y의 짝꿍은 존재하지 않습니다. 따라서 &quot;-1&quot;을 return합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;입출력 예 #2&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;X,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y의 공통된 숫자는 0으로만 구성되어 있기 때문에, 두 수의 짝꿍은 정수 0입니다. 따라서 &quot;0&quot;을 return합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;입출력 예 #3&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;X,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y의 짝꿍은 10이므로, &quot;10&quot;을 return합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;입출력 예 #4&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;X,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Y의 짝꿍은 321입니다. 따라서 &quot;321&quot;을 return합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;입출력 예 #5&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지문에 설명된 예시와 같습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답)&lt;/p&gt;
&lt;pre id=&quot;code_1770306383734&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    public String solution(String X, String Y) {
        StringBuilder answer = new StringBuilder();

        int[] countX = new int[10];
        int[] countY = new int[10];

        for (char c : X.toCharArray()) {
            countX[c - '0']++;
        }
        
        for (char c : Y.toCharArray()) {
            countY[c - '0']++;
        }
        
        for (int i = 9; i &amp;gt;= 0; i--) {
            int commonCount = Math.min(countX[i], countY[i]);
            for (int j = 0; j &amp;lt; commonCount; j++) {
                answer.append(i);
            }
        }
        
        if (answer.length() == 0) {
            answer.append(&quot;-1&quot;);
        } else if (answer.charAt(0) == '0') {
            answer.setLength(1);
        }
        
        return answer.toString();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 답)&lt;/p&gt;
&lt;pre id=&quot;code_1770306522124&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    public String solution(String X, String Y) {
        StringBuilder answer = new StringBuilder();

        StringBuilder xSb = new StringBuilder(X);
        StringBuilder ySb = new StringBuilder(Y);

        for (int i = 0; i &amp;lt; xSb.length(); i++) {
            char x = xSb.charAt(i);

            for (int j = 0; j &amp;lt; ySb.length(); j++) {
                char y = ySb.charAt(j);

                if (x == y) {
                    answer.append(x);
                    xSb.deleteCharAt(i);
                    ySb.deleteCharAt(j);
                    i--;
                    break;
                }
            }
        }

        if (answer.length() == 0) {
            answer.append(&quot;-1&quot;);
        } else if (answer.toString().replace(&quot;0&quot;, &quot;&quot;).length() == 0) {
            answer.setLength(0);
            answer.append(&quot;0&quot;);
        } else {
            char[] answerArr = answer.toString().toCharArray();
            Arrays.sort(answerArr);
            answer.setLength(0);
            for (int i = answerArr.length - 1; i &amp;gt;= 0; i--) {
                answer.append(answerArr[i]);
            }
        }
        
        return answer.toString();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;X,Y 를 StringBuilder 로 변환 후 루프를 돌려 일치하는 숫자는 answer에 집어넣고, 각 SB에서 제거.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나온 결과를 내림차순 정렬.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 시간 초과로 실패.&lt;/p&gt;</description>
      <category>Etc./개인공부</category>
      <category>java</category>
      <author>baek-dev</author>
      <guid isPermaLink="true">https://baek-dev.tistory.com/241</guid>
      <comments>https://baek-dev.tistory.com/241#entry241comment</comments>
      <pubDate>Fri, 6 Feb 2026 00:50:52 +0900</pubDate>
    </item>
    <item>
      <title>LogBack</title>
      <link>https://baek-dev.tistory.com/240</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;log를 남기기 위한 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SLF4J(Simple Logging Facade for Java)의 구현체&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src/main/resources 경로에 'logback-spring.xml' 파일 생성&lt;/p&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;configuration&amp;gt;

    &amp;lt;!-- 로그 패턴 변수 설정 --&amp;gt;
    &amp;lt;property name=&quot;LOG_PATTERN&quot; value=&quot;%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n&quot;/&amp;gt;

    &amp;lt;!-- 콘솔 로그 --&amp;gt;
    &amp;lt;appender name=&quot;CONSOLE&quot; class=&quot;ch.qos.logback.core.ConsoleAppender&quot;&amp;gt;
        &amp;lt;encoder&amp;gt;
            &amp;lt;pattern&amp;gt;${LOG_PATTERN}&amp;lt;/pattern&amp;gt;
        &amp;lt;/encoder&amp;gt;
    &amp;lt;/appender&amp;gt;

    &amp;lt;!-- 파일 로그 --&amp;gt;
    &amp;lt;appender name=&quot;FILE&quot; class=&quot;ch.qos.logback.core.rolling.RollingFileAppender&quot;&amp;gt;
        &amp;lt;!-- 로그 파일 기본 경로 --&amp;gt;
        &amp;lt;file&amp;gt;logs/app.log&amp;lt;/file&amp;gt;

        &amp;lt;rollingPolicy class=&quot;ch.qos.logback.core.rolling.TimeBasedRollingPolicy&quot;&amp;gt;
            &amp;lt;!-- 로그 파일 이름 패턴 --&amp;gt;
            &amp;lt;fileNamePattern&amp;gt;logs/app.%d{yyyy-MM-dd}.log&amp;lt;/fileNamePattern&amp;gt;
            &amp;lt;!-- 보관할 최대 로그 파일 수 (30일) --&amp;gt;
            &amp;lt;maxHistory&amp;gt;30&amp;lt;/maxHistory&amp;gt;
        &amp;lt;/rollingPolicy&amp;gt;

        &amp;lt;encoder&amp;gt;
            &amp;lt;pattern&amp;gt;${LOG_PATTERN}&amp;lt;/pattern&amp;gt;
        &amp;lt;/encoder&amp;gt;
    &amp;lt;/appender&amp;gt;

    &amp;lt;!-- 로그 레벨 --&amp;gt;
    &amp;lt;root level=&quot;INFO&quot;&amp;gt;
        &amp;lt;appender-ref ref=&quot;CONSOLE&quot;/&amp;gt;
        &amp;lt;appender-ref ref=&quot;FILE&quot;/&amp;gt;
    &amp;lt;/root&amp;gt;

    &amp;lt;!-- 특정 패키지에 대한 로그 레벨 설정 --&amp;gt;
    &amp;lt;logger name=&quot;com.example&quot; level=&quot;DEBUG&quot;/&amp;gt; &amp;lt;!-- 예: com.example 패키지의 로그 레벨을 DEBUG로 설정 --&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Slf4j 와 log.info debug 등등을 활용해 남기고 싶은 로그를 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;로그패턴&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. %d{yyyy-MM-dd HH:mm:ss} &amp;mdash; 로그 발생 시각&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그가 언제 발생했는지&lt;/li&gt;
&lt;li&gt;서버 시간 기준&lt;/li&gt;
&lt;li&gt;포맷은 Java DateTime 패턴과 동일&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영 환경에서 장애 시간 추적의 핵심 정보&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. [%thread] &amp;mdash; 실행 중인 스레드 이름&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 스레드에서 로그가 발생했는지&lt;/li&gt;
&lt;li&gt;웹 요청 처리 시 보통 다음과 같이 나옴&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;http-nio-8080-exec-3&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의미: 같은 요청 흐름 추적&lt;br /&gt;동시성 문제 분석 시 중요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. %-5level &amp;mdash; 로그 레벨&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;INFO, DEBUG, ERROR 등&lt;/li&gt;
&lt;li&gt;-5는 왼쪽 정렬 + 5칸 고정 폭&lt;br /&gt;그래서 로그가 이렇게 정렬됨:&lt;br /&gt;INFO&lt;br /&gt;WARN&lt;br /&gt;ERROR&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가독성을 위한 포맷 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. %logger{36} &amp;mdash; 로그를 찍은 클래스(또는 패키지)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그를 발생시킨 Logger 이름&lt;/li&gt;
&lt;li&gt;보통 클래스의 풀 패키지명&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{36} 의미: 최대 36글자까지만 출력, 너무 길면 앞을 줄여서 표시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가독성과 로그 폭 균형을 위한 옵션&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. %msg &amp;mdash; 실제 로그 메시지&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;log.info(&quot;게시글 조회 성공&quot;);&lt;br /&gt;여기서 문자열 그대로 출력됨&lt;/p&gt;</description>
      <category>BE/Spring &amp;amp; Spring Boot</category>
      <category>java</category>
      <category>log</category>
      <category>springboot</category>
      <author>baek-dev</author>
      <guid isPermaLink="true">https://baek-dev.tistory.com/240</guid>
      <comments>https://baek-dev.tistory.com/240#entry240comment</comments>
      <pubDate>Fri, 23 Jan 2026 19:27:11 +0900</pubDate>
    </item>
    <item>
      <title>커스텀 어노테이션</title>
      <link>https://baek-dev.tistory.com/239</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;회원가입할때 DTO로 validation을 하는데, password 와 password2 를 비교할때, &lt;br /&gt;service에서 password.equals(passowrd2) 를 사용하는것은 좋지 않음.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API마다 중복&lt;/li&gt;
&lt;li&gt;테스트 어려움&lt;/li&gt;
&lt;li&gt;검증 책임 혼재&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 이유때문.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JoinDto&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Getter
@NoArgsConstructor
@AllArgsConstructor
@PasswordMatch
public class JoinRequest {

    @NotBlank
    @Size(min = 4)
    @Pattern(
            regexp = &quot;^[a-zA-Z0-9]+$&quot;,
            message = &quot;아이디는 영문 대소문자와 숫자만 포함할 수 있습니다.&quot;
    )
    private String username;

    @NotBlank
    @Size(min = 8)
    @Pattern(
            regexp = &quot;^(?=.*[!@#$%^&amp;amp;*(),.?\&quot;:{}|&amp;lt;&amp;gt;]).+$&quot;,
            message = &quot;비밀번호에는 최소 8자이며, 최소 하나의 특수문자가 포함되어야 합니다.&quot;
    )
    private String password;

    @NotBlank
    private String password2;

    @NotBlank
    @Pattern(
            regexp = &quot;^[^\\s]+$&quot;,
            message = &quot;닉네임에는 공백을 포함할 수 없습니다.&quot;
    )
    private String nickname;

    @NotBlank
    @Email
    private String email;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. PasswordMatch.java&lt;/p&gt;
&lt;pre class=&quot;monkey&quot;&gt;&lt;code&gt;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PasswordMatchValidator.class)
public @interface PasswordMatch {
    String message() default &quot;비밀번호가 일치하지 않습니다.&quot;;

    Class&amp;lt;?&amp;gt;[] groups() default {};

    Class&amp;lt;? extends Payload&amp;gt;[] payload() default {};
}&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;@Target(ElementType.TYPE)
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;FIELD, METHOD X&lt;/li&gt;
&lt;li&gt;CLASS O&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;@Retention(RetentionPolicy.RUNTIME)&lt;/li&gt;
&lt;li&gt;@Constraint(validatedBy&amp;nbsp;=&amp;nbsp;PasswordMatchValidator.class)
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이 어노테이션이 붙은 대상을 검증할 때, PasswordMatchValidator를 실행해라 라는 의미&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;@interface
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;annotation interface 라는 의미&lt;/li&gt;
&lt;li&gt;일반 인터페이스가 아닌 어노테이션용 인터페이스라는 의미&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PasswordMatch 가 규칙이름이라면, PasswordMatchValidator는 실제 로직.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. PasswordMatchValidator.java&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class PasswordMatchValidator
        implements ConstraintValidator&amp;lt;PasswordMatch, JoinRequest&amp;gt; {

    @Override
    public boolean isValid(JoinRequest value, ConstraintValidatorContext context) {
        if (value.getPassword() == null || value.getPassword2() == null) {
            return true;
        }
        return value.getPassword().equals(value.getPassword2());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;ConstraintValidator&amp;lt;A,&amp;nbsp;T&amp;gt;&lt;br /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;A - 어떤 어노테이션을 처리할지, &lt;br /&gt;T - 어떤 타입을 검증할지&lt;/li&gt;
&lt;li&gt;PasswordMatch 어노테이션이 붙은 JoinRequest 객체를 검증하겠다&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;isValid 메서드가 실행되는 순서.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;2328&quot; data-start=&quot;2307&quot;&gt;클라이언트 &amp;rarr; /join 요청&lt;/li&gt;
&lt;li data-end=&quot;2356&quot; data-start=&quot;2329&quot;&gt;JSON &amp;rarr; JoinRequest 객체 생성&lt;/li&gt;
&lt;li data-end=&quot;2371&quot; data-start=&quot;2357&quot;&gt;@Valid 발견&lt;/li&gt;
&lt;li data-end=&quot;2451&quot; data-start=&quot;2372&quot;&gt;JoinRequest에 붙은 검증 어노테이션 수집
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2451&quot; data-start=&quot;2406&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2417&quot; data-start=&quot;2406&quot;&gt;@NotBlank&lt;/li&gt;
&lt;li data-end=&quot;2431&quot; data-start=&quot;2421&quot;&gt;@Pattern&lt;/li&gt;
&lt;li data-end=&quot;2451&quot; data-start=&quot;2435&quot;&gt;@PasswordMatch&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;2472&quot; data-start=&quot;2452&quot;&gt;@PasswordMatch 발견&lt;/li&gt;
&lt;li data-end=&quot;2492&quot; data-start=&quot;2473&quot;&gt;@Constraint 확인&lt;/li&gt;
&lt;li data-end=&quot;2526&quot; data-start=&quot;2493&quot;&gt;PasswordMatchValidator 인스턴스 생성&lt;/li&gt;
&lt;li data-end=&quot;2546&quot; data-start=&quot;2527&quot;&gt;&lt;b&gt;isValid() 호출&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검증이 실패하면 GlobalExceptionHandler로 이동.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@Target 의 ElementType 종류&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ElementType&lt;/td&gt;
&lt;td&gt;의미&lt;/td&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TYPE&lt;/td&gt;
&lt;td&gt;클래스, 인터페이스, enum&lt;/td&gt;
&lt;td&gt;class, interface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FIELD&lt;/td&gt;
&lt;td&gt;필드(멤버 변수)&lt;/td&gt;
&lt;td&gt;private String name;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;METHOD&lt;/td&gt;
&lt;td&gt;메서드&lt;/td&gt;
&lt;td&gt;public void save()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PARAMETER&lt;/td&gt;
&lt;td&gt;메서드 파라미터&lt;/td&gt;
&lt;td&gt;(@Valid String name)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CONSTRUCTOR&lt;/td&gt;
&lt;td&gt;생성자&lt;/td&gt;
&lt;td&gt;public User()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LOCAL_VARIABLE&lt;/td&gt;
&lt;td&gt;지역 변수&lt;/td&gt;
&lt;td&gt;String tmp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ANNOTATION_TYPE&lt;/td&gt;
&lt;td&gt;어노테이션&lt;/td&gt;
&lt;td&gt;@interface MyAnno&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PACKAGE&lt;/td&gt;
&lt;td&gt;패키지&lt;/td&gt;
&lt;td&gt;package-info.java&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TYPE_PARAMETER&lt;/td&gt;
&lt;td&gt;제네릭 타입 파라미터&lt;/td&gt;
&lt;td&gt;&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TYPE_USE&lt;/td&gt;
&lt;td&gt;타입이 사용되는 모든 위치&lt;/td&gt;
&lt;td&gt;List&amp;lt;@NotNull String&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MODULE&lt;/td&gt;
&lt;td&gt;모듈 (Java 9+)&lt;/td&gt;
&lt;td&gt;module-info.java&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RECORD_COMPONENT&lt;/td&gt;
&lt;td&gt;record 필드 (Java 16+)&lt;/td&gt;
&lt;td&gt;record User(String name)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>BE/Spring &amp;amp; Spring Boot</category>
      <category>annotation</category>
      <category>java</category>
      <category>Spring</category>
      <author>baek-dev</author>
      <guid isPermaLink="true">https://baek-dev.tistory.com/239</guid>
      <comments>https://baek-dev.tistory.com/239#entry239comment</comments>
      <pubDate>Mon, 5 Jan 2026 01:13:50 +0900</pubDate>
    </item>
    <item>
      <title>git 최초 커밋 삭제</title>
      <link>https://baek-dev.tistory.com/238</link>
      <description>&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git update-ref -d HEAD
git rm -- cached -rf .

...작업후 -f 로 push&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Tips</category>
      <category>git</category>
      <author>baek-dev</author>
      <guid isPermaLink="true">https://baek-dev.tistory.com/238</guid>
      <comments>https://baek-dev.tistory.com/238#entry238comment</comments>
      <pubDate>Sat, 3 Jan 2026 17:40:22 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 제네릭 vs 와일드카드</title>
      <link>https://baek-dev.tistory.com/237</link>
      <description>&lt;h1&gt;제네릭과 와일드카드의 차이&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 제네릭 (Generics)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;클래스나 메서드가 다룰 데이터 타입을 파라미터화&lt;/b&gt;해서, 컴파일 시점에 타입 안전성을 보장하는 문법임.&lt;/li&gt;
&lt;li&gt;선언 시점에 타입을 확정지음 &amp;rarr; 컴파일러가 타입 체크 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; names = new ArrayList&amp;lt;&amp;gt;(); 
names.add(&quot;철수&quot;);  // OK
names.add(123);    // 컴파일 에러
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;List&amp;lt;String&amp;gt; 제네릭을 통해 &quot;이 리스트는 문자열만 담는다&quot; 라는 타입 정보를 컴파일러에 알려줌.&lt;/li&gt;
&lt;li&gt;잘못된 타입(Integer)을 넣으면 컴파일 단계에서 막힘.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 와일드카드 (Wildcard)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제네릭 타입을 다룰 때, &lt;b&gt;정확한 타입을 지정하지 않고 유연하게 범위를 한정&lt;/b&gt;하고 싶을 때 사용함.&lt;/li&gt;
&lt;li&gt;? 로 표현됨.&lt;/li&gt;
&lt;li&gt;제네릭의 소비/생산(Producer/Consumer) 관점에서 자주 등장.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;종류&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;비한정 와일드카드 &amp;lt;?&amp;gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;어떤 타입이든 들어올 수 있음&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;List&amp;lt;?&amp;gt; list = new ArrayList&amp;lt;String&amp;gt;();
list = new ArrayList&amp;lt;Integer&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단, 안전하지 않으므로 요소 추가는 불가(null만 가능).&lt;/li&gt;
&lt;li&gt;요소 조회만 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상한 제한 와일드카드 &amp;lt;? extends T&amp;gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;T 또는 T의 하위 타입만 올 수 있음&quot;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;읽기(Producer)&lt;/b&gt; 용도&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;List&amp;lt;? extends Number&amp;gt; list = new ArrayList&amp;lt;Integer&amp;gt;();
Number n = list.get(0);   // OK
// list.add(10);          // 컴파일 에러 (추가 불가)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;하한 제한 와일드카드 &amp;lt;? super T&amp;gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;T 또는 T의 상위 타입만 올 수 있음&quot;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쓰기(Consumer)&lt;/b&gt; 용도&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;List&amp;lt;? super Integer&amp;gt; list = new ArrayList&amp;lt;Number&amp;gt;();
list.add(10);    // OK (Integer는 허용)
// Integer i = list.get(0); // 불가능 (Object로만 꺼낼 수 있음)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 핵심 차이&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구분&lt;/td&gt;
&lt;td&gt;제네릭&lt;/td&gt;
&lt;td&gt;와일드카드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;선언 위치&lt;/td&gt;
&lt;td&gt;클래스/인터페이스/메서드 정의 시 사용&lt;/td&gt;
&lt;td&gt;이미 정의된 제네릭 타입을 사용할 때 유연성을 위해 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;타입 확정 여부&lt;/td&gt;
&lt;td&gt;구체적인 타입을 지정 (List&amp;lt;String&amp;gt;)&lt;/td&gt;
&lt;td&gt;타입을 알 수 없거나 범위를 지정 (List&amp;lt;?&amp;gt;, List&amp;lt;? extends Number&amp;gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;목적&lt;/td&gt;
&lt;td&gt;컴파일 시점 타입 안정성 확보&lt;/td&gt;
&lt;td&gt;메서드 파라미터의 유연성 확보&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;활용&lt;/td&gt;
&lt;td&gt;직접 사용하는 코드&lt;/td&gt;
&lt;td&gt;API 설계 시 (라이브러리, 범용 메서드)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 직관적인 비유&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;제네릭&lt;/b&gt;은 &quot;이 상자에는 사과만 담을 거야&quot; 라고 처음부터 딱 정해버리는 것.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;와일드카드&lt;/b&gt;는 &quot;어떤 과일이 들어있을지 모르지만 과일 계열만 올 수 있어&quot; 혹은 &quot;과일 이상(슈퍼클래스)만 허용할게&quot; 라고 &lt;b&gt;범위를 열어두는 것&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 예시 비교&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;// 제네릭 방식
public &amp;lt;T&amp;gt; void printList(List&amp;lt;T&amp;gt; list) {
    for (T elem : list) {
        System.out.println(elem);
    }
}

// 와일드카드 방식
public void printList(List&amp;lt;?&amp;gt; list) {
    for (Object elem : list) {
        System.out.println(elem);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제네릭은 T를 선언해서 내부적으로 &lt;b&gt;타입을 유지&lt;/b&gt;할 수 있음.&lt;/li&gt;
&lt;li&gt;와일드카드는 &lt;b&gt;읽기 전용&lt;/b&gt; 느낌 &amp;rarr; 타입 정보를 유지하지 않음.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제네릭: &lt;b&gt;타입 안정성&lt;/b&gt; 확보 (직접 코드 작성할 때 주로 사용)&lt;/li&gt;
&lt;li&gt;와일드카드: &lt;b&gt;유연성&lt;/b&gt; 확보 (API 설계, 범용 라이브러리에서 자주 사용)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PECS 원칙&lt;/b&gt; (Producer Extends, Consumer Super)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;? extends T&amp;gt; &amp;rarr; 데이터를 꺼내(Produce) 읽기 전용&lt;/li&gt;
&lt;li&gt;&amp;lt;? super T&amp;gt; &amp;rarr; 데이터를 집어넣기(Consume) 전용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;출처 : ChatGPT&lt;/span&gt;&lt;/p&gt;</description>
      <category>BE/Java</category>
      <category>generic</category>
      <category>java</category>
      <category>WildCard</category>
      <author>baek-dev</author>
      <guid isPermaLink="true">https://baek-dev.tistory.com/237</guid>
      <comments>https://baek-dev.tistory.com/237#entry237comment</comments>
      <pubDate>Thu, 4 Sep 2025 18:27:34 +0900</pubDate>
    </item>
    <item>
      <title>변수 정리</title>
      <link>https://baek-dev.tistory.com/236</link>
      <description>&lt;h1&gt;자바(Java)의 변수 종류 정리&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바의 변수는 크게 다음 4가지로 분류됨:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;지역 변수 (Local Variable)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;멤버 변수 (Member Variable)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인스턴스 변수 (Instance Variable)&lt;/li&gt;
&lt;li&gt;클래스 변수 (Class Variable / static 변수)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;매개변수 (Parameter Variable)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상수 (final 변수)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 변수는 &lt;b&gt;선언 위치, 생명 주기, 메모리 저장 위치&lt;/b&gt;에 따라 다르게 동작함.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 지역 변수 (Local Variable)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;메서드 내부&lt;/b&gt;, &lt;b&gt;생성자 내부&lt;/b&gt;, &lt;b&gt;블록 내부&lt;/b&gt;에서 선언된 변수임&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해당 블록이 실행될 때 생성&lt;/b&gt;되고, &lt;b&gt;블록이 종료되면 소멸&lt;/b&gt;됨&lt;/li&gt;
&lt;li&gt;반드시 &lt;b&gt;초기화 후 사용해야 함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메서드 호출 시마다 새롭게 생성&lt;/b&gt;됨&lt;/li&gt;
&lt;li&gt;메모리: &lt;b&gt;스택(stack)&lt;/b&gt; 영역에 저장됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public void printSum() {
    int a = 5;     // 지역 변수
    int b = 10;    // 지역 변수
    System.out.println(a + b);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 멤버 변수 (Member Variable)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 블록 내부에 선언되며, 객체나 클래스의 &lt;b&gt;속성(상태)&lt;/b&gt; 을 저장함.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 인스턴스 변수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;static 키워드가 없는 멤버 변수임&lt;/li&gt;
&lt;li&gt;객체가 생성될 때 함께 생성되며, 객체마다 &lt;b&gt;고유한 값을 가짐&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;클래스의 인스턴스가 사라지면 소멸됨&lt;/li&gt;
&lt;li&gt;메모리: &lt;b&gt;힙(heap)&lt;/b&gt; 영역에 저장됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class Car {
    String color;  // 인스턴스 변수
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. 클래스 변수 (static 변수)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;static 키워드가 붙은 멤버 변수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;클래스 로딩 시 단 한 번 생성되어 모든 인스턴스가 공유함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;객체 생성 없이도 접근 가능&lt;/li&gt;
&lt;li&gt;메모리: &lt;b&gt;메서드 영역(method area)&lt;/b&gt; 에 저장됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class Car {
    static int totalCars = 0;  // 클래스 변수
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 매개변수 (Parameter Variable)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메서드나 생성자 호출 시 전달받는 값임&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메서드 호출 시 생성되고, 호출이 끝나면 소멸됨&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;지역 변수처럼 &lt;b&gt;스택(stack)&lt;/b&gt; 영역에 저장됨&lt;/li&gt;
&lt;li&gt;일반적으로 final 키워드를 붙여 변경을 막는 경우도 많음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;public void greet(String name) {  // name: 매개변수
    System.out.println(&quot;Hello, &quot; + name);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 상수 (final 변수)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;final 키워드를 사용하면 &lt;b&gt;값을 한 번만 초기화할 수 있는 변수&lt;/b&gt;가 됨&lt;/li&gt;
&lt;li&gt;불변성을 가지며, 값을 변경하려 하면 컴파일 에러가 발생함&lt;/li&gt;
&lt;li&gt;static final로 선언하면 &lt;b&gt;클래스 전체에서 공유되는 상수&lt;/b&gt;가 됨 (관례상 대문자 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class Config {
    static final int MAX_SIZE = 100;  // 상수
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;메모리 영역 정리&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;변수 종류&lt;/td&gt;
&lt;td&gt;저장 위치&lt;/td&gt;
&lt;td&gt;생성 시점&lt;/td&gt;
&lt;td&gt;소멸 시점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;지역 변수&lt;/td&gt;
&lt;td&gt;스택&lt;/td&gt;
&lt;td&gt;메서드 호출 시&lt;/td&gt;
&lt;td&gt;메서드 종료 시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;매개 변수&lt;/td&gt;
&lt;td&gt;스택&lt;/td&gt;
&lt;td&gt;메서드 호출 시&lt;/td&gt;
&lt;td&gt;메서드 종료 시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;인스턴스 변수&lt;/td&gt;
&lt;td&gt;힙&lt;/td&gt;
&lt;td&gt;객체 생성 시&lt;/td&gt;
&lt;td&gt;객체가 GC 될 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;클래스 변수&lt;/td&gt;
&lt;td&gt;메서드 영역&lt;/td&gt;
&lt;td&gt;클래스 로딩 시&lt;/td&gt;
&lt;td&gt;클래스 언로드 시&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주요 차이점 정리&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;지역 변수&lt;/td&gt;
&lt;td&gt;인스턴스 변수&lt;/td&gt;
&lt;td&gt;클래스 변수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;선언 위치&lt;/td&gt;
&lt;td&gt;메서드, 블록 내부&lt;/td&gt;
&lt;td&gt;클래스 내부&lt;/td&gt;
&lt;td&gt;클래스 내부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;static 여부&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;static 필수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;메모리 영역&lt;/td&gt;
&lt;td&gt;스택&lt;/td&gt;
&lt;td&gt;힙&lt;/td&gt;
&lt;td&gt;메서드 영역&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;초기화 필요 여부&lt;/td&gt;
&lt;td&gt;반드시 초기화 필요&lt;/td&gt;
&lt;td&gt;자동 초기화됨&lt;/td&gt;
&lt;td&gt;자동 초기화됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;공유 여부&lt;/td&gt;
&lt;td&gt;불가능&lt;/td&gt;
&lt;td&gt;객체 간 공유 불가&lt;/td&gt;
&lt;td&gt;모든 인스턴스가 공유&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실무에서 자주 사용하는 예시&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;설정값 상수&lt;/b&gt;: public static final String BASE_URL = &quot;&lt;a href=&quot;https://api.example.com&quot;&gt;https://api.example.com&lt;/a&gt;&quot;;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;객체마다 다른 값&lt;/b&gt;: 인스턴스 변수로 name, age 등 선언&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로그인 상태 유지&lt;/b&gt;: static 변수로 전역 세션 상태 관리 (단, 추천되지 않음)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;임시 연산 변수&lt;/b&gt;: 지역 변수로 sum, i, temp 등 선언&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;출처 : ChatGPT&lt;/span&gt;&lt;/p&gt;</description>
      <category>BE/Java</category>
      <category>java</category>
      <author>baek-dev</author>
      <guid isPermaLink="true">https://baek-dev.tistory.com/236</guid>
      <comments>https://baek-dev.tistory.com/236#entry236comment</comments>
      <pubDate>Tue, 22 Jul 2025 12:30:45 +0900</pubDate>
    </item>
    <item>
      <title>중첩, 내부클래스</title>
      <link>https://baek-dev.tistory.com/235</link>
      <description>&lt;h1&gt;Java의 중첩 클래스(Nested Class), 내부 클래스(Inner Class), 지역 클래스(Local Class) 정리&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서는 클래스 안에 또 다른 클래스를 선언할 수 있음. 이를 &lt;b&gt;중첩 클래스(Nested Class)&lt;/b&gt; 라고 부름.&lt;br /&gt;중첩 클래스는 코드의 구조를 더 논리적으로 구성할 수 있도록 도와줌.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 중첩 클래스란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;중첩 클래스(Nested Class)&lt;/b&gt; 는 다른 클래스 내부에 선언된 클래스를 의미함.&lt;br /&gt;일반 클래스 외에, 클래스의 일부 기능을 내부 클래스로 구조화할 때 사용함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩 클래스는 다음과 같이 크게 두 가지로 나뉨:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정적 중첩 클래스 (Static Nested Class)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비정적 중첩 클래스 &amp;rarr; 내부 클래스(Inner Class)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 클래스는 다시 세분화됨:&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;분류&lt;/td&gt;
&lt;td&gt;static 여부&lt;/td&gt;
&lt;td&gt;선언 위치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;정적 중첩 클래스&lt;/td&gt;
&lt;td&gt;있음&lt;/td&gt;
&lt;td&gt;클래스 내부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;내부 클래스&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;클래스 내부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;지역 클래스&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;메서드, 블록 내부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;익명 클래스&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;td&gt;메서드, 블록 내부&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 정적 중첩 클래스 (Static Nested Class)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;static 키워드로 선언된 중첩 클래스&lt;/li&gt;
&lt;li&gt;외부 클래스의 인스턴스 없이도 사용 가능함&lt;/li&gt;
&lt;li&gt;외부 클래스의 &lt;b&gt;정적 멤버(static field/method)&lt;/b&gt; 에만 접근 가능함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Outer {
    static int staticValue = 100;

    static class StaticNested {
        void show() {
            System.out.println(&quot;Static value = &quot; + staticValue);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;Outer.StaticNested nested = new Outer.StaticNested();
nested.show();
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 내부 클래스 (Inner Class)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;static 없이 외부 클래스 안에 선언된 클래스&lt;/li&gt;
&lt;li&gt;외부 클래스의 &lt;b&gt;모든 멤버(필드, 메서드 포함)&lt;/b&gt; 에 접근 가능함&lt;/li&gt;
&lt;li&gt;내부 클래스는 반드시 &lt;b&gt;외부 클래스의 인스턴스가 존재&lt;/b&gt;해야 생성 가능함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Outer {
    private String message = &quot;Hello from Outer&quot;;

    class Inner {
        void printMessage() {
            System.out.println(message);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.printMessage();
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 지역 클래스 (Local Class)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메서드, 생성자, 초기화 블록 안에서 선언되는 클래스&lt;/li&gt;
&lt;li&gt;해당 블록 내에서만 유효함 (지역 변수처럼 동작)&lt;/li&gt;
&lt;li&gt;외부 클래스의 필드, 메서드에 접근 가능&lt;/li&gt;
&lt;li&gt;메서드 내 지역 변수에 접근할 경우, 해당 변수는 &lt;b&gt;final 또는 effectively final&lt;/b&gt; 이어야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Outer {
    void doTask() {
        int taskId = 10; // final처럼 사용되어야 함

        class LocalClass {
            void print() {
                System.out.println(&quot;Task ID: &quot; + taskId);
            }
        }

        LocalClass lc = new LocalClass();
        lc.print();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 익명 클래스 (Anonymous Class)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이름 없이 클래스를 선언하고 즉시 객체로 생성함&lt;/li&gt;
&lt;li&gt;인터페이스나 추상 클래스의 구현이 필요할 때 자주 사용됨&lt;/li&gt;
&lt;li&gt;지역 클래스와 비슷하지만 &lt;b&gt;한 번만 사용되는 간단한 용도&lt;/b&gt;에 적합함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println(&quot;Running&quot;);
    }
};

new Thread(r).start();
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 네 가지 중첩 클래스 비교 요약&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구분&lt;/td&gt;
&lt;td&gt;선언 위치&lt;/td&gt;
&lt;td&gt;외부 멤버 접근&lt;/td&gt;
&lt;td&gt;static 여부&lt;/td&gt;
&lt;td&gt;사용 시기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;정적 중첩 클래스&lt;/td&gt;
&lt;td&gt;클래스 내부&lt;/td&gt;
&lt;td&gt;정적 멤버만 접근&lt;/td&gt;
&lt;td&gt;static 있음&lt;/td&gt;
&lt;td&gt;외부 인스턴스 없이 사용 시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;내부 클래스&lt;/td&gt;
&lt;td&gt;클래스 내부&lt;/td&gt;
&lt;td&gt;모두 접근 가능&lt;/td&gt;
&lt;td&gt;static 없음&lt;/td&gt;
&lt;td&gt;외부 인스턴스 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;지역 클래스&lt;/td&gt;
&lt;td&gt;메서드/블록 내부&lt;/td&gt;
&lt;td&gt;일부 접근 가능&lt;/td&gt;
&lt;td&gt;static 없음&lt;/td&gt;
&lt;td&gt;특정 메서드 내에서만 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;익명 클래스&lt;/td&gt;
&lt;td&gt;메서드/블록 내부&lt;/td&gt;
&lt;td&gt;일부 접근 가능&lt;/td&gt;
&lt;td&gt;static 없음&lt;/td&gt;
&lt;td&gt;일회성 인터페이스 구현 시&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;중첩 클래스는 코드의 논리적 구성을 돕고 캡슐화를 강화함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;내부 클래스는 외부 인스턴스와 강하게 연결되므로 주의가 필요함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지역 클래스와 익명 클래스는 메서드 내 일시적 기능 구현에 적합함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정적 중첩 클래스는 외부 인스턴스에 의존하지 않아 독립적으로 사용 가능함&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;출처 : ChatGPT&lt;/span&gt;&lt;/p&gt;</description>
      <category>BE/Java</category>
      <category>class</category>
      <category>java</category>
      <author>baek-dev</author>
      <guid isPermaLink="true">https://baek-dev.tistory.com/235</guid>
      <comments>https://baek-dev.tistory.com/235#entry235comment</comments>
      <pubDate>Mon, 21 Jul 2025 12:20:22 +0900</pubDate>
    </item>
    <item>
      <title>LocalDate.parse(입력문자,포맷);</title>
      <link>https://baek-dev.tistory.com/234</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;LocalDate.parse(입력문자열, 포맷터) 는 &lt;b&gt;문자열을 LocalDate 객체로 변환할 때 사용하는 정적 메서드&lt;/b&gt;임.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;LocalDate.parse(입력문자, 포맷) &amp;ndash; 문자열을 날짜로 파싱하는 메서드&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LocalDate.parse(String text, DateTimeFormatter formatter)&lt;/b&gt; 는&lt;br /&gt;문자열 형식의 날짜를 &lt;b&gt;LocalDate 객체로 변환(parse)&lt;/b&gt; 하는 메서드임.&lt;br /&gt;입력 문자열의 형식을 DateTimeFormatter.ofPattern() 을 통해 지정할 수 있음.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 기본 구조&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;LocalDate.parse(&quot;2025-05-21&quot;, DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd&quot;));
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫 번째 인자: 문자열(String)&lt;/li&gt;
&lt;li&gt;두 번째 인자: 포맷터(DateTimeFormatter)&lt;/li&gt;
&lt;li&gt;반환값: LocalDate 객체&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 예제 ① 기본 포맷 (ISO-8601)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java의 LocalDate.parse(String) 는 포맷을 생략하면 ISO-8601 형식(yyyy-MM-dd)으로 간주함&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;LocalDate date = LocalDate.parse(&quot;2025-05-21&quot;);
// formatter 생략 가능
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 예제 ② 사용자 지정 포맷 사용&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;String input = &quot;21/05/2025&quot;;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(&quot;dd/MM/yyyy&quot;);

LocalDate date = LocalDate.parse(input, formatter); // 2025-05-21
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;rarr; 포맷이 다르면 DateTimeParseException 예외가 발생함&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 예제 ③ 한글 날짜 파싱&lt;/h2&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;String input = &quot;2025년 5월 21일&quot;;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(&quot;yyyy년 M월 d일&quot;);

LocalDate date = LocalDate.parse(input, formatter);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;rarr; 포맷 문자열은 입력과 정확히 일치해야 함&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 주의사항&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;포맷 불일치&lt;/td&gt;
&lt;td&gt;포맷이 입력 문자열과 다르면 DateTimeParseException 발생&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MM vs mm&lt;/td&gt;
&lt;td&gt;MM: 월 / mm: 분 &amp;rarr; 혼용 금지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;24시간제 사용 시&lt;/td&gt;
&lt;td&gt;LocalDate는 시/분/초 없음 &amp;rarr; 시간 관련 포맷 사용 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 자주 쓰는 포맷 패턴&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;포맷&lt;/td&gt;
&lt;td&gt;의미&lt;/td&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;yyyy-MM-dd&lt;/td&gt;
&lt;td&gt;ISO 기본 형식&lt;/td&gt;
&lt;td&gt;2025-05-21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dd/MM/yyyy&lt;/td&gt;
&lt;td&gt;유럽식&lt;/td&gt;
&lt;td&gt;21/05/2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;yyyy.MM.dd&lt;/td&gt;
&lt;td&gt;점(.) 구분&lt;/td&gt;
&lt;td&gt;2025.05.21&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;yyyy년 M월 d일&lt;/td&gt;
&lt;td&gt;한글 포맷&lt;/td&gt;
&lt;td&gt;2025년 5월 21일&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 실무 활용 예시&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;활용 상황&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용자 입력 날짜 파싱&lt;/td&gt;
&lt;td&gt;Form, Excel 등에서 입력된 날짜 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;외부 API 응답 파싱&lt;/td&gt;
&lt;td&gt;JSON 등에서 전달된 날짜 문자열을 객체로 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;파일 이름의 날짜 추출&lt;/td&gt;
&lt;td&gt;로그 파일 이름 등에서 날짜 추출&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LocalDate.parse(입력문자, 포맷) 은 문자열을 &lt;b&gt;LocalDate 객체로 변환&lt;/b&gt;할 때 사용하는 메서드임.&lt;br /&gt;DateTimeFormatter.ofPattern() 과 함께 사용하여 &lt;b&gt;다양한 형식의 문자열을 날짜로 안전하게 파싱&lt;/b&gt;할 수 있음.&lt;br /&gt;입력 포맷이 정확히 일치해야 하며, 날짜만을 처리하기 때문에 시간 정보는 포함할 수 없음.&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;출처 : ChatGPT&lt;/span&gt;&lt;/p&gt;</description>
      <category>BE/Java</category>
      <category>java</category>
      <category>localdate.parse()</category>
      <author>baek-dev</author>
      <guid isPermaLink="true">https://baek-dev.tistory.com/234</guid>
      <comments>https://baek-dev.tistory.com/234#entry234comment</comments>
      <pubDate>Thu, 29 May 2025 13:18:39 +0900</pubDate>
    </item>
    <item>
      <title>date.format()</title>
      <link>https://baek-dev.tistory.com/233</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서 date.format() 은 날짜/시간 객체를 &lt;b&gt;지정한 포맷 문자열로 변환하는 메서드&lt;/b&gt;임.&lt;br /&gt;Java 8 이후의 java.time API에서는 LocalDate, LocalDateTime, ZonedDateTime 등에서 format() 메서드를 지원함.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;date.format() &amp;ndash; 날짜 객체를 문자열로 변환하는 메서드&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;format()&lt;/b&gt; 은 Java 8 이상의 java.time 패키지에서 제공되며,&lt;br /&gt;날짜/시간 객체를 &lt;b&gt;사람이 읽을 수 있는 문자열 형태로 포맷&lt;/b&gt;할 때 사용함.&lt;br /&gt;DateTimeFormatter 와 함께 사용되며, &lt;b&gt;스레드 세이프하고 직관적인 날짜 출력 방식&lt;/b&gt;을 제공함.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 기본 사용법&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;LocalDate date = LocalDate.of(2025, 5, 21);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd&quot;);

String result = date.format(formatter); // &quot;2025-05-21&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;date.format() 은 내부적으로 formatter의 format(date) 와 같음&lt;/li&gt;
&lt;li&gt;DateTimeFormatter 객체를 넘겨서 &lt;b&gt;출력 형식&lt;/b&gt;을 지정함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. LocalDateTime 예제&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;LocalDateTime now = LocalDateTime.of(2025, 5, 21, 14, 30, 0);
String formatted = now.format(DateTimeFormatter.ofPattern(&quot;yyyy/MM/dd HH:mm&quot;)); // &quot;2025/05/21 14:30&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 자주 사용하는 포맷 예시&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;포맷&lt;/td&gt;
&lt;td&gt;문자열 의미&lt;/td&gt;
&lt;td&gt;결과 예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;yyyy-MM-dd&lt;/td&gt;
&lt;td&gt;연-월-일&lt;/td&gt;
&lt;td&gt;&quot;2025-05-21&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;yyyy년 M월 d일&lt;/td&gt;
&lt;td&gt;한글 날짜 표현&lt;/td&gt;
&lt;td&gt;&quot;2025년 5월 21일&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;yyyyMMdd_HHmmss&lt;/td&gt;
&lt;td&gt;파일명 등 기술적 표기&lt;/td&gt;
&lt;td&gt;&quot;20250521_143000&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EEEE&lt;/td&gt;
&lt;td&gt;요일 (풀 이름)&lt;/td&gt;
&lt;td&gt;&quot;Wednesday&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;a hh:mm&lt;/td&gt;
&lt;td&gt;오전/오후 시:분&lt;/td&gt;
&lt;td&gt;&quot;오후 02:30&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. ZonedDateTime 예시 (시간대 포함)&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of(&quot;Asia/Seoul&quot;));
String result = zdt.format(DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd HH:mm z&quot;)); 
// 예: &quot;2025-05-21 14:30 KST&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. DateTimeFormatter.ofLocalizedDateTime 사용&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;String result = LocalDateTime.now().format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM));
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SHORT, MEDIUM, LONG, FULL 등으로 로케일 기반 포맷도 가능함&lt;/li&gt;
&lt;li&gt;로케일 변경은 .withLocale(Locale.KOREA) 등으로 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 실무 사용 사례&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;사용 목적&lt;/td&gt;
&lt;td&gt;포맷&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI 출력용&lt;/td&gt;
&lt;td&gt;yyyy년 M월 d일 (E)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;파일명에 포함&lt;/td&gt;
&lt;td&gt;yyyyMMdd_HHmmss&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API 응답 JSON 포맷&lt;/td&gt;
&lt;td&gt;yyyy-MM-dd'T'HH:mm:ss (ISO 8601)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;로그 기록&lt;/td&gt;
&lt;td&gt;yyyy-MM-dd HH:mm:ss.SSS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 실수 주의사항&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;잘못된 코드&lt;/td&gt;
&lt;td&gt;원인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&quot;mm&quot; &amp;rarr; 분 / &quot;MM&quot; &amp;rarr; 월&lt;/td&gt;
&lt;td&gt;혼동되기 쉬움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hh 사용 시 a 없이 출력&lt;/td&gt;
&lt;td&gt;12시간제는 a와 함께 사용해야 정확함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;format() 호출 시 NullPointerException&lt;/td&gt;
&lt;td&gt;formatter가 null이거나 날짜 객체가 null인 경우 발생함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;date.format(DateTimeFormatter)&lt;/b&gt; 은 Java 8 이상에서&lt;br /&gt;LocalDate, LocalDateTime, ZonedDateTime 등의 날짜 객체를 &lt;b&gt;사람이 읽을 수 있는 문자열로 포맷&lt;/b&gt;하는 메서드임.&lt;br /&gt;DateTimeFormatter.ofPattern() 과 함께 사용하여&lt;br /&gt;&lt;b&gt;간단하고 안전하게 날짜/시간을 문자열로 출력할 수 있음.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;출처 : ChatGPT&lt;/span&gt;&lt;/p&gt;</description>
      <category>BE/Java</category>
      <category>date.format()</category>
      <category>java</category>
      <author>baek-dev</author>
      <guid isPermaLink="true">https://baek-dev.tistory.com/233</guid>
      <comments>https://baek-dev.tistory.com/233#entry233comment</comments>
      <pubDate>Wed, 28 May 2025 15:01:34 +0900</pubDate>
    </item>
  </channel>
</rss>