<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>nstgic3_archive</title>
    <link>https://nstgic3.tistory.com/</link>
    <description>Studying archive
https://github.com/ChoMinGi</description>
    <language>ko</language>
    <pubDate>Wed, 8 Apr 2026 18:03:54 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>nstgic3</managingEditor>
    <image>
      <title>nstgic3_archive</title>
      <url>https://tistory1.daumcdn.net/tistory/5487685/attach/c2e42467e5d1406a92e9f839547c2eaf</url>
      <link>https://nstgic3.tistory.com</link>
    </image>
    <item>
      <title>[Gmail SMTP] 인증 방식 비교 16자리 패스키 vs OAuth2</title>
      <link>https://nstgic3.tistory.com/entry/Gmail-SMTP-%EC%9D%B8%EC%A6%9D-%EB%B0%A9%EC%8B%9D-%EB%B9%84%EA%B5%90-16%EC%9E%90%EB%A6%AC-%ED%8C%A8%EC%8A%A4%ED%82%A4-vs-OAuth2</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;SMTP(Simple Mail Transfer Protocol)는 메일 전송 프로토콜이다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1751529163839&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Simple Mail Transfer Protocol - Wikipedia&quot; data-og-description=&quot;From Wikipedia, the free encyclopedia Internet protocol used for relaying e-mails Simple Mail Transfer ProtocolAbbreviationSMTPPurposeElectronic mail transmission protocolIntroductionNovember&amp;nbsp;1981; 43&amp;nbsp;years ago&amp;nbsp;(1981-11)OSI layerApplication layerPort(s)&quot; data-og-host=&quot;en.wikipedia.org&quot; data-og-source-url=&quot;https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#:~:text=SMTP%20(%20Simple%20Mail%20Transfer%20Protocol%20)%EB%8A%94,%EC%A0%84%EC%86%A1%EC%9D%84%20%EC%9C%84%ED%95%9C%20%EC%9D%B8%ED%84%B0%EB%84%B7%20%ED%91%9C%EC%A4%80%20%ED%86%B5%EC%8B%A0%20%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C%20%EC%9E%85%EB%8B%88%EB%8B%A4.&amp;amp;text=SMTP%20%EC%84%9C%EB%B2%84%EB%8A%94%20%EC%9D%BC%EB%B0%98%EC%A0%81%EC%9C%BC%EB%A1%9C%20%ED%8F%AC%ED%8A%B8%20%EB%B2%88%ED%98%B8%2025(%EC%84%9C%EB%B2%84%20%EA%B0%84)%EC%99%80,%EC%82%AC%EC%9A%A9%ED%95%98%EB%A9%B0%2C%20%EC%A0%84%EC%86%A1%20%EC%8B%9C%EC%97%90%EB%8A%94%20465%EB%B2%88%20%ED%8F%AC%ED%8A%B8%EB%A5%BC%20%EC%95%94%ED%98%B8%ED%99%94%ED%95%98%EC%97%AC%20%EC%82%AC%EC%9A%A9%ED%95%A9%EB%8B%88%EB%8B%A4.&quot; data-og-url=&quot;https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#:~:text=SMTP%20(%20Simple%20Mail%20Transfer%20Protocol%20)%EB%8A%94,%EC%A0%84%EC%86%A1%EC%9D%84%20%EC%9C%84%ED%95%9C%20%EC%9D%B8%ED%84%B0%EB%84%B7%20%ED%91%9C%EC%A4%80%20%ED%86%B5%EC%8B%A0%20%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C%20%EC%9E%85%EB%8B%88%EB%8B%A4.&amp;amp;text=SMTP%20%EC%84%9C%EB%B2%84%EB%8A%94%20%EC%9D%BC%EB%B0%98%EC%A0%81%EC%9C%BC%EB%A1%9C%20%ED%8F%AC%ED%8A%B8%20%EB%B2%88%ED%98%B8%2025(%EC%84%9C%EB%B2%84%20%EA%B0%84)%EC%99%80,%EC%82%AC%EC%9A%A9%ED%95%98%EB%A9%B0%2C%20%EC%A0%84%EC%86%A1%20%EC%8B%9C%EC%97%90%EB%8A%94%20465%EB%B2%88%20%ED%8F%AC%ED%8A%B8%EB%A5%BC%20%EC%95%94%ED%98%B8%ED%99%94%ED%95%98%EC%97%AC%20%EC%82%AC%EC%9A%A9%ED%95%A9%EB%8B%88%EB%8B%A4.&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#:~:text=SMTP%20(%20Simple%20Mail%20Transfer%20Protocol%20)%EB%8A%94,%EC%A0%84%EC%86%A1%EC%9D%84%20%EC%9C%84%ED%95%9C%20%EC%9D%B8%ED%84%B0%EB%84%B7%20%ED%91%9C%EC%A4%80%20%ED%86%B5%EC%8B%A0%20%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C%20%EC%9E%85%EB%8B%88%EB%8B%A4.&amp;amp;text=SMTP%20%EC%84%9C%EB%B2%84%EB%8A%94%20%EC%9D%BC%EB%B0%98%EC%A0%81%EC%9C%BC%EB%A1%9C%20%ED%8F%AC%ED%8A%B8%20%EB%B2%88%ED%98%B8%2025(%EC%84%9C%EB%B2%84%20%EA%B0%84)%EC%99%80,%EC%82%AC%EC%9A%A9%ED%95%98%EB%A9%B0%2C%20%EC%A0%84%EC%86%A1%20%EC%8B%9C%EC%97%90%EB%8A%94%20465%EB%B2%88%20%ED%8F%AC%ED%8A%B8%EB%A5%BC%20%EC%95%94%ED%98%B8%ED%99%94%ED%95%98%EC%97%AC%20%EC%82%AC%EC%9A%A9%ED%95%A9%EB%8B%88%EB%8B%A4.&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#:~:text=SMTP%20(%20Simple%20Mail%20Transfer%20Protocol%20)%EB%8A%94,%EC%A0%84%EC%86%A1%EC%9D%84%20%EC%9C%84%ED%95%9C%20%EC%9D%B8%ED%84%B0%EB%84%B7%20%ED%91%9C%EC%A4%80%20%ED%86%B5%EC%8B%A0%20%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C%20%EC%9E%85%EB%8B%88%EB%8B%A4.&amp;amp;text=SMTP%20%EC%84%9C%EB%B2%84%EB%8A%94%20%EC%9D%BC%EB%B0%98%EC%A0%81%EC%9C%BC%EB%A1%9C%20%ED%8F%AC%ED%8A%B8%20%EB%B2%88%ED%98%B8%2025(%EC%84%9C%EB%B2%84%20%EA%B0%84)%EC%99%80,%EC%82%AC%EC%9A%A9%ED%95%98%EB%A9%B0%2C%20%EC%A0%84%EC%86%A1%20%EC%8B%9C%EC%97%90%EB%8A%94%20465%EB%B2%88%20%ED%8F%AC%ED%8A%B8%EB%A5%BC%20%EC%95%94%ED%98%B8%ED%99%94%ED%95%98%EC%97%AC%20%EC%82%AC%EC%9A%A9%ED%95%A9%EB%8B%88%EB%8B%A4.&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Simple Mail Transfer Protocol - Wikipedia&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;From Wikipedia, the free encyclopedia Internet protocol used for relaying e-mails Simple Mail Transfer ProtocolAbbreviationSMTPPurposeElectronic mail transmission protocolIntroductionNovember&amp;nbsp;1981; 43&amp;nbsp;years ago&amp;nbsp;(1981-11)OSI layerApplication layerPort(s)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;en.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;Gmail SMTP 서버를 사용할 경우, 기본 사용자명/비밀번호 인증은 2022년 이후로 지원되지 않는다.&lt;/span&gt;&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;대신 아래 두 가지 인증 방식이 제공된다.&lt;/span&gt;&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;App Password 방식 (2FA 필수)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;OAuth2 방식 (Token 기반, 2FA 우회 가능)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;16자리 패스키 방식( App password)&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대부분의 기술블로그에서 설명하고 있고, 개인 계정의 IMAP 설정을 통해 해당 패스키를 앱 내부에 넣어 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특징&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2단계 인증(2FA)이 활성화된 계정만 사용 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Google 계정 설정에서 생성한 16자리 전용 비밀번호 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자는 비밀번호를 직접 소스 코드에 포함시켜야 함&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;장점&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;구현이 간단&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Gmail 계정만 있으면 바로 사용 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단점&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;비밀번호 직접 노출 위험&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1792&quot; data-origin-height=&quot;992&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M4bHp/btsO3MLrkj7/GLcrINEBTSlK4K7pewMzVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M4bHp/btsO3MLrkj7/GLcrINEBTSlK4K7pewMzVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M4bHp/btsO3MLrkj7/GLcrINEBTSlK4K7pewMzVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM4bHp%2FbtsO3MLrkj7%2FGLcrINEBTSlK4K7pewMzVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1792&quot; height=&quot;992&quot; data-origin-width=&quot;1792&quot; data-origin-height=&quot;992&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;설정 절차는 여러 블로그에서 설명하고 있어서 생략한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdFPmW/btsO4sZYaty/iFhfPQRDZAj8xgMiZ3G7n1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdFPmW/btsO4sZYaty/iFhfPQRDZAj8xgMiZ3G7n1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdFPmW/btsO4sZYaty/iFhfPQRDZAj8xgMiZ3G7n1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdFPmW%2FbtsO4sZYaty%2FiFhfPQRDZAj8xgMiZ3G7n1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1426&quot; height=&quot;422&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;422&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 구글에서는 그렇게 추천하지 않는다.&amp;nbsp;&amp;nbsp;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이전에 단순 비밀번호 방식의 smtp 접근법 또한 22년도 5월중으로 종료된 바가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPH5UJ/btsO3GxZpYo/x7yTZU3Zl8Mun7tEDfPYK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPH5UJ/btsO3GxZpYo/x7yTZU3Zl8Mun7tEDfPYK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPH5UJ/btsO3GxZpYo/x7yTZU3Zl8Mun7tEDfPYK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPH5UJ%2FbtsO3GxZpYo%2Fx7yTZU3Zl8Mun7tEDfPYK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1488&quot; height=&quot;506&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;국내 블로그글 중에서는 2FA 가 필수가 된 이유가 스팸메일을 보내는걸 방지하기 위해서 identify 를 하는것 같다라는 추측글이 있었는데,&amp;nbsp; Oauth2 방식으로 진행시에는 발신 계정이 2FA 를 요구하지 않는걸 보니 대상 어플리케이션의 보안문제에 가까운것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Oauth2 방식&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Oauth2 를 활용해 얻은 토큰을 이용해 발신자를 인증하는 방식이다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;만약 어플리케이션이 Oauth2 를 활용한다면 적극적으로 메일전송에도 이를 활용하는걸 생각해봐도 좋을것 같다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특징&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;OAuth2 access token을 이용한 SMTP 인증&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자 인증 또는 서비스 계정 방식 선택 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;XOAUTH2 메커니즘 사용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;장점&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;계정 비밀번호 직접 노출 없음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서버 간 통신(백엔드 자동 발송)에 적합&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Google Workspace에서는 Domain-wide Delegation 사용 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단점&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;구현 복잡도 높음 (Token 발급, 갱신 로직 필요)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;토큰 만료에 따른 예외 처리 필수&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;구성 요소&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;access token: short-lived credential (보통 1시간)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;refresh token: long-lived credential (갱신용)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;scope:&amp;nbsp;&lt;a href=&quot;https://mail.google.com/&quot;&gt;https://mail.google.com/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인증 메커니즘: XOAUTH2&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2120&quot; data-origin-height=&quot;1322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvOec7/btsO29nbbql/Gich1jK1htZDGh1RKBfmkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvOec7/btsO29nbbql/Gich1jK1htZDGh1RKBfmkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvOec7/btsO29nbbql/Gich1jK1htZDGh1RKBfmkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvOec7%2FbtsO29nbbql%2FGich1jK1htZDGh1RKBfmkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2120&quot; height=&quot;1322&quot; data-origin-width=&quot;2120&quot; data-origin-height=&quot;1322&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;아 뭔가 여러가지를 해야하는게 보인다.&amp;nbsp;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;앱이 대신 메일을 보낸다면, 사용자가 그 행위를 &lt;b&gt;OAuth 동의창을 통해 직접 승인&lt;/b&gt;해야만 하기 때문에 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Google은 사용자의 Gmail 접근에 대해 반드시&amp;nbsp;&lt;/span&gt;&lt;b&gt;명시적 동의&lt;/b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;를 요구하게 된다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;따라서 관리자(메일 발신자)&lt;/span&gt;가 웹 UI에서 &quot;이 계정으로 뉴스레터 발송&quot; 같은 api 가 필요하겠다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;추후에 Oauth2 인증 과정 (&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;607&quot; data-start=&quot;546&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;브라우저 &amp;rarr; Google OAuth Consent Screen&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;rarr; 사용자가 메일 전송 권한 수락&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;673&quot; data-start=&quot;608&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서버가 Authorization Code 수신 &amp;rarr; Access Token + Refresh Token 발급&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;707&quot; data-start=&quot;674&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;Refresh Token을 DB 등에 안전하게 저장&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;) 을 거쳐야겠다.&amp;nbsp; 대신 편의를 위해 refreshToken 은 저장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2036&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KfkOT/btsO3xVCj97/OI16WSwBAQdIIrQZcFSUG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KfkOT/btsO3xVCj97/OI16WSwBAQdIIrQZcFSUG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KfkOT/btsO3xVCj97/OI16WSwBAQdIIrQZcFSUG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKfkOT%2FbtsO3xVCj97%2FOI16WSwBAQdIIrQZcFSUG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2036&quot; height=&quot;290&quot; data-origin-width=&quot;2036&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;토큰 을 활용하는 아키텍처가 도입되었으니 핸들링 해야하는 케이스도 많아진다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. Refresh Token &amp;rarr; Access Token 발급&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[이전과 같은] JavaMail 설정 구성 (Session, MimeMessage)&amp;nbsp;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. XOAUTH2로 Gmail SMTP 접속 후 뉴스레터 전송&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;AccessToken 의 만료 유무도 고려해야한다. 만료 시간도 함께 DB 에 저장해서&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;711&quot; data-start=&quot;680&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;선 조회 후 필요 시 갱신&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1751531148912&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String getSMTPAccessToken() {
    Token token = tokenRepository.findByUser(&quot;admin@gmail.com&quot;);

    if (token.isExpired()) {
        token = refreshAccessToken(token.getRefreshToken());
        tokenRepository.save(token);
    }

    return token.getAccessToken();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;h3 data-end=&quot;1022&quot; data-start=&quot;993&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;무조건 재발급 후 저장&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1751531172341&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String getSMTPAccessToken() {
    Token newToken = refreshAccessToken(existingRefreshToken);
    tokenRepository.save(newToken);
    return newToken.getAccessToken();
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;혹은 아예 예외를 터트려 버리는거도 방법일거같다&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h2 data-end=&quot;1316&quot; data-start=&quot;1286&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;실패 시 재발급 후 재시도 (예외 기반 흐름)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1751531228278&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try {
    transport.connect(&quot;smtp.gmail.com&quot;, username, accessToken);
} catch (AuthenticationFailedException e) {
    // 토큰 만료 or 폐기
    Token refreshed = refreshAccessToken(refreshToken);
    tokenRepository.save(refreshed);
    transport.connect(&quot;smtp.gmail.com&quot;, username, refreshed.getAccessToken());
}​&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;혹은 모놀리 구조에서만 가능하겠지만 or 레디스 같은 db 활용해서 accessToken 을 만료 시간까지만 캐싱해놓고 null check하는것도 방법일것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;사용 시나리오 비교&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그래서 GPT한테 언제 뭐쓰면 좋겠느냐고 물어봤다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;상황 권장 방식 비고&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개인 블로그, 소규모 서버&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;App Password&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2FA 필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자 없이 메일 자동 발송&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;OAuth2&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;refresh token 필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;조직 내 대표 계정 발송&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;OAuth2 + Domain-wide Delegation&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Google Workspace 환경&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Google 계정 없이도 작동&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;OAuth2 + Service Account&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자 로그인 불필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;이렇다고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대부분의 토이 프로젝트는 App Password 로 충분해보인다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;XOauth2 를 제공하는 JavaMail&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1714&quot; data-origin-height=&quot;958&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjqz3r/btsO4doxVJ3/0soMxwnNvpjx10VAKujLkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjqz3r/btsO4doxVJ3/0soMxwnNvpjx10VAKujLkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjqz3r/btsO4doxVJ3/0soMxwnNvpjx10VAKujLkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbjqz3r%2FbtsO4doxVJ3%2F0soMxwnNvpjx10VAKujLkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1714&quot; height=&quot;958&quot; data-origin-width=&quot;1714&quot; data-origin-height=&quot;958&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; Google 이메일 서비스가 2022년에 기존의 비밀번호 기반 인증을 제외한것처럼 Java Mail Sender 의존 내의 JavaMail도 1.5.5부터 XOAUTH2 메커니즘을 &lt;b&gt;내장 지원&lt;/b&gt;하고 있다.&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이런 흐름을 보면 추후에는 Oauth2 를 기반으로 한 인증 방식이 표준이 되어가지 않을까 생각하면서, 다음 프로젝트에는 적용을 해보려한다. 예제도 괜찮을듯,,&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS</category>
      <category>gmail passkey</category>
      <category>Java mail</category>
      <category>oauth2</category>
      <category>smtp 2fa</category>
      <category>xoauth2 내장 지원</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/243</guid>
      <comments>https://nstgic3.tistory.com/entry/Gmail-SMTP-%EC%9D%B8%EC%A6%9D-%EB%B0%A9%EC%8B%9D-%EB%B9%84%EA%B5%90-16%EC%9E%90%EB%A6%AC-%ED%8C%A8%EC%8A%A4%ED%82%A4-vs-OAuth2#entry243comment</comments>
      <pubDate>Thu, 3 Jul 2025 17:45:37 +0900</pubDate>
    </item>
    <item>
      <title>Spring은 어떻게 컨트롤러를 찾아 실행할까? (1편) - DispatcherServlet과 리플렉션</title>
      <link>https://nstgic3.tistory.com/entry/Spring%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC%EB%A5%BC-%EC%B0%BE%EC%95%84-%EC%8B%A4%ED%96%89%ED%95%A0%EA%B9%8C-1%ED%8E%B8-DispatcherServlet%EA%B3%BC-%EB%A6%AC%ED%94%8C%EB%A0%89%EC%85%98</link>
      <description>&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Spring MVC를 사용하면서 자연스럽게 사용하고 있는 것이 바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;@Controller&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;@GetMapping&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;@PostMapping&lt;/span&gt;&lt;span&gt;과 같은 애너테이션 기반 컨트롤러 매핑이다. 그러나 내부적으로 이 컨트롤러들이 실제로 어떻게 등록되고 매핑되는지 이해하는 개발자는 많지 않다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 글에서는 Spring MVC가 내부적으로 어떻게 컨트롤러를 등록하고, 요청이 왔을 때 어떻게 적절한 컨트롤러 메서드를 찾아 실행하는지 살펴본다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;DispatcherServlet 이란?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Spring MVC에서 가장 중요한 클래스는 바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;DispatcherServlet이다. DispatcherServlet은 프론트 컨트롤러 역할을 하며, 모든 요청의 진입점이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링이 실행될때의 ApplicationContext 초기화 흐름을 한번 살펴보자, [어플리케이션의 구동 시점]&lt;/p&gt;
&lt;pre id=&quot;code_1744166399673&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. ApplicationContext(WebApplicationContext) 초기화 시작
   └ 빈(Bean) 생성 및 의존성 주입 (DI)
   └ @Controller, @Service 등 Component 스캔 (클래스패스 스캔)
     └ 리플렉션(Reflection)을 사용하여 클래스 및 메서드 분석
     └ 컨트롤러(@Controller)의 메서드(@GetMapping, @PostMapping) 정보를 추출
     └ 추출된 URL과 메서드 정보를 RequestMappingHandlerMapping에 등록
2. ApplicationContext 초기화 완료&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;[클라이언트의 요청 처리 시점]에서도 살펴 보자&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1744166600541&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;클라이언트 요청 
&amp;rarr; DispatcherServlet이 요청을 받음
&amp;rarr; HandlerMapping(RequestMappingHandlerMapping)을 통해 미리 등록된 URL &amp;harr; Controller 메서드 정보에서 요청에 맞는 메서드 탐색
&amp;rarr; HandlerAdapter가 Controller 메서드를 실행
&amp;rarr; Controller 메서드가 비즈니스 로직을 처리하고 View 이름을 반환
&amp;rarr; DispatcherServlet이 ViewResolver를 통해 View 객체를 찾아 반환
&amp;rarr; 클라이언트에 응답 전송&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;컨트롤러는 언제, 어떻게 등록되는가? (어플리케이션 시점)&lt;/span&gt;&lt;/h3&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt; &lt;span&gt;예를 들어 아래와 같은 컨트롤러가 있다면&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;@Controller
public class HelloController {

    @GetMapping(&quot;/hello&quot;)
    public String hello() {
        return &quot;hello&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Spring은 다음과 같은 과정으로 컨트롤러를 등록한다&lt;/span&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;span&gt;1. 클래스 스캔 중&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;@Controller&lt;/span&gt;&lt;span&gt;가 붙은 클래스를 찾는다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.baeldung.com/spring-component-scanning&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.baeldung.com/spring-component-scanning&lt;/a&gt;&lt;/span&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;span&gt;2. 리플렉션 API(&lt;/span&gt;&lt;span&gt;Class.getDeclaredMethods()&lt;/span&gt;&lt;span&gt;)를 사용하여 해당 클래스의 모든 메서드를 읽는다.&lt;/span&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;span&gt;자바의 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Reflection(리플렉션)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 이란, 객체를 통해 클래스의 정보를 분석하거나 런타임(runtime)에 클래스의 동작을 검사하고 조작할 수 있게 해주는 기술이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;리플렉션을 사용하면 클래스 이름만 알고 있어도 다음과 같은 작업을 수행할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;클래스의 메서드, 변수, 생성자와 같은 정보 조회&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;클래스의 객체를 동적으로 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;객체의 메서드를 동적으로 호출&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, 리플렉션은 컴파일 시점에서 클래스에 대한 명확한 타입 정보를 알지 못하더라도, 실행 시점(runtime)에 동적으로 클래스를 활용할 수 있게 해준다.&lt;/span&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;span&gt;3. 메서드에 붙은 애너테이션(&lt;/span&gt;&lt;span&gt;@GetMapping&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;@PostMapping&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등)을 확인하고, URL 패턴과 HTTP 메서드 등을 추출한다.&lt;/span&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;span&gt;4. 이렇게 얻은 정보를 바탕으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;RequestMappingHandlerMapping&lt;/span&gt;&lt;span&gt;에 등록하여 URL &amp;rarr; 메서드 매핑 테이블을 만든다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;* 매핑 테이블을 만드는 과정 - Spring MVC 기준&lt;/span&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;667&quot; data-start=&quot;101&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;279&quot; data-start=&quot;101&quot;&gt;&lt;b&gt;클래스 후보 찾기&lt;/b&gt;&lt;br /&gt;ClassPathScanningCandidateComponentProvider가 ASM으로 클래스 파일을 읽어&lt;br /&gt;@Controller, @RestController 등을 가진 빈 후보를 모읍니다.&lt;br /&gt;이때는 클래스 로딩&amp;middot;리플렉션 없이 바이트코드만 훑음.&lt;br /&gt;&lt;a href=&quot;https://minkukjo.github.io/framework/2020/07/09/Spring-133/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://minkukjo.github.io/framework/2020/07/09/Spring-133/&lt;/a&gt;&lt;/li&gt;
&lt;li data-end=&quot;512&quot; data-start=&quot;281&quot;&gt;&lt;b&gt;빈 로딩 후 메서드 조사&lt;/b&gt;&lt;br /&gt;RequestMappingHandlerMapping.initHandlerMethods() &amp;rarr;&lt;br /&gt;MethodIntrospector.selectMethods()
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;512&quot; data-start=&quot;408&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;424&quot; data-start=&quot;408&quot;&gt;실제 클래스를 로딩하고&lt;/li&gt;
&lt;li data-end=&quot;512&quot; data-start=&quot;428&quot;&gt;&lt;b&gt;리플렉션으로 모든 메서드&amp;middot;애노테이션&lt;/b&gt;을 순회하여&lt;br /&gt;@RequestMapping, @GetMapping 등 매핑 정보를 수집.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;667&quot; data-start=&quot;514&quot;&gt;&lt;b&gt;매핑 테이블 구축&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;667&quot; data-start=&quot;536&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;566&quot; data-start=&quot;536&quot;&gt;각 메서드를 HandlerMethod로 래핑&lt;/li&gt;
&lt;li data-end=&quot;618&quot; data-start=&quot;570&quot;&gt;Map&amp;lt;RequestMappingInfo, HandlerMethod&amp;gt;에 저장&lt;/li&gt;
&lt;li data-end=&quot;667&quot; data-start=&quot;622&quot;&gt;이후 DispatcherServlet이 URL 패턴으로 &lt;b&gt;O(1) 조회&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;figure id=&quot;og_1744172570927&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;ComponentScan Annotation이 처리되는 과정&quot; data-og-description=&quot;Component Scan 실질적으로 처리하는 클래스와 메소드&quot; data-og-host=&quot;minkukjo.github.io&quot; data-og-source-url=&quot;https://minkukjo.github.io/framework/2020/07/09/Spring-133/&quot; data-og-url=&quot;https://minkukjo.github.io/framework/2020/07/09/Spring-133/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eAQPe/hyYEJRH6Gi/RmYDZrkQVJOFtAEdyu2Mz0/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200,https://scrap.kakaocdn.net/dn/bkPicC/hyYClRVB8d/GQm82P0IAKulnydja6lyw0/img.png?width=3636&amp;amp;height=452&amp;amp;face=0_0_3636_452&quot;&gt;&lt;a href=&quot;https://minkukjo.github.io/framework/2020/07/09/Spring-133/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://minkukjo.github.io/framework/2020/07/09/Spring-133/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eAQPe/hyYEJRH6Gi/RmYDZrkQVJOFtAEdyu2Mz0/img.png?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200,https://scrap.kakaocdn.net/dn/bkPicC/hyYClRVB8d/GQm82P0IAKulnydja6lyw0/img.png?width=3636&amp;amp;height=452&amp;amp;face=0_0_3636_452');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;ComponentScan Annotation이 처리되는 과정&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Component Scan 실질적으로 처리하는 클래스와 메소드&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;minkukjo.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;리플렉션은 성능에 문제를 주지 않을까?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;리플렉션은 일반적으로 성능이 좋지 않다고 알려져 있다.&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt; &lt;a href=&quot;https://blogs.oracle.com/javamagazine/post/java-reflection-performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://blogs.oracle.com/javamagazine/post/java-reflection-performance&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1744168031620&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;blog&quot; data-og-title=&quot;The performance implications of Java reflection&quot; data-og-description=&quot;Reflection slows down your Java code. Why is that?&quot; data-og-host=&quot;blogs.oracle.com&quot; data-og-source-url=&quot;https://blogs.oracle.com/javamagazine/post/java-reflection-performance&quot; data-og-url=&quot;https://orasites-prodapp.cec.ocp.oraclecloud.com/site/javamagazine/post/java-reflection-performance&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/QloSu/hyYBdtpVoY/oZK3wJWiCfepYeXWlh4GxK/img.jpg?width=1024&amp;amp;height=576&amp;amp;face=0_0_1024_576,https://scrap.kakaocdn.net/dn/FQZQ9/hyYCcHp1Hg/sMNJgN6gnhYncIdiQ8D2Lk/img.jpg?width=1024&amp;amp;height=576&amp;amp;face=0_0_1024_576,https://scrap.kakaocdn.net/dn/hcV4U/hyYCkk7RQs/SewhUVUg3UGTIyTqfAvH0k/img.jpg?width=1000&amp;amp;height=570&amp;amp;face=0_0_1000_570&quot;&gt;&lt;a href=&quot;https://blogs.oracle.com/javamagazine/post/java-reflection-performance&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blogs.oracle.com/javamagazine/post/java-reflection-performance&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/QloSu/hyYBdtpVoY/oZK3wJWiCfepYeXWlh4GxK/img.jpg?width=1024&amp;amp;height=576&amp;amp;face=0_0_1024_576,https://scrap.kakaocdn.net/dn/FQZQ9/hyYCcHp1Hg/sMNJgN6gnhYncIdiQ8D2Lk/img.jpg?width=1024&amp;amp;height=576&amp;amp;face=0_0_1024_576,https://scrap.kakaocdn.net/dn/hcV4U/hyYCkk7RQs/SewhUVUg3UGTIyTqfAvH0k/img.jpg?width=1000&amp;amp;height=570&amp;amp;face=0_0_1000_570');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;The performance implications of Java reflection&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Reflection slows down your Java code. Why is that?&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blogs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 요약 : 리플렉션은 컴파일 시점에 구체적인 타입을 모르더라도, 런타임에 클래스‧메서드‧필드 정보를 조회하고 조작하는 기능이다.&lt;br /&gt;즉, 유연성 대가로 JNI 전환, 인라이닝 불가, 박싱, 접근 제어 등 의 특징을 가진다.&lt;br /&gt;호출 빈도를 감지해 바이트코드를 동적 생성해 완화하지만, 여전히 직접 호출보다 느리다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt; &lt;span&gt;그렇다면 Spring은 리플렉션으로 인한 성능 문제를 어떻게 해결할까?&lt;/span&gt;&lt;/span&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결론부터 말하자면, Spring은 리플렉션을 초기 한 번만 사용한다. (하단은 BeanUtils의 코드)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;999&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp9Qj4/btsNc8jr678/lQcpCXYkINAqkzTr8QprHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp9Qj4/btsNc8jr678/lQcpCXYkINAqkzTr8QprHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp9Qj4/btsNc8jr678/lQcpCXYkINAqkzTr8QprHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp9Qj4%2FbtsNc8jr678%2FlQcpCXYkINAqkzTr8QprHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;999&quot; height=&quot;236&quot; data-origin-width=&quot;999&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, 최초 애플리케이션 구동 시점에 한 번 클래스와 메서드 분석을 완료하고, 분석된 정보는 내부적으로 캐싱한다. 이후 실제 요청이 들어올 때는 캐싱된 정보를 기반으로 처리하므로 리플렉션을 다시 사용하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;요청이 들어왔을 때의 처리 과정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;span&gt;실제 요청이 들어왔을 때의 처리는 다음과 같다&lt;/span&gt;&lt;/span&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;span&gt;1. DispatcherServlet이 요청을 받고 URL을 분석한다.&lt;/span&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;span&gt;2. 미리 생성된 URL &amp;rarr; 메서드 매핑 테이블을 기반으로 HandlerMethod를 빠르게 찾아낸다. 즉, 캐시된 Map 을 통해 가져오는것이다.&lt;/span&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;span&gt;3. 찾아낸 메서드는 HandlerAdapter가 실행한다.&lt;/span&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;span&gt;4. HandlerMethod가 실행되어 결과가 반환되고, ViewResolver를 통해 뷰가 결정되어 최종 응답이 클라이언트에 전달된다.&lt;/span&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;span&gt;요청 처리 시점에는 리플렉션 API가 사용되지 않고, 캐싱된 정보가 사용되므로 성능이 매우 우수하다.&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;자바 코드로 모사해보자&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컨트롤러를 만들고, 그 컨트롤러 내 메서드를 호출하기&lt;/p&gt;
&lt;pre id=&quot;code_1744171726723&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.example.mvc;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;

public class MethodCall {
	public static void main(String[] args) throws Exception {
		HashMap&amp;lt;String, String&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
		System.out.println(&quot;before: &quot; + map);

		MyController controller = new MyController();
		String viewName = controller.main(map);

		System.out.println(&quot;after: &quot; + map);
		render(map, viewName);
	}

	static void render(HashMap&amp;lt;String, String&amp;gt; map, String viewName) throws IOException {
		StringBuilder result = new StringBuilder();
		Scanner sc = new Scanner(new File(viewName + &quot;.txt&quot;));
		while (sc.hasNextLine()) {
			result.append(sc.nextLine()).append(System.lineSeparator());
		}
		for (String key : map.keySet()) {
			result = new StringBuilder(result.toString().replace(&quot;${&quot; + key + &quot;}&quot;, map.get(key)));
		}
		System.out.println(result);
	}
}

class MyController {
	public String main(HashMap&amp;lt;String, String&amp;gt; map) {
		map.put(&quot;id&quot;, &quot;user01&quot;);
		map.put(&quot;pwd&quot;, &quot;1234&quot;);
		return &quot;viewTemplate&quot;;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;리플렉션을 활용해서 메서드 매핑 테이블을 만든다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1744171797912&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.example.mvc;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import org.springframework.ui.Model;
import org.springframework.validation.support.BindingAwareModelMap;

public class MethodCallWithReflection {
	public static void main(String[] args) throws Exception {
		Class&amp;lt;?&amp;gt; clazz = Class.forName(&quot;com.example.mvc.MyMvcController&quot;);
		Object obj = clazz.getDeclaredConstructor().newInstance();
        // 리플렉션이 적용된 부분.
		Method method = clazz.getDeclaredMethod(&quot;main&quot;, int.class, int.class, int.class, Model.class);

		Model model = new BindingAwareModelMap();
		System.out.println(&quot;[before] model=&quot; + model);

		String viewName = (String) method.invoke(obj, 2021, 10, 1, model);
		System.out.println(&quot;viewName=&quot; + viewName);
		System.out.println(&quot;[after] model=&quot; + model);

		render(model, viewName);
	}

	static void render(Model model, String viewName) throws IOException {
		String result = &quot;&quot;;
		Scanner sc = new Scanner(new File(&quot;src/views/&quot; + viewName + &quot;.jsp&quot;), &quot;utf-8&quot;);
		while (sc.hasNextLine()) {
			result += sc.nextLine() + System.lineSeparator();
		}
		Map&amp;lt;String, Object&amp;gt; map = model.asMap();
		for (String key : map.keySet()) {
			result = result.replace(&quot;${&quot; + key + &quot;}&quot;, map.get(key) + &quot;&quot;);
		}
		System.out.println(result);
	}
}&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;&lt;span&gt;정리하자면 Spring MVC는 애플리케이션 초기 구동 시 리플렉션을 통해 컨트롤러의 메서드 정보를 분석하고, 이후 실제 요청 처리 시에는 빠른 캐싱 정보를 활용한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>dispatherservlet</category>
      <category>spring이 컨트롤러를 찾는 방법</category>
      <category>리플렉션</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/242</guid>
      <comments>https://nstgic3.tistory.com/entry/Spring%EC%9D%80-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC%EB%A5%BC-%EC%B0%BE%EC%95%84-%EC%8B%A4%ED%96%89%ED%95%A0%EA%B9%8C-1%ED%8E%B8-DispatcherServlet%EA%B3%BC-%EB%A6%AC%ED%94%8C%EB%A0%89%EC%85%98#entry242comment</comments>
      <pubDate>Wed, 9 Apr 2025 13:15:59 +0900</pubDate>
    </item>
    <item>
      <title>Dayner에서 이벤트성, 일회성 쿠폰을 발급하고 관리하는 방법 [2]</title>
      <link>https://nstgic3.tistory.com/entry/Dayner%EC%97%90%EC%84%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EC%84%B1-%EC%9D%BC%ED%9A%8C%EC%84%B1-%EC%BF%A0%ED%8F%B0%EC%9D%84-%EB%B0%9C%EA%B8%89%ED%95%98%EA%B3%A0-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-2</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Part 1 에서는 쿠폰 발급 로직을 전략 패턴을 통해 분리하고 서비스 레이어를 명확히 나누어 유지보수성과 확장성을 향상시킨 내용을 다루었다. &lt;/span&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;span&gt;이번 포스팅에서는 쿠폰 발급의 빈도(IssuanceFrequency)와 제한 조건을 전략 패턴을 이용해 보다 유연하고 효율적으로 관리하는 방법을 소개하려고한다.&lt;/span&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;span&gt;쿠폰 시스템의 특성을 자세히 생각해본다면 &lt;/span&gt;&lt;span&gt;&lt;b&gt;&quot;얼마나, 누구한테, 언제, 쿠폰을 발급할 것인가?&quot;&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 발급 빈도와 제한 조건을 명확히 정의해야지, &lt;/span&gt;&lt;span&gt;이벤트 쿠폰이나 회원가입 축하 쿠폰 등 다양한 조건과 상황에 유연하게 대응이 가능해진다.&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어, 최근 클라이언트가 요청한 특정 기간에만 발급되는 신규 가입 이벤트 쿠폰의 경우를 살펴보자.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트 요청은 특정 기간(예: 3월 23일~3월 31일)에만 기존의 회원가입 축하 쿠폰 대신 새로운 쿠폰을 발급하고 싶어 했다. 또한, 이벤트 기간이 종료된 후에는 기존의 쿠폰 발급 전략으로 다시 복구를 요청 하기도 하였다.&lt;/span&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;span&gt;이전 포스팅에서는 이러한 요구사항을 효과적으로 관리하기 위해, 쿠폰 발급 전략을 별도의 정책(Policy) 엔티티로 정의하여 데이터베이스에 저장하고 관리하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-&amp;gt; 하지만 이때마다 매번 정책을 삭제하고 재생성하는 방식은 기존 쿠폰 발급 이력 관리나 통계 조회 시 혼란을 야기할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 정책에 대한 &lt;/span&gt;&lt;span&gt;&lt;b&gt;soft delete&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 방식을 활용하면 기존 데이터를 안전하게 보존하면서도 효율적으로 정책을 활성화 및 비활성화할 수 있다.&lt;/span&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;span&gt;또한, 해당 방식을 활용하게 된다면, 관리자 패널에서 한 가지 타입의 쿠폰 발급 전략을 동시에 단 하나만 활성화할 수 있도록 제한 조건을 추가를 통해서 위에 우리가 고민했던 상황에 유연하게 대처가 편해질 것이다.&lt;/span&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;span&gt;즉, 관리자 패널에서 정책 유형별로 쿠폰 발급 전략 목록을 제공하고, 그 중 딱 하나만 활성화 상태로 관리함으로써 발급 전략의 명확성과 유지보수 편의성을 높일 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이처럼 쿠폰 발급 빈도와 제한 조건을 명확히 설정하고 전략 패턴으로 구현하면 응집성 있게 다양한 비즈니스 요구사항에 효율적으로 대응할 수 있게 된다.&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그렇다면,&amp;nbsp; 내가 쿠폰 발급 제한 조건을 나눈 기준&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;그렇다면, 쿠폰 발급 제한 조건을 나누는 기준은 어떻게 설계하면 좋을까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;181&quot; data-start=&quot;42&quot; data-ke-size=&quot;size16&quot;&gt;쿠폰 발급의 빈도와 제한 조건을 명확히 관리하기 위해서는 먼저 쿠폰이 &lt;b&gt;어떤 상황에서&lt;/b&gt;, &lt;b&gt;얼마나 자주&lt;/b&gt; 발급될지를 정확히 분석해야 한다.&lt;/p&gt;
&lt;p data-end=&quot;181&quot; data-start=&quot;42&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;215&quot; data-start=&quot;183&quot; data-ke-size=&quot;size23&quot;&gt;1. 사용자 단위 제한 (ONCE_PER_USER)&lt;/h3&gt;
&lt;p data-end=&quot;389&quot; data-start=&quot;216&quot; data-ke-size=&quot;size16&quot;&gt;가장 흔하게 사용되는 제한 조건으로, 한 명의 사용자가 특정 쿠폰을 단 한 번만 받을 수 있도록 관리하는 방식이다.&lt;/p&gt;
&lt;p data-end=&quot;389&quot; data-start=&quot;216&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;389&quot; data-start=&quot;216&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 회원 가입 축하 쿠폰이나 특정 프로모션 참여에 대한 보상으로 발급되는 쿠폰이 여기에 해당한다. 이러한 제한은 사용자 단위로 쿠폰 중복 발급을 방지하고 공정성을 유지하는 데 유용하다.&lt;/p&gt;
&lt;h3 data-end=&quot;421&quot; data-start=&quot;391&quot; data-ke-size=&quot;size23&quot;&gt;2. 연 단위 제한 (ONCE_PER_YEAR)&lt;/h3&gt;
&lt;p data-end=&quot;601&quot; data-start=&quot;422&quot; data-ke-size=&quot;size16&quot;&gt;매년 반복적으로 진행되는 이벤트나 프로모션에서 활용되는 방식으로, 특정 쿠폰을 사용자당 연간 1회만 받을 수 있게 제한한다.&lt;/p&gt;
&lt;p data-end=&quot;601&quot; data-start=&quot;422&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;601&quot; data-start=&quot;422&quot; data-ke-size=&quot;size16&quot;&gt;주로 생일 쿠폰, 연말 감사 쿠폰 등 정기적으로 반복 발급되는 쿠폰에 적합한 제한 방식이다.&lt;/p&gt;
&lt;p data-end=&quot;601&quot; data-start=&quot;422&quot; data-ke-size=&quot;size16&quot;&gt;배치 프로세스를 통해 매년 지정된 날짜에 자동으로 발급 및 관리가 가능하도록 구현하는 것이 바람직하다.&lt;/p&gt;
&lt;h3 data-end=&quot;636&quot; data-start=&quot;603&quot; data-ke-size=&quot;size23&quot;&gt;3. 이벤트 단위 제한 (ONCE_PER_EVENT)&lt;/h3&gt;
&lt;p data-end=&quot;843&quot; data-start=&quot;637&quot; data-ke-size=&quot;size16&quot;&gt;특정 이벤트나 프로모션 기간 동안 사용자가 단 한 번만 쿠폰을 발급받을 수 있도록 설정하는 방식이다.&lt;/p&gt;
&lt;p data-end=&quot;843&quot; data-start=&quot;637&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;843&quot; data-start=&quot;637&quot; data-ke-size=&quot;size16&quot;&gt;이벤트 기간 내에 과도한 중복 참여나 악용 사례를 방지하는 데 효과적이다. 이 제한 방식은 특히 사용자가 몰리는 대규모 이벤트에서 동시성을 효과적으로 관리하기 위해, 쿠폰 재고 관리와 낙관적 락(Optimistic Lock)과 같은 기술적 전략이 필수적으로 요구된다.&lt;/p&gt;
&lt;p data-end=&quot;843&quot; data-start=&quot;637&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;843&quot; data-start=&quot;637&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;1045&quot; data-start=&quot;845&quot; data-ke-size=&quot;size16&quot;&gt;위의 제한 조건들은 개별 쿠폰 정책(Policy)으로 관리하고, 이를 전략 패턴(Strategy Pattern)을 활용해 동적으로 적용함으로써 각 정책이 쿠폰 발급 프로세스에 쉽게 추가 및 교체될 수 있게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;1045&quot; data-start=&quot;845&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;1045&quot; data-start=&quot;845&quot; data-ke-size=&quot;size16&quot;&gt;이를 통해 정책 변경이나 추가 요청이 들어올 때마다 기존 시스템의 코드를 수정하지 않고도 유연하게 대응할 수 있는 환경이 구축되는 것이다.&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;1045&quot; data-start=&quot;845&quot; 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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;563&quot; data-start=&quot;323&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;563&quot; data-start=&quot;382&quot;&gt;
&lt;tr data-end=&quot;442&quot; data-start=&quot;382&quot;&gt;
&lt;td&gt;&lt;b&gt;사용자 단위 제한&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;한 사용자가 한 번만 받을 수 있는 쿠폰 (ONCE_PER_USER)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;495&quot; data-start=&quot;443&quot;&gt;
&lt;td&gt;&lt;b&gt;연 단위 제한&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;연 1회만 받을 수 있는 쿠폰 (ONCE_PER_YEAR)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;563&quot; data-start=&quot;496&quot;&gt;
&lt;td&gt;&lt;b&gt;이벤트 단위 제한&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;특정 이벤트 기간 동안 한 번만 받을 수 있는 쿠폰 (ONCE_PER_EVENT)&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 contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;IssueFrequency 의 도입과 빈도 기반의 전략 패턴 적용&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;990&quot; data-start=&quot;941&quot; data-ke-size=&quot;size16&quot;&gt;쿠폰 정책을 설계할 때 단순히 쿠폰 발급 시점을 결정하는 것만으로는 부족하다.&lt;/p&gt;
&lt;p data-end=&quot;990&quot; data-start=&quot;941&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;990&quot; data-start=&quot;941&quot; data-ke-size=&quot;size16&quot;&gt;발급 빈도를 설정하고 이를 관리할 수 있는 명확한 전략이 있어야 시스템이 보다 유연해지고 관리가 수월해진다.&lt;/p&gt;
&lt;p data-end=&quot;990&quot; data-start=&quot;941&quot; data-ke-size=&quot;size16&quot;&gt;이를 위해 도입한 것이 바로 &lt;b&gt;IssuanceFrequency&lt;/b&gt;라는 개념이다.&lt;/p&gt;
&lt;p data-end=&quot;230&quot; data-start=&quot;195&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;230&quot; data-start=&quot;195&quot; data-ke-size=&quot;size16&quot;&gt;IssuanceFrequency는 다음과 같이 정의할 수 있다&lt;/p&gt;
&lt;pre id=&quot;code_1741333251939&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package net.dayner.api.domain.coupon.entity;

public enum IssuanceFrequency {
    ONCE_PER_USER,      // 최초 1회
    ONCE_PER_YEAR,      // 연 1회
    ONCE_PER_EVENT,     // 이벤트 기간 내 1회
    ONCE_PER_MONTH,     // 월 1회
    ONCE_PER_WEEK,      // 주 1회
    DAILY_LIMITED,      // 하루 1회 (예: 출석 체크 쿠폰)
    CUSTOM              // 커스텀 정책 (별도 로직 필요)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;230&quot; data-start=&quot;195&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;230&quot; data-start=&quot;195&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;564&quot; data-start=&quot;413&quot; data-ke-size=&quot;size16&quot;&gt;쿠폰 정책을 생성할 때 발급 빈도(IssuanceFrequency)를 설정하면, 발급 시점에서 사용자 및 정책의 조건에 따라 적절한 검증 로직을 수행해야 한다.&lt;/p&gt;
&lt;p data-end=&quot;564&quot; data-start=&quot;413&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;564&quot; data-start=&quot;413&quot; data-ke-size=&quot;size16&quot;&gt;하지만 이 발급 제한 로직을 모두 단일 클래스나 메서드에서 처리할 경우, 코드가 복잡해지고 유지보수가 어렵다.&lt;/p&gt;
&lt;p data-end=&quot;564&quot; data-start=&quot;413&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;714&quot; data-start=&quot;566&quot; data-ke-size=&quot;size16&quot;&gt;이러한 문제를 해결하기 위해 &lt;b&gt;전략 패턴(Strategy Pattern)&lt;/b&gt; 을 도입한다.&lt;/p&gt;
&lt;p data-end=&quot;714&quot; data-start=&quot;566&quot; data-ke-size=&quot;size16&quot;&gt;전략 패턴을 활용하면 IssuanceFrequency 타입별로 서로 다른 발급 제한 로직을 별도의 클래스에서 관리할 수 있으며, 런타임에 동적으로 선택하여 실행할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;714&quot; data-start=&quot;566&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;941&quot; data-start=&quot;716&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 사용자가 한 번만 받을 수 있는 쿠폰(ONCE_PER_USER)은 사용자의 발급 이력을 확인해 이미 발급된 적이 있는지 여부를 체크하는 로직이 필요하다.&lt;/p&gt;
&lt;p data-end=&quot;941&quot; data-start=&quot;716&quot; data-ke-size=&quot;size16&quot;&gt;반면, 연 단위 제한(ONCE_PER_YEAR) 쿠폰은 발급된 시점을 기준으로 특정 연도에만 한 번 허용하고, 이벤트 단위 제한(ONCE_PER_EVENT) 쿠폰은 특정 이벤트 기간을 기준으로 중복 발급 여부를 체크해야 한다.&lt;/p&gt;
&lt;p data-end=&quot;941&quot; data-start=&quot;716&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;1110&quot; data-start=&quot;943&quot; data-ke-size=&quot;size16&quot;&gt;결국, 전략 패턴을 통해 쿠폰 발급 조건을 동적으로 적용함으로써, 새로운 빈도 조건이 추가되거나 기존 발급 제한 조건이 변경되더라도 코드 수정 없이 전략 클래스를 추가하거나 교체하는 것만으로 쉽게 대응할 수 있게 된다.&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;EligibilityStrategyFactory를 통한 동적 전략 주입&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1166&quot; data-start=&quot;1052&quot; data-ke-size=&quot;size16&quot;&gt;쿠폰의 발급 가능 여부를 판단하는 로직은 쿠폰 정책의 발급 빈도(IssuanceFrequency)에 따라 달라지며, 이 로직을 직접 쿠폰 발급 프로세스 내부에서 처리하면 코드가 복잡해지고 변경이 어려워진다.&lt;/p&gt;
&lt;p data-end=&quot;1166&quot; data-start=&quot;1052&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1166&quot; data-start=&quot;1052&quot; data-ke-size=&quot;size16&quot;&gt;이를 효율적으로 해결하기 위해 &lt;b&gt;EligibilityStrategyFactory&lt;/b&gt;를 도입하여 발급 제한 로직을 동적으로 관리한다.&lt;/p&gt;
&lt;p data-end=&quot;1166&quot; data-start=&quot;1052&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;359&quot; data-start=&quot;238&quot; data-ke-size=&quot;size16&quot;&gt;구체적으로 EligibilityStrategyFactory는 정책의 IssuanceFrequency 값을 바탕으로 적절한 발급 제한 전략을 매핑하여 제공하는 역할을 담당한다.&lt;/p&gt;
&lt;p data-end=&quot;359&quot; data-start=&quot;238&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;359&quot; data-start=&quot;238&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;359&quot; data-start=&quot;238&quot; data-ke-size=&quot;size16&quot;&gt;아래처럼 구현해두었다.&lt;/p&gt;
&lt;div style=&quot;background-color: #212121; color: #eeffff;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;@Component
public class EligibilityStrategyFactory {
    private final Map&amp;lt;IssuanceFrequency, EligibilityStrategy&amp;gt; strategyMap = new HashMap&amp;lt;&amp;gt;();

    public EligibilityStrategyFactory(CouponHistoryRepository couponHistoryRepository) {
       strategyMap.put(ONCE_PER_USER, new OncePerUserEligibilityStrategy(couponHistoryRepository));
       strategyMap.put(ONCE_PER_YEAR, new OncePerYearEligibilityStrategy(couponHistoryRepository));
       strategyMap.put(ONCE_PER_EVENT, new OncePerEventEligibilityStrategy(couponHistoryRepository));
    }

    public EligibilityStrategy getStrategy(IssuanceFrequency frequency) {
       return strategyMap.get(frequency);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-end=&quot;359&quot; data-start=&quot;238&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2053&quot; data-start=&quot;1908&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;/b&gt;전략패턴을 도입하면 뭐가 좋을까?&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2053&quot; data-start=&quot;1908&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2053&quot; data-start=&quot;1908&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;OCP(개방-폐쇄 원칙) 준수&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2053&quot; data-start=&quot;1908&quot; data-ke-size=&quot;size16&quot;&gt;새로운 발급 제한 정책을 추가하거나 기존 정책을 변경할 때 CouponProcessor 같은 핵심 로직을 수정하지 않고도 새로운 전략 클래스만 추가하면 되므로 &lt;b&gt;확장성이 높아진다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2053&quot; data-start=&quot;1908&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;유지보수 용이&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2053&quot; data-start=&quot;1908&quot; data-ke-size=&quot;size16&quot;&gt;전략별 클래스에서 로직이 명확히 분리되어 있으므로 특정 조건 변경이나 신규 로직 추가 시 해당 전략만 변경하거나 추가하면 된다.&lt;/p&gt;
&lt;p data-end=&quot;2053&quot; data-start=&quot;1908&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;발급 주기별 전략 구현&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;709&quot; data-end=&quot;780&quot; data-ke-size=&quot;size16&quot;&gt;쿠폰 정책을 생성할 때, IssuanceFrequency를 설정하면 해당 쿠폰이 어떤 빈도로 발급될지를 결정할 수 있다.&lt;/p&gt;
&lt;div style=&quot;color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h3 data-end=&quot;2139&quot; data-start=&quot;2083&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) OncePerUserEligibilityStrategy: 1회 한정 발급&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1741332582308&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class OncePerUserEligibilityStrategy implements EligibilityStrategy {
    private final CouponHistoryRepository couponHistoryRepository;

    public OncePerUserEligibilityStrategy(CouponHistoryRepository couponHistoryRepository) {
        this.couponHistoryRepository = couponHistoryRepository;
    }

    @Override
    public boolean isEligible(Long userId, Long policyId) {
        return !couponHistoryRepository.existsByUserIdAndPolicyId(userId, policyId);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2670&quot; data-start=&quot;2628&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;사용자가 해당 쿠폰을 한 번이라도 받은 적이 있으면 발급 불가&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2675&quot; data-start=&quot;2672&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2735&quot; data-start=&quot;2677&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) OncePerYearEligibilityStrategy: 연 1회 발급 제한&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1741332592188&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class OncePerYearEligibilityStrategy implements EligibilityStrategy {
    private final CouponHistoryRepository couponHistoryRepository;

    public OncePerYearEligibilityStrategy(CouponHistoryRepository couponHistoryRepository) {
        this.couponHistoryRepository = couponHistoryRepository;
    }

    @Override
    public boolean isEligible(Long userId, Long policyId) {
        int currentYear = LocalDate.now().getYear();
        LocalDateTime startOfYear = LocalDate.of(currentYear, 1, 1).atStartOfDay();
        LocalDateTime endOfYear = LocalDate.of(currentYear, 12, 31).atTime(23, 59, 59);

        return !couponHistoryRepository.existsByUserIdAndPolicyIdAndIssuedAtBetween(
            userId, policyId, startOfYear, endOfYear);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3580&quot; data-start=&quot;3505&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;쿠폰이 발급된 연도를 기준으로 발급 가능 여부 체크&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;현재 연도에 한 번도 발급받지 않은 경우에만 쿠폰 지급&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;3585&quot; data-start=&quot;3582&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;3648&quot; data-start=&quot;3587&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(3) OncePerEventEligibilityStrategy: 이벤트 단위 발급 제한&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1741332607395&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class OncePerEventEligibilityStrategy implements EligibilityStrategy {
    private final CouponHistoryRepository couponHistoryRepository;

    public OncePerEventEligibilityStrategy(CouponHistoryRepository couponHistoryRepository) {
        this.couponHistoryRepository = couponHistoryRepository;
    }

    @Override
    public boolean isEligible(Long userId, Long policyId) {
        return !couponHistoryRepository.existsByUserIdAndPolicyId(userId, policyId);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4245&quot; data-start=&quot;4139&quot; data-ke-size=&quot;size16&quot;&gt;✔ 이벤트 단위 발급은 기본적으로 OncePerUserEligibilityStrategy와 유사한 로직을 사용&lt;br /&gt;✔ &lt;b&gt;단, 특정 이벤트 기간을 DB에서 조회해 체크할 수도 있음&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Part 1. CouponProcessor 에서의 전략 적용&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1741335143726&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Dayner에서 이벤트성, 일회성 쿠폰을 발급하고 관리하는 방법 [1]&quot; data-og-description=&quot;개요사실 블로깅할 소재가 쌓여있다.. 인턴하면서 국제화 리팩터링 한 건도 그렇고 알림/메일링 서버도,,,&amp;nbsp; 사업보안인증을 위해서 메인서버 취약점을 고쳤던 소재도 남아있는데,,&amp;nbsp;클라이언트&quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/Dayner%EC%97%90%EC%84%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EC%84%B1-%EC%9D%BC%ED%9A%8C%EC%84%B1-%EC%BF%A0%ED%8F%B0%EC%9D%84-%EB%B0%9C%EA%B8%89%ED%95%98%EA%B3%A0-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-1&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/Dayner%EC%97%90%EC%84%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EC%84%B1-%EC%9D%BC%ED%9A%8C%EC%84%B1-%EC%BF%A0%ED%8F%B0%EC%9D%84-%EB%B0%9C%EA%B8%89%ED%95%98%EA%B3%A0-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-1&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/TSenb/hyYqaosa9K/9Xuz2yC1Xr8T1axElwjf81/img.png?width=800&amp;amp;height=789&amp;amp;face=0_0_800_789,https://scrap.kakaocdn.net/dn/bcsVyF/hyYmJMHihB/sxc79P58wBj0WStNUpaJRk/img.png?width=800&amp;amp;height=789&amp;amp;face=0_0_800_789,https://scrap.kakaocdn.net/dn/Jcm9W/hyYm0Ok13A/GO39DeU92BSelF3MAiqwd0/img.png?width=750&amp;amp;height=739&amp;amp;face=0_0_750_739&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/Dayner%EC%97%90%EC%84%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EC%84%B1-%EC%9D%BC%ED%9A%8C%EC%84%B1-%EC%BF%A0%ED%8F%B0%EC%9D%84-%EB%B0%9C%EA%B8%89%ED%95%98%EA%B3%A0-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/Dayner%EC%97%90%EC%84%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EC%84%B1-%EC%9D%BC%ED%9A%8C%EC%84%B1-%EC%BF%A0%ED%8F%B0%EC%9D%84-%EB%B0%9C%EA%B8%89%ED%95%98%EA%B3%A0-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/TSenb/hyYqaosa9K/9Xuz2yC1Xr8T1axElwjf81/img.png?width=800&amp;amp;height=789&amp;amp;face=0_0_800_789,https://scrap.kakaocdn.net/dn/bcsVyF/hyYmJMHihB/sxc79P58wBj0WStNUpaJRk/img.png?width=800&amp;amp;height=789&amp;amp;face=0_0_800_789,https://scrap.kakaocdn.net/dn/Jcm9W/hyYm0Ok13A/GO39DeU92BSelF3MAiqwd0/img.png?width=750&amp;amp;height=739&amp;amp;face=0_0_750_739');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Dayner에서 이벤트성, 일회성 쿠폰을 발급하고 관리하는 방법 [1]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요사실 블로깅할 소재가 쌓여있다.. 인턴하면서 국제화 리팩터링 한 건도 그렇고 알림/메일링 서버도,,,&amp;nbsp; 사업보안인증을 위해서 메인서버 취약점을 고쳤던 소재도 남아있는데,,&amp;nbsp;클라이언트&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;생일 축하 쿠폰을 발급하는 과정을 예시로 들어보자&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;쿠폰 발급 전략을 보다 실질적으로 이해하기 위해, 매달 자동으로 발급되는 생일 축하 쿠폰 배치 작업의 예시를 살펴보자.&lt;/p&gt;
&lt;p data-end=&quot;168&quot; data-start=&quot;94&quot; data-ke-size=&quot;size16&quot;&gt;아래는 Spring의 @Scheduled 어노테이션을 활용하여 매달 정기적으로 생일 쿠폰을 발급하는 작업을 구현한 예시 코드이다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1741335434868&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
@RequiredArgsConstructor
public class ScheduledTasks {
    private final UserFacade userFacade;
    private final CouponProcessor couponProcessor;
    private final CacheManager cacheManager;

    // 매달 1일 새벽 1시에 생일 쿠폰 발급 배치 실행
    @Scheduled(cron = &quot;0 0 1 1 * *&quot;)
    public void issueMonthlyBirthdayCoupon() {
        userFacade.issueBirthdayCoupon();
    }
}

// UserFacade 내부 메서드
public void issueBirthdayCoupon() {
    int currentMonth = LocalDate.now().getMonthValue();
    
    // 생일이 해당 월에 속한 사용자 조회 및 발급 처리
    List&amp;lt;Long&amp;gt; userIdsWithBirthday = userRepository.findUserIdsByBirthdayMonth(currentMonth);
    userIdsWithBirthday.forEach(userId -&amp;gt;
        couponProcessor.processCouponIssuance(userId, PolicyType.BIRTHDAY_COUPON, 3)
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1098&quot; data-start=&quot;940&quot; data-ke-size=&quot;size16&quot;&gt;위의 코드와 같이 매달 지정된 날짜와 시간에 배치 작업을 실행하여 지금까지 구현하였던 Processor에 BIRTHDAY 타입과 함께 생일 쿠폰을 자동 발급하는 로직을 간단히 구현할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1098&quot; data-start=&quot;940&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1098&quot; data-start=&quot;940&quot; data-ke-size=&quot;size16&quot;&gt;이 방식을 활용하면 시스템 관리자는 복잡한 수동 작업 없이 정해진 기간에 정확히 쿠폰을 발급할 수 있으며, 동시에 시스템의 유지보수성과 효율성 또한 향상된다.&lt;/p&gt;
&lt;p data-end=&quot;1098&quot; data-start=&quot;940&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;1170&quot; data-start=&quot;1100&quot; 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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;마무리&lt;/span&gt;&lt;/h3&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;IssuanceFrequency&lt;/b&gt;와 &lt;b&gt;EligibilityStrategy&lt;/b&gt;를 도입하여 전략 패턴을 활용한 구조 개선을 다뤘다. 또한, 쿠폰 정책의 명확한 분류와 관리를 위해 PolicyType을 활용했고, 실질적인 예로 생일 쿠폰의 배치 작업을 살펴보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;222&quot; data-start=&quot;198&quot; data-ke-size=&quot;size16&quot;&gt;이를 통해 얻은 주요 개선점은 다음과 같다.&lt;/p&gt;
&lt;p data-end=&quot;239&quot; data-start=&quot;224&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;명확한 책임 분리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;328&quot; data-start=&quot;240&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;328&quot; data-start=&quot;240&quot;&gt;쿠폰 정책(PolicyType)과 발급 빈도(IssuanceFrequency), 그리고 전략(EligibilityStrategy)의 책임을 명확히 구분함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;352&quot; data-start=&quot;330&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;OCP(개방-폐쇄 원칙) 준수&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;413&quot; data-start=&quot;353&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;413&quot; data-start=&quot;353&quot;&gt;새로운 쿠폰 발급 제한 조건이 추가되더라도 기존 코드를 수정하지 않고 전략 클래스만 추가하면 확장 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;관리 편의성 향상&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;476&quot; data-start=&quot;431&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;476&quot; data-start=&quot;431&quot;&gt;정책과 발급 전략을 명확히 나눠 관리함으로써, 유지보수와 운영 효율성을 높임.&lt;/li&gt;
&lt;li data-end=&quot;476&quot; data-start=&quot;431&quot;&gt;실제로&lt;span style=&quot;background-color: #f6e199;&quot;&gt; 해당 클라이언트의 요청으로 부터 변경사항 적용-배포까지의 과정이 10분이 채 걸리지 않았다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot;&gt;데이터 중심 애플리케이션 설계 - 마틴 클레프만&lt;u&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot;&gt;자바/스프링 개발자를 위한 실용주의 프로그래밍 - 김우근&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot;&gt;내 머리속 내공냠냠&lt;/span&gt;&lt;/p&gt;</description>
      <category>Dayner 프로젝트</category>
      <category>리팩터링</category>
      <category>멀티 서비스레이어</category>
      <category>의존성 주입</category>
      <category>전략패턴</category>
      <category>쿠폰 발급 전략</category>
      <category>팩토리패턴</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/241</guid>
      <comments>https://nstgic3.tistory.com/entry/Dayner%EC%97%90%EC%84%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EC%84%B1-%EC%9D%BC%ED%9A%8C%EC%84%B1-%EC%BF%A0%ED%8F%B0%EC%9D%84-%EB%B0%9C%EA%B8%89%ED%95%98%EA%B3%A0-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-2#entry241comment</comments>
      <pubDate>Fri, 7 Mar 2025 17:56:24 +0900</pubDate>
    </item>
    <item>
      <title>Dayner에서 이벤트성, 일회성 쿠폰을 발급하고 관리하는 방법 [1]</title>
      <link>https://nstgic3.tistory.com/entry/Dayner%EC%97%90%EC%84%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EC%84%B1-%EC%9D%BC%ED%9A%8C%EC%84%B1-%EC%BF%A0%ED%8F%B0%EC%9D%84-%EB%B0%9C%EA%B8%89%ED%95%98%EA%B3%A0-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-1</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사실 블로깅할 소재가 쌓여있다.. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;인턴하면서 국제화 리팩터링 한 건도 그렇고 알림/메일링 서버도,,,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 사업보안인증을 위해서 메인서버 취약점을 고쳤던 소재도 남아있는데,,&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;클라이언트께서 신학기 맞이 이벤트를 준비하시면서 첫회원가입시에 발급하는 쿠폰 옵션 변경 요청이 들어왔는데 나름 유연하게 리팩터링 해놨던 터라 무려 10분도 안되어서 대응을 완료했기 때문에 겸사겸사 작성을 해본다.&lt;/span&gt;&lt;/span&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;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;실제 운영을 하면서 개발자로서 가장 고민되는 부분은, 클라이언트의 갑작스러운 요청사항에 얼마나 빠르고 효율적으로 대응할 수 있는가이다.&lt;/span&gt;&lt;/span&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;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최근 클라이언트로부터 '신학기 맞이 이벤트'를 위한 쿠폰 옵션 변경 요청을 받았다.&lt;/span&gt;&lt;/span&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;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다행히도 이전에 쿠폰 발급 전략을 기간별, 이벤트별, 회원별로 유연하게 관리할 수 있도록 설계해둔 덕분에, 단 10분 이내에 요청 사항을 처리할 수 있었다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;본 글에서는 실제 클라이언트의 요구 사항을 사례로 들어, 하드코딩 방식의 한계점과 상태관리 및 쿠폰 발급 전략이 왜 중요한지, 그리고 어떻게 설계하면 다양한 상황에 유연하게 대응할 수 있는지 분석하고자 한다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한 앞으로 소개할 쿠폰 관리 전략에서는 회원가입 축하 쿠폰뿐만 아니라 생일 쿠폰 등 정기적 또는 일회성 쿠폰들의 효율적인 발급 및 관리 방안까지 다룰 예정이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;요청 사항 분석과 내 생각&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;대부분 클라이언트 요청은 예상을 벗어난다. &lt;/span&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;span&gt;실제 요구는 예측하기 어렵고, 때로는 합의된 요구 사항 이상의 기능을 요청하는 경우도 흔히 발생한다. &lt;/span&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;span&gt;클라이언트는 자신의 사업이 요구하는 비즈니스 흐름을 명확히 이해하고 있기에, 이를 온전히 기술적으로 구현하기 위해선 개발자 역시 해당 비즈니스에 대한 깊은 이해가 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;br /&gt;아래는 실제로 클라이언트와의 대화내용이다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;1586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRMkrl/btsMDhANDUj/A2xSkeI6mKQooYWLaFaT41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRMkrl/btsMDhANDUj/A2xSkeI6mKQooYWLaFaT41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRMkrl/btsMDhANDUj/A2xSkeI6mKQooYWLaFaT41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRMkrl%2FbtsMDhANDUj%2FA2xSkeI6mKQooYWLaFaT41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;324&quot; height=&quot;676&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;1586&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-pm-slice=&quot;3 3 []&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;신규 가입 회원 및 기존 회원을 위한 일회성 쿠폰 발급&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;발급 기간과 사용 기한이 명확히 정해져 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;기존의 웰컴 쿠폰은 일시 중단&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;쿠폰 사용 조건이 기존과 다름 (모든 음료 및 디저트 중 하나를 50% 할인)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span&gt;만약 쿠폰 발급 로직을 하드코딩 방식으로 작성했다면, 클라이언트의 이번 요청을 해결하기 위한 개발자의 선택지는 극히 제한적이다.&lt;/span&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;span&gt;예를 들어:&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;기존 쿠폰 로직을 즉시 변경하고, 이벤트 기간이 끝나면 원상복구하거나,&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;쿠폰의 유효기간이 기존에 고정값으로 설정되어 있다면, 이벤트 기간을 임시로 코드에 직접 삽입하는 등 임시방편적 작업을 해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;추가로 클라이언트가 '발급된 모든 가입 쿠폰을 종류별로 한눈에 관리'하고 싶다고 했을 때도 역시 비슷한 문제가 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결국, 쿠폰에 추가 상태 필드를 급히 넣거나 새로운 타입 구분자를 만들어 대응할 수밖에 없다.&lt;/span&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;span&gt;생일 쿠폰 역시 마찬가지다.&lt;/span&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;span&gt;회원별로 매달 정기적으로 발급되며, 이를 배치작업으로 처리해야 한다면? 일회성 쿠폰과 정기적 쿠폰의 관리 방식은 어떻게 다르게 접근해야 할까?&lt;/span&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;span&gt;이외에도 다음과 같은 다양한 상황을 미리 고려해 설계해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;쿠폰의 유효기간이 회원가입일이 아니라 특정 이벤트 날짜에 따라 정해질 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;쿠폰의 발급 및 중단 기간이 빈번하게 변경되는 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;발급된 쿠폰을 별도의 조건(회원 등급, 과거 구매 내역)에 따라 분류해 관리하고자 하는 경우&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;본 글에서는 이러한 현실적 문제를 깊게 고민한 결과로, 다양한 쿠폰 전략과 상태 관리를 활용하여 유연하고 신속한 대응 방식을 제안하고자 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;기존 구조, 그리고 쿠폰 발급 전략의 도입&lt;/span&gt;&lt;/h3&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;기존의 구조 및 문제점&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;초기 시스템에서는 기프티콘과 같은 단순 쿠폰만 지원하였으나, 회원가입 축하, 생일 축하(배치 처리), 이벤트 쿠폰과 같은 다양한 요구사항이 추가됨에 따라 서비스 로직이 점점 복잡해졌다.&lt;/span&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;span&gt;초기에는 각 기능을 별도의 서비스 코드로 만들어 회원가입이나 이벤트 로직 내부에서 직접 호출하는 방식을 취했고, 이로 인해 도메인이 혼잡해지기 시작했다.&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;이벤트의 경우에도 부랴부랴 당시 참여했던 이벤트이름을 가진 도메인을 만들고 구현에 급급했었다.&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;하지만 여러 기능을 만들다보기 기능의 속성들에 대해서 고찰하기 시작했고 이는 정책 도메인으로의 성숙에 이르렀다.&lt;/span&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;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;CouponService&lt;br /&gt;├── CouponRepository (쿠폰 저장)&lt;br /&gt;├── CouponHistoryRepository (기록 조회)&lt;br /&gt;├── 쿠폰 발급 조건 검증 (직접 처리)&amp;nbsp;&lt;br /&gt;├── 정책별 발급 방식 분기 (하드 코딩)&lt;br /&gt;├── DB에서 중복 체크 (서비스단에서 직접 처리)&lt;/blockquote&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;span&gt;이 방식은 쿠폰 발급 조건이 다양해지면서 유지보수가 어렵고 코드의 복잡도가 증가하는 문제를 야기했다.&lt;/span&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;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;쿠폰 발급 전략과 정책 도입&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;위와 같은 문제를 해결하기 위해 정책(Policy) 도메인을 도입했다.&lt;/span&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;span&gt;쿠폰의 특성을 분석하여 불변 속성(쿠폰 이미지, 설명, 발급자 등)과 가변 속성(사용정보, 유효기간 등)을 분리하여 각각 별도의 클래스로 관리했다.&lt;/span&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;span&gt;금융 자산과 유사한 쿠폰의 특성상 불변성과 가변성을 명확히 구분하는 것이 중요했기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;정책과 속성의 명확한 구분&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;정책은 아래와 같은 명확한 속성들로 정의되었다:&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #212121; color: #eeffff;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class CouponPolicy {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Enumerated(EnumType.STRING)
    private PolicyType policyType;

    private String policyName;

    @Embedded
    private CouponAttribute couponAttribute;

    @Enumerated(EnumType.STRING)
    private IssuanceFrequency issuanceFrequency;
    
    @JsonProperty(&quot;isActive&quot;)
    private boolean isActive;

    private int stock;
    
    private Long expiryDurationInSeconds;
    
 }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;span style=&quot;color: #000000;&quot;&gt;겸사겸사 Policy 로 인해 변하지 않는(불변) 속성은 따로 쿠폰 속성이라고 따로 클래스를 만들어 주었다.&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;금융자산의 특성을 가지기 때문에 불변인 속성과 그렇지 않은 속성간의 바운더리 또한 필요함을 느꼈었다.&lt;/span&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;span&gt;불변 속성은 CouponAttribute로 따로 관리했다:&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #212121; color: #eeffff;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Embeddable
@Getter
public class CouponAttribute {
    private String imageUrl;
    private String description;
    @Column(nullable = false)
    private Long giverId;
    private String giverInfo;
    private boolean isPrepaid;
    private int maxUsageAmount;
    private LocalDateTime expiryDate;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&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;span&gt;쿠폰 엔티티도 구조가 명확해졌다:&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #212121; color: #eeffff;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Coupon extends BaseEntity {
    @Id
    @GeneratedValue(generator = &quot;uuid2&quot;)
    @Column(nullable = false)
    private UUID id;
    @Column(nullable = false)
    private String couponNumber;

    @Column
    private Long receiverId;

    @Column
    private Long policyId;

    @Embedded
    private CouponAttribute couponAttribute;

    @Embedded
    private CouponUsageInfo couponUsageInfo;
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;span style=&quot;color: #000000;&quot;&gt;당연하지만 CouponUsageInfo 는 변할수 있는 객체들을 묶어두었다.&lt;/span&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;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;CouponService&lt;br /&gt;├── CouponRepository (쿠폰 저장)&lt;br /&gt;├── CouponPolicyRepository (정책 조회)&lt;br /&gt;├── CouponHistoryRepository (기록 조회)&lt;br /&gt;├── 쿠폰 발급 조건 검증 (직접 처리) ❌&lt;br /&gt;├── 정책별 발급 방식 분기 ❌&lt;br /&gt;├── DB에서 중복 체크 ❌&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&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;span style=&quot;color: #000000; font-size: 1.62em; letter-spacing: -1px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;책임 분리의 성과&lt;/span&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;span&gt;정책과 속성을 명확히 구분한 결과 다음과 같은 책임 분리가 가능해졌다&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;CouponPolicy&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: 쿠폰 발급 조건 및 전략 관리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;CouponAttribute&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: 쿠폰의 불변 속성 관리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;CouponProcessor&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: 쿠폰 발급 프로세스 관리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;EligibilityStrategy&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: 쿠폰 발급 가능 여부 판단&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;현재 서비스 레이어의 한계와 미해결 과제&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서비스 레이어를 명확히 구분했지만, 서비스 계층의 구조는 여전히 단일 클래스에 많은 책임이 집중되는 문제가 존재했다&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;서비스단은 어떨까? 대강 코드를 보면(실제로는 더 비대하다)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1741312239126&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class CouponService {
    private final CouponRepository couponRepository;
    private final CouponPolicyRepository couponPolicyRepository;

    public void issueCoupon(Long userId, PolicyType policyType) {
        CouponPolicy policy = couponPolicyRepository.findByPolicyTypeAndIsActive(policyType, true)
            .orElseThrow(() -&amp;gt; new NoSuchElementException(&quot;정책 없음&quot;));

        // 발급 가능 여부 확인 (여기서 DB 조회 포함)
        if (couponRepository.existsByUserIdAndPolicyId(userId, policy.getId())) {
            throw new IllegalArgumentException(&quot;이미 발급됨&quot;);
        }

        // 쿠폰 생성 후 저장
        Coupon coupon = new Coupon(userId, policy);
        couponRepository.save(coupon);
    }
}&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;&lt;span style=&quot;color: #000000;&quot;&gt;구조는 직관적이지만, &lt;b&gt;클래스 하나가 너무 많은 역할을 담당&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;2491&quot; data-end=&quot;2516&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;그럼에도 아직 해결되지 않은 문제&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1550&quot; data-start=&quot;1122&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1272&quot; data-start=&quot;1122&quot;&gt;&lt;b&gt;단일 책임 원칙(SRP) 위반&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1272&quot; data-start=&quot;1151&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1215&quot; data-start=&quot;1151&quot;&gt;쿠폰 발급 조건 검사는 &lt;b&gt;발급 정책(Policy)의 역할&lt;/b&gt;이지만 CouponService가 담당한다.&lt;/li&gt;
&lt;li data-end=&quot;1272&quot; data-start=&quot;1219&quot;&gt;만약 정책이 복잡해지면 CouponService는 거대해지고, 유지보수도 어려워진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1417&quot; data-start=&quot;1274&quot;&gt;&lt;b&gt;테스트가 어려움&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1417&quot; data-start=&quot;1295&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1417&quot; data-start=&quot;1295&quot;&gt;CouponService는 CouponRepository, CouponPolicyRepository 등을 직접 사용하므로,&lt;br /&gt;&lt;b&gt;단위 테스트가 어렵고, DB 종속적인 테스트가 필요&lt;/b&gt;해진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1550&quot; data-start=&quot;1419&quot;&gt;&lt;b&gt;유연성이 부족&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1550&quot; data-start=&quot;1439&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1501&quot; data-start=&quot;1439&quot;&gt;정책 추가(예: 특정 VIP 회원만 발급 가능, 이번 요청 사항등,,)를 하려면 issueCoupon을 직접 수정해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;1550&quot; data-start=&quot;1505&quot;&gt;기존 코드 수정이 필요하므로, &lt;b&gt;OCP(개방-폐쇄 원칙)를 위반&lt;/b&gt;한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&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;span&gt;결론적으로, 앞으로는 정책과 검증 로직을 완전히 서비스 레이어에서 분리하고, 전략 패턴과 인터페이스를 적극적으로 활용하여 쿠폰 발급과 관련된 유연성을 극대화하는 방향으로 구조를 더욱 발전시킬 필요가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;서비스 레이어의 분리에 대한 고민&lt;/span&gt;&lt;/h3&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;서비스 레이어 분리의 필요성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서비스 레이어(Service Layer)의 분리는 애플리케이션 구조를 명확하게 만들고 유지보수성과 확장성을 높이기 위한 중요한 설계 원칙이다.&lt;/span&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;span&gt; 하지만 현실적으로는 메서드가 몇 개 없더라도 무조건적으로 인터페이스와 구현체를 나누는 사례가 빈번히 발생한다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;나 역시 초기에 그 필요성을 명확히 인지하지 못해 불편함을 느낀 이후에야 레이어 분리의 중요성을 깨닫게 되었다. &lt;s&gt;(미리 할걸,,)&lt;/s&gt;&lt;/span&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;span&gt;위에서도 봤다싶이 현재의 쿠폰 관리 서비스 구조를 분석해보면 명확히 서비스 레이어 분리가 요구된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다양한 유즈케이스와 도메인이 뒤섞여 코드의 책임과 목적이 불분명해졌기 때문이다.&lt;/span&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;span&gt;실제로 쿠폰 관련 단순 CRUD 작업부터, 사용자와의 도메인 연관성, 발급 여부 검증(Validation), 쿠폰 사용 이력 관리, 금융 거래로 인한 원장 기록 등 수많은 의존성이 복잡하게 얽혀 있었다. omg,,&lt;/span&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;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;서비스 레이어 분리를 위한 접근법&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서비스 레이어를 명확히 나누기 위해 다음과 같은 기준으로 분석 및 분리를 시도했다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;책임 주체와 도메인 구분&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;행위의 명확한 정의&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;객체의 생애주기와 목적&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이처럼&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000; text-align: start;&quot;&gt;여러가지 기준을 통해서 레이어를 바라보았다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;지금 위의 구조를 보면 확실하게 상위 서비스레이어의 분리가 필요함이 느껴진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;1. CRUD 중심의 기본 서비스 레이어&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가장 기본적인 CRUD 작업은 서비스 레이어의 핵심이자 기본이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 작업은 복잡하지 않지만, 반드시 독립적으로 관리되어야 한다고 생각한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000; text-align: start;&quot;&gt;이건 가장 근본에 가깝다고 생각하기에, 현재 존재하는 서비스 코드인 CouponService 에 남겨두려했다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000; text-align: start;&quot;&gt;혹은 CouponCRUDService 라고 단순하게 네이밍 해도 좋겠다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;2. 정책과 전략 중심의 서비스 레이어&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;정책과 관련된 기능은 별도의 레이어로 명확히 분리했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서의 핵심 포인트는 쿠폰 정책을 이벤트 기반, 회원 기반, 일반 쿠폰 등 다양한 조건에 따라 분류하여 독립적으로 관리하는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 효과적으로 관리하기 위해 팩토리 패턴과 전략 패턴을 조합하여 유연한 구조를 구축했다.&lt;/span&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;span&gt;이를 통해 각 쿠폰 정책의 유효성 검증 및 유효기간 처리 등을 명확하게 관리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;3. 행위 중심의 서비스 레이어&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;쿠폰의 주요 행위는 크게 &amp;lsquo;발급&amp;rsquo;과 &amp;lsquo;사용&amp;rsquo;으로 나뉜다.&lt;/span&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;span&gt;&amp;lsquo;사용&amp;rsquo;은 상대적으로 명확하지만, 실제로는 유효기간 관리, 회원 등급별 조건 처리, 무효화 처리 등 복합적인 로직이 존재한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;lsquo;발급&amp;rsquo; 또한 앞서 설명한 전략 기반의 정책을 적용하여 보다 복잡한 로직이 존재한다.&lt;/span&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;span&gt;따라서 쿠폰의 사용과 발급 행위를 각각 명확하게 정의하고, 이를 별도의 서비스로 분리하여 관리하는 것이 효율적이다.&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;발급 전략 분리와 레이어 분리 적용&lt;/span&gt;&lt;/h3&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;span&gt;쿠폰 발급 로직의 복잡성과 책임의 명확한 분리를 위해 전략 패턴을 적용하고 서비스 레이어를 분리하였다. 특히, 기존의 직접적인 검증 방식에서 벗어나, 명확한 책임 분리를 통해 쿠폰 발급 프로세스를 단순화하고 유지보수성을 높였다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;CouponProcessor 구조 개선&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;CouponProcessor는 다음과 같은 흐름으로 쿠폰 발급 프로세스를 관리하도록 구조화되었다&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1741312353365&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
@RequiredArgsConstructor
public class CouponProcessor {
    private final CouponPolicyRepository couponPolicyRepository;
    private final EligibilityStrategyFactory eligibilityStrategyFactory;

    @Transactional
	public void processCouponIssuance(Long userId, PolicyType policyType, int maxRetries) {
		CouponPolicy policy = couponPolicyRepository.findByPolicyTypeAndIsActive(policyType, true)
			.orElseThrow(() -&amp;gt; new NoSuchElementException(ErrorMessage.POLICY_NOT_FOUND));

		EligibilityStrategy strategy = eligibilityStrategyFactory.getStrategy(policy.getIssuanceFrequency());

		if (!strategy.isEligible(userId, policy.getId())) {
			throw new IllegalArgumentException(ErrorMessage.NOT_ELIGIBLE);
		}

		int retryCount = 0;
		while (retryCount &amp;lt;= maxRetries) {
			// 재고 감소 및 정책 저장에 대한 예외 처리
			try {
				CouponPolicy couponPolicy = couponPolicyRepository.findById(policy.getId())
					.orElseThrow(() -&amp;gt; new NoSuchElementException(&quot;Policy not found&quot;));

				couponPolicy.decrementStock(); // 재고 감소
				couponPolicyRepository.save(couponPolicy); // 재고 감소 저장 (낙관적 락 적용)

				// 유니크한 카드 번호를 생성하거나,
                // 쿠폰 생성에 따른 개인정보보호법을 따르기 위해 발급 내역을 저장하거나(이건 나중에 메시지큐나 비동기로 빼도 좋을듯하다.)
				completeCouponIssuance(userId, couponPolicy);
				break;
				
			} catch (OptimisticLockException e) {
				retryCount++;
				if (retryCount &amp;gt; maxRetries) {
					throw new RuntimeException(ErrorMessage.CONCURRENT_UPDATE);
				}
			}
		}
	}
}&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;물론 완벽한 객체지향은 아니다. 메서드 내부에 흐름이 존재하고 누군가는 함수형 프로그래밍이라고 이야기 할수도 있다. (&lt;s&gt;또 불편함을 겪으면 다시 변경하지 않을까?&lt;/s&gt;)&amp;nbsp;&lt;/span&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;span&gt;이 구조는 기존에 쿠폰 서비스가 직접 검증을 처리하던 방식에서 벗어나, &lt;b&gt;EligibilityStrategyFactory가 적절한 발급 전략을 반환&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;하고&amp;nbsp;전략별 클래스에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;발급 조건을 분리하여 개별 처리&lt;/b&gt;하여 책임을&amp;nbsp; 분산하였다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;책임 분리 및 얻은 이점&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;책임 분리 (SRP 적용)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-start=&quot;2540&quot; data-end=&quot;2576&quot;&gt;CouponProcessor는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;쿠폰 발급만 담당&lt;/b&gt;&lt;/li&gt;
&lt;li data-start=&quot;2577&quot; data-end=&quot;2629&quot;&gt;&lt;b&gt;발급 조건 검사는 EligibilityStrategy에 위임&lt;/b&gt;하여 역할을 분리&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;테스트 용이성 증가&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-start=&quot;2650&quot; data-end=&quot;2714&quot;&gt;CouponProcessor는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;EligibilityStrategyFactory를 주입받아 사용&lt;/b&gt;&lt;/li&gt;
&lt;li data-start=&quot;2715&quot; data-end=&quot;2745&quot;&gt;&lt;b&gt;발급 정책과 관계없이 개별 테스트가 가능&lt;/b&gt;&lt;/li&gt;
&lt;li data-start=&quot;2746&quot; data-end=&quot;2773&quot;&gt;Mock을 활용한 단위 테스트가 가능함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;확장성 증가 (OCP 적용)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-start=&quot;2799&quot; data-end=&quot;2871&quot;&gt;새로운 발급 정책을 추가할 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;기존 코드 수정 없이 새로운 EligibilityStrategy를 추가&lt;/b&gt;하면 된다.&lt;/li&gt;
&lt;li data-start=&quot;2872&quot; data-end=&quot;2919&quot;&gt;Strategy 패턴을 활용하여&lt;span&gt;&amp;nbsp;&lt;/span&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: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 구조가 상당히 개선되었으나 여전히 추가로 다룰 만한 주제들이 존재한다.&lt;/span&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;span&gt;생일 쿠폰과 같이 주기적으로 발급이 필요한 경우 배치(batch) 처리를 통해 별도의 주기적 프로세스를 구성할 필요가 있으며, 이벤트 쿠폰과 같이 순간적으로 높은 트래픽이 몰릴 때는 락(lock)을 이용한 동시성 처리 메커니즘 도입이 필요하다.&lt;/span&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;span&gt;다음 글에서는 정책을 나눈 기준과, 각각의 정책이 적용된 예시, 배치 및 락을 활용한 발급 방식에 대해 보다 심도 있게 다뤄볼 예정이다.&lt;/span&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;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot;&gt;데이터 중심 애플리케이션 설계 - 마틴 클레프만&lt;u&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot;&gt;자바/스프링 개발자를 위한 실용주의 프로그래밍 - 김우근&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: left;&quot;&gt;내 머리속 내공냠냠&lt;/span&gt;&lt;/p&gt;</description>
      <category>Dayner 프로젝트</category>
      <category>리팩터링</category>
      <category>멀티 서비스레이어</category>
      <category>의존성 주입</category>
      <category>전략패턴</category>
      <category>쿠폰 발급 전략</category>
      <category>팩토리패턴</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/240</guid>
      <comments>https://nstgic3.tistory.com/entry/Dayner%EC%97%90%EC%84%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EC%84%B1-%EC%9D%BC%ED%9A%8C%EC%84%B1-%EC%BF%A0%ED%8F%B0%EC%9D%84-%EB%B0%9C%EA%B8%89%ED%95%98%EA%B3%A0-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-1#entry240comment</comments>
      <pubDate>Fri, 7 Mar 2025 15:27:46 +0900</pubDate>
    </item>
    <item>
      <title>조건문 없이 깔끔하게, 자바 비트마스킹으로 문제 해결하는 법 (사용 유형 정리)</title>
      <link>https://nstgic3.tistory.com/entry/%EC%A1%B0%EA%B1%B4%EB%AC%B8-%EC%97%86%EC%9D%B4-%EA%B9%94%EB%81%94%ED%95%98%EA%B2%8C-%EC%9E%90%EB%B0%94-%EB%B9%84%ED%8A%B8%EB%A7%88%EC%8A%A4%ED%82%B9%EC%9C%BC%EB%A1%9C-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0%ED%95%98%EB%8A%94-%EB%B2%95-%EC%82%AC%EC%9A%A9-%EC%9C%A0%ED%98%95-%EC%A0%95%EB%A6%AC</link>
      <description>&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;비트마스킹 기본 연산&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1 특정 비트 확인 (Check)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boolean isSet = (mask &amp;amp; (1 &amp;lt;&amp;lt; i)) != 0;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;`1 &amp;lt;&amp;lt; i`는 1을 i만큼 왼쪽으로 이동해 i번째 비트를 의미한다.&lt;/li&gt;
&lt;li&gt;`&amp;amp;` 연산을 통해 i번째 비트가 1인지 0인지 확인 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2 특정 비트 세팅 (Set)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mask |= (1 &amp;lt;&amp;lt; i);&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;i번째 비트를 1로 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3 특정 비트 해제 (Clear)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mask &amp;amp;= ~(1 &amp;lt;&amp;lt; i);&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;i번째 비트를 0으로 만든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.4 특정 비트 뒤집기 (Toggle)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mask ^= (1 &amp;lt;&amp;lt; i);&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;i번째 비트를 1이면 0, 0이면 1로 바꾼다.&lt;/li&gt;
&lt;/ul&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;/2 대신 &amp;gt;&amp;gt; 1, *2 대신 &amp;lt;&amp;lt; 1&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;`/2` 연산은 `&amp;gt;&amp;gt; 1`로 대체 가능&lt;/li&gt;
&lt;li&gt;`*2` 연산은 `&amp;lt;&amp;lt; 1`로 대체 가능&lt;/li&gt;
&lt;li&gt;컴파일러가 대부분 최적화하므로 큰 체감은 없을 수 있으나, 간단한 비트 연산을 직접 사용하면 의도를 더 명확히 드러낼 수 있음.&lt;/li&gt;
&lt;/ul&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;방문 배열(visited) 대체&lt;/h3&gt;
&lt;h3 data-end=&quot;167&quot; data-start=&quot;161&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-end=&quot;167&quot; data-start=&quot;161&quot; data-ke-size=&quot;size23&quot;&gt;개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;376&quot; data-start=&quot;168&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;219&quot; data-start=&quot;168&quot;&gt;기존에는 boolean[] visited를 사용해 특정 노드가 방문되었는지 추적한다.&lt;/li&gt;
&lt;li data-end=&quot;268&quot; data-start=&quot;220&quot;&gt;N이 15 이하라면 int visitedMask로 방문 상태를 표현할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;321&quot; data-start=&quot;269&quot;&gt;i번째 노드를 방문하면 visitedMask |= (1 &amp;lt;&amp;lt; i)로 1비트를 설정한다.&lt;/li&gt;
&lt;li data-end=&quot;376&quot; data-start=&quot;322&quot;&gt;이후 (visitedMask &amp;amp; (1 &amp;lt;&amp;lt; i)) == 0이면 아직 방문하지 않은 상태다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1741065180101&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void dfs(int current, int visitedMask) {
    // 현재 노드를 방문 표시
    visitedMask |= (1 &amp;lt;&amp;lt; current);

    // 다음 노드들 탐색
    for (int next = 0; next &amp;lt; N; next++) {
        // 방문 여부 확인
        if ((visitedMask &amp;amp; (1 &amp;lt;&amp;lt; next)) == 0) {
            dfs(next, visitedMask);
        }
    }
}&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 data-end=&quot;719&quot; data-start=&quot;680&quot;&gt;visitedMask 하나로 모든 노드의 방문 상태를 관리한다.&lt;/li&gt;
&lt;li data-end=&quot;762&quot; data-start=&quot;720&quot;&gt;재귀호출 시 새로운 visitedMask값으로 다음 노드를 방문한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;775&quot; data-start=&quot;764&quot; data-ke-size=&quot;size23&quot;&gt;성능과 단순성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;887&quot; data-start=&quot;776&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;821&quot; data-start=&quot;776&quot;&gt;메모리: N이 작을 때 비트로 방문 상태를 저장하면 배열보다 공간을 절약한다.&lt;/li&gt;
&lt;li data-end=&quot;844&quot; data-start=&quot;822&quot;&gt;연산: 비트 연산은 빠르고 간단하다.&lt;/li&gt;
&lt;li data-end=&quot;887&quot; data-start=&quot;845&quot;&gt;가독성: 작은 N 범위에서는 비트마스킹이 더 간결하고 직관적일 수 있다.&lt;/li&gt;
&lt;/ul&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;모든 부분집합 순회하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;920&quot; data-start=&quot;914&quot; data-ke-size=&quot;size23&quot;&gt;개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1059&quot; data-start=&quot;921&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;976&quot; data-start=&quot;921&quot;&gt;어떤 집합의 부분집합을 모두 방문하고 싶을 때, 비트마스킹을 이용하면 효율적으로 순회 가능하다.&lt;/li&gt;
&lt;li data-end=&quot;1059&quot; data-start=&quot;977&quot;&gt;예를 들어, mask = (1 &amp;lt;&amp;lt; N) - 1은 0부터 N-1까지 비트가 전부 1인 상태(즉, 모든 원소를 포함하는 부분집합)를 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1741065210427&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int mask = (1 &amp;lt;&amp;lt; N) - 1;
for (int subset = mask; subset &amp;gt; 0; subset = (subset - 1) &amp;amp; mask) {
    // subset은 mask의 부분집합 중 하나
    // 필요한 로직 처리
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1327&quot; data-start=&quot;1226&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1285&quot; data-start=&quot;1226&quot;&gt;(subset - 1) &amp;amp; mask는 subset 바로 이전 부분집합을 추출하는 핵심 기법이다.&lt;/li&gt;
&lt;li data-end=&quot;1327&quot; data-start=&quot;1286&quot;&gt;공집합까지 포함하려면 subset &amp;gt;= 0 조건으로 변경하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1340&quot; data-start=&quot;1329&quot; data-ke-size=&quot;size23&quot;&gt;성능과 단순성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1427&quot; data-start=&quot;1341&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1387&quot; data-start=&quot;1341&quot;&gt;부분집합의 개수는 2^N개이며, 위 기법은 해당 부분집합들을 빠짐없이 순회한다.&lt;/li&gt;
&lt;li data-end=&quot;1427&quot; data-start=&quot;1388&quot;&gt;부분집합을 직접 만들기보다 비트마스크로 표현하면 구현이 단순해진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;조합(Combination) 생성하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1468&quot; data-start=&quot;1462&quot; data-ke-size=&quot;size23&quot;&gt;개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1559&quot; data-start=&quot;1469&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1526&quot; data-start=&quot;1469&quot;&gt;N개 중 어떤 원소를 고를지 비트(0 또는 1)로 표현하면 모든 조합을 손쉽게 열거할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;1559&quot; data-start=&quot;1527&quot;&gt;0번째 비트가 1이면 0번째 원소를 포함한다는 뜻이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1741065522859&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int N = 4;
for (int bit = 0; bit &amp;lt; (1 &amp;lt;&amp;lt; N); bit++) {
    List&amp;lt;Integer&amp;gt; subset = new ArrayList&amp;lt;&amp;gt;();
    for (int i = 0; i &amp;lt; N; i++) {
        if ((bit &amp;amp; (1 &amp;lt;&amp;lt; i)) != 0) {
            subset.add(i);
        }
    }
    System.out.println(subset);
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1916&quot; data-start=&quot;1831&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1880&quot; data-start=&quot;1831&quot;&gt;bit가 0일 때는 공집합, (1 &amp;lt;&amp;lt; N) - 1일 때는 전체 집합이 된다.&lt;/li&gt;
&lt;li data-end=&quot;1916&quot; data-start=&quot;1881&quot;&gt;각 비트가 켜져 있는지 확인해 선택된 원소를 수집하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1929&quot; data-start=&quot;1918&quot; data-ke-size=&quot;size23&quot;&gt;성능과 단순성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1986&quot; data-start=&quot;1930&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1960&quot; data-start=&quot;1930&quot;&gt;2^N 번 반복하지만, N이 작으면 충분히 빠르다.&lt;/li&gt;
&lt;li data-end=&quot;1986&quot; data-start=&quot;1961&quot;&gt;백트래킹보다 코드가 짧고 간단할 수 있다.&lt;/li&gt;
&lt;/ul&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;간단한 예시: 부분수열 합 구하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;2025&quot; data-start=&quot;2019&quot; data-ke-size=&quot;size23&quot;&gt;개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2130&quot; data-start=&quot;2026&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2087&quot; data-start=&quot;2026&quot;&gt;어떤 배열 arr의 모든 부분수열 합을 구하고 싶다면, 비트마스킹을 이용해 부분집합을 표현할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;2130&quot; data-start=&quot;2088&quot;&gt;각 부분집합에 대응하는 bit값을 순회하면서 해당하는 요소를 더한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1741065560925&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    int[] arr = {1, 2, 3};
    List&amp;lt;Integer&amp;gt; sums = new ArrayList&amp;lt;&amp;gt;();
    int N = arr.length;

    for (int bit = 0; bit &amp;lt; (1 &amp;lt;&amp;lt; N); bit++) {
        int sum = 0;
        for (int i = 0; i &amp;lt; N; i++) {
            if ((bit &amp;amp; (1 &amp;lt;&amp;lt; i)) != 0) {
                sum += arr[i];
            }
        }
        sums.add(sum);
    }

    System.out.println(&quot;부분수열 합 리스트: &quot; + sums);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2626&quot; data-start=&quot;2572&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2601&quot; data-start=&quot;2572&quot;&gt;bit에 따라 어떤 원소를 포함할지 결정한다.&lt;/li&gt;
&lt;li data-end=&quot;2626&quot; data-start=&quot;2602&quot;&gt;모든 부분수열 합을 쉽게 구할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2639&quot; data-start=&quot;2628&quot; data-ke-size=&quot;size23&quot;&gt;성능과 단순성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2760&quot; data-start=&quot;2640&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2660&quot; data-start=&quot;2640&quot;&gt;시간 복잡도: O(N * 2^N)&lt;/li&gt;
&lt;li data-end=&quot;2701&quot; data-start=&quot;2661&quot;&gt;N이 15 이하라면 2^15(=32768) 안에서 문제없이 동작한다.&lt;/li&gt;
&lt;li data-end=&quot;2760&quot; data-start=&quot;2702&quot;&gt;더 큰 N에서는 비트마스킹 대신 분할정복(Meet in the Middle) 등의 방식도 고려 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;비트마스킹? 백트래킹?&amp;nbsp;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;3105&quot; data-start=&quot;2782&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;2931&quot; data-start=&quot;2782&quot;&gt;&lt;b&gt;비트마스킹&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2931&quot; data-start=&quot;2800&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2836&quot; data-start=&quot;2800&quot;&gt;&lt;b&gt;장점&lt;/b&gt;: 메모리 사용 감소, 빠른 연산, 간결한 코드&lt;/li&gt;
&lt;li data-end=&quot;2879&quot; data-start=&quot;2840&quot;&gt;&lt;b&gt;단점&lt;/b&gt;: N이 커지면(보통 20 이상) 2^N 연산이 부담&lt;/li&gt;
&lt;li data-end=&quot;2931&quot; data-start=&quot;2883&quot;&gt;&lt;b&gt;적절 사례&lt;/b&gt;: N &amp;le; 15, 방문 상태 관리, 부분집합/조합/부분수열 문제&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;3105&quot; data-start=&quot;2933&quot;&gt;&lt;b&gt;백트래킹&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3105&quot; data-start=&quot;2950&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2989&quot; data-start=&quot;2950&quot;&gt;&lt;b&gt;장점&lt;/b&gt;: 직관적, 가지치기(pruning) 로직 추가 용이&lt;/li&gt;
&lt;li data-end=&quot;3044&quot; data-start=&quot;2993&quot;&gt;&lt;b&gt;단점&lt;/b&gt;: (가지치기가 없으면) 같은 2^N 복잡도를 갖고 코드가 길어질 수 있음&lt;/li&gt;
&lt;li data-end=&quot;3105&quot; data-start=&quot;3048&quot;&gt;&lt;b&gt;적절 사례&lt;/b&gt;: N이 커서 일부 가지치기가 필요한 경우, 상태에 따라 로직이 복잡해지는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;3242&quot; data-start=&quot;3107&quot; data-ke-size=&quot;size16&quot;&gt;결과적으로 N이 작다면, &lt;b&gt;비트마스킹&lt;/b&gt;이 더 단순하면서도 성능이 우수하다.&lt;/p&gt;
&lt;p data-end=&quot;3242&quot; data-start=&quot;3107&quot; data-ke-size=&quot;size16&quot;&gt;만약 N이 커서 2^N이 너무 크다면, 문제 특성에 맞춰 &lt;b&gt;백트래킹 + 가지치기&lt;/b&gt;를 병행하거나 &lt;b&gt;Meet in the Middle&lt;/b&gt; 등의 전략이 필요해진다.&lt;/p&gt;
&lt;p data-end=&quot;3242&quot; data-start=&quot;3107&quot; 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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;실전 + 야구 경기 비트 마스킹으로 묘사&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 흔히 아는 야구경기를 생각해보면, 아웃 카운트 3개가 쌓이면 공수가 바뀌고 그 외에 1루타 부터 홈런까지 주자가 1칸~4칸을 움직이는 것을 알수 있다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;이를 단순하게 구현을 해보면 어쩔수 없이 많은 조건문으로 이를 처리해야하는데&lt;/p&gt;
&lt;pre id=&quot;code_1741065824355&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static int simulateGame(int[] curOrder) {
        int score = 0;
        int batterIndex = 0;

        for (int i = 0; i &amp;lt; N; i++) {
            int outCount = 0;
            boolean base1 = false;
            boolean base2 = false;
            boolean base3 = false;

            while (outCount &amp;lt; 3) {
                int batter = curOrder[batterIndex];
                int result = game[i][batter];

                if (result == 0) {
                    outCount++;
                } else {
                    if (result == 1) {
                        if (base3) {
                            score++;
                            base3 = false;
                        }
                        if (base2) {
                            base3 = true;
                            base2 = false;
                        }
                        if (base1) {
                            base2 = true;
                            base1 = false;
                        }
                        base1 = true;
                    } else if (result == 2) {
                        if (base3) {
                            score++;
                            base3 = false;
                        }
                        if (base2) {
                            score++;
                            base2 = false;
                        }
                        if (base1) {
                            base3 = true;
                            base1 = false;
                        }
                        base2 = true;
                    } else if (result == 3) {
                        if (base3) {
                            score++;
                            base3 = false;
                        }
                        if (base2) {
                            score++;
                            base2 = false;
                        }
                        if (base1) {
                            score++;
                            base1 = false;
                        }
                        base3 = true;
                    } else if (result == 4) {
                        if (base3) {
                            score++;
                            base3 = false;
                        }
                        if (base2) {
                            score++;
                            base2 = false;
                        }
                        if (base1) {
                            score++;
                            base1 = false;
                        }
                        score++;
                    }
                }

                batterIndex = (batterIndex + 1) % 9;
            }
        }
        return score;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 베이스 3개를 base1, base2, base3 같은 불리언 변수를 따로 두고 다양한 조건문으로 처리했지만,&lt;br /&gt;&lt;b&gt;비트 마스크를 활용한다면 단 하나의 정수(baseState)에 주자 상태를 압축&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비트 마스크로 나타내어 보면 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1741065848850&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static int simulateGame(int[] curOrder) {
    int score = 0;
    int batterIndex = 0;

    for (int i = 0; i &amp;lt; N; i++) {
        int outCount = 0;
        int baseState = 0b000; // 1루, 2루, 3루 상태를 비트로 표현

        while (outCount &amp;lt; 3) {
            int batter = curOrder[batterIndex];
            int result = game[i][batter]; // 0: 아웃, 1~4: 진루

            if (result == 0) {
                outCount++;
            } else {
                // 1) 기존 주자들을 result만큼 이동
                baseState &amp;lt;&amp;lt;= result;

                // 2) 새로 타석에 들어선 타자가 result칸(루) 진루하는 것 처리
                //    예: 싱글(1루타)이면 baseState |= 0b001
                //        더블(2루타)이면 baseState |= 0b010
                baseState |= (1 &amp;lt;&amp;lt; (result - 1));

                // 3) 홈에 들어온 주자(3루 초과로 넘어간 주자) 수를 점수로 추가
                //    0b1111000은 3루(비트 2)보다 높은 비트를 모두 체크하기 위한 마스크
                score += Integer.bitCount(baseState &amp;amp; 0b1111000);

                // 4) 3루 이하의 주자 상태만 남기고, 나머지는 제거(홈인으로 처리됨)
                baseState &amp;amp;= 0b111; // 하위 3비트만 유지
            }

            // 다음 타자로 이동
            batterIndex = (batterIndex + 1) % 9;
        }
    }
    return score;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-end=&quot;1407&quot; data-start=&quot;1382&quot; data-ke-size=&quot;size23&quot;&gt;1. baseState의 비트 구성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1599&quot; data-start=&quot;1408&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1545&quot; data-start=&quot;1408&quot;&gt;baseState는 하위 3비트를 사용해 1&amp;middot;2&amp;middot;3루에 주자가 있는지 표현한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1545&quot; data-start=&quot;1459&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1485&quot; data-start=&quot;1459&quot;&gt;&lt;b&gt;하위 1비트(0번)&lt;/b&gt;: 1루 주자 여부&lt;/li&gt;
&lt;li data-end=&quot;1514&quot; data-start=&quot;1488&quot;&gt;&lt;b&gt;다음 1비트(1번)&lt;/b&gt;: 2루 주자 여부&lt;/li&gt;
&lt;li data-end=&quot;1545&quot; data-start=&quot;1517&quot;&gt;&lt;b&gt;다음 1비트(2번)&lt;/b&gt;: 3루 주자 여부&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1599&quot; data-start=&quot;1546&quot;&gt;예를 들어, baseState = 0b101(5)는 1루와 3루에 주자가 있다는 뜻이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1640&quot; data-start=&quot;1601&quot; data-ke-size=&quot;size23&quot;&gt;2. 주자 이동 ( baseState &amp;lt;&amp;lt;= result )&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1846&quot; data-start=&quot;1641&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1785&quot; data-start=&quot;1641&quot;&gt;result가 1(싱글)이면 baseState를 왼쪽으로 1비트 이동
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1785&quot; data-start=&quot;1690&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1734&quot; data-start=&quot;1690&quot;&gt;예: 0b101(1,3루 주자) &amp;rarr; 0b1010 (2,4루 주자)&lt;/li&gt;
&lt;li data-end=&quot;1785&quot; data-start=&quot;1737&quot;&gt;실제로 4루는 곧 득점(홈) 위치에 해당되므로, 이후에 점수 계산에서 반영한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1846&quot; data-start=&quot;1786&quot;&gt;result가 2(더블)면 왼쪽으로 2비트, 3(트리플)이면 3비트, 4(홈런)이면 4비트 이동한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1905&quot; data-start=&quot;1848&quot; data-ke-size=&quot;size23&quot;&gt;3. 새 주자(타자) 진루 ( baseState |= (1 &amp;lt;&amp;lt; (result - 1)) )&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2095&quot; data-start=&quot;1906&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1952&quot; data-start=&quot;1906&quot;&gt;타자가 1루타면 baseState |= 1 &amp;lt;&amp;lt; 0 (즉, 0b001 추가)&lt;/li&gt;
&lt;li data-end=&quot;1999&quot; data-start=&quot;1953&quot;&gt;타자가 2루타면 baseState |= 1 &amp;lt;&amp;lt; 1 (즉, 0b010 추가)&lt;/li&gt;
&lt;li data-end=&quot;2095&quot; data-start=&quot;2000&quot;&gt;홈런(4루타)일 때는 1 &amp;lt;&amp;lt; 3을 추가하므로, &lt;b&gt;곧바로 홈으로 들어가는 위치(3보다 높은 비트)에 해당&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2095&quot; data-start=&quot;2070&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2095&quot; data-start=&quot;2070&quot;&gt;이는 결국 득점 처리에서 점수가 추가된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2164&quot; data-start=&quot;2097&quot; data-ke-size=&quot;size23&quot;&gt;4. 득점 처리 ( score += Integer.bitCount(baseState &amp;amp; 0b1111000) )&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2355&quot; data-start=&quot;2165&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2232&quot; data-start=&quot;2165&quot;&gt;0b1111000(이진수로 0111_1000)은 &lt;b&gt;3루 비트(2번)보다 높은 비트&lt;/b&gt;를 확인하기 위한 마스크다.&lt;/li&gt;
&lt;li data-end=&quot;2293&quot; data-start=&quot;2233&quot;&gt;왼쪽 시프트로 인해 3루를 초과한 모든 주자(즉, 홈에 들어온 주자)는 3번 비트 이상에 위치하게 된다.&lt;/li&gt;
&lt;li data-end=&quot;2355&quot; data-start=&quot;2294&quot;&gt;Integer.bitCount()를 사용해 해당 영역에 몇 명의 주자가 있는지를 세어 점수에 더해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2402&quot; data-start=&quot;2357&quot; data-ke-size=&quot;size23&quot;&gt;5. 3루 이하 상태만 남기기 ( baseState &amp;amp;= 0b111 )&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2500&quot; data-start=&quot;2403&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2449&quot; data-start=&quot;2403&quot;&gt;3루(비트 2) 이하만 유지하고, 홈을 밟은 주자(비트 3 이상)는 날려버린다.&lt;/li&gt;
&lt;li data-end=&quot;2500&quot; data-start=&quot;2450&quot;&gt;홈을 밟은 주자는 이미 득점 처리되었으므로 baseState에서 제거해도 무방하다.&lt;/li&gt;
&lt;/ul&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;h3 data-end=&quot;3131&quot; data-start=&quot;3125&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3369&quot; data-start=&quot;3132&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3199&quot; data-start=&quot;3132&quot;&gt;&lt;b&gt;비트마스킹&lt;/b&gt;은 야구 주자 이동처럼 상태 변화가 규칙적이면서 간단한(여기서는 최대 3루까지) 문제에 탁월하다.&lt;/li&gt;
&lt;li data-end=&quot;3308&quot; data-start=&quot;3200&quot;&gt;불리언 변수를 여러 개 두어 &amp;ldquo;1루 주자가 있을 때 &amp;rarr; 2루로 옮김&amp;rdquo; 같은 if문을 일일이 쓰기보다,&lt;br /&gt;&lt;b&gt;왼쪽 시프트 + 마스킹&lt;/b&gt;으로 한 번에 처리하므로 코드가 짧고 명료해진다.&lt;/li&gt;
&lt;li data-end=&quot;3369&quot; data-start=&quot;3309&quot;&gt;또한 홈에 들어온 주자를 빠르게 계산할 수 있어, &lt;b&gt;숫자 조작&lt;/b&gt; 하나로 득점을 기록하기 쉬워진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;3428&quot; data-start=&quot;3371&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 단순한&lt;b&gt;&amp;nbsp;로직&lt;/b&gt;을 비트로 관리하면, 짧고 효율적인 코드로 구현이 가능해진다.&lt;/p&gt;</description>
      <category>Java</category>
      <category>비트마스크</category>
      <category>비트마스킹</category>
      <category>야구게임</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/239</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%A1%B0%EA%B1%B4%EB%AC%B8-%EC%97%86%EC%9D%B4-%EA%B9%94%EB%81%94%ED%95%98%EA%B2%8C-%EC%9E%90%EB%B0%94-%EB%B9%84%ED%8A%B8%EB%A7%88%EC%8A%A4%ED%82%B9%EC%9C%BC%EB%A1%9C-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0%ED%95%98%EB%8A%94-%EB%B2%95-%EC%82%AC%EC%9A%A9-%EC%9C%A0%ED%98%95-%EC%A0%95%EB%A6%AC#entry239comment</comments>
      <pubDate>Tue, 4 Mar 2025 14:30:11 +0900</pubDate>
    </item>
    <item>
      <title>[Spring-Mock] Vanilla Java로 Custom HTTP Server 구축하기 [1]</title>
      <link>https://nstgic3.tistory.com/entry/Spring-Mock-Vanilla-Java%EB%A1%9C-Custom-HTTP-Server-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-1</link>
      <description>&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;서론: 왜 직접 HTTP 서버를 만들어보는가?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 개발을 할 때 우리는 대부분 Spring Boot 같은 프레임워크를 사용하여 서버를 구축한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot는 내부적으로 &lt;b&gt;Tomcat&lt;/b&gt;, &lt;b&gt;Jetty&lt;/b&gt; 같은 내장 서버를 사용하기 때문에, HTTP 요청이 어떻게 처리되는지 직접 고민할 일이 거의 없다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HTTP 서버의 동작 원리를 직접 구현해 본다면&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;b&gt;Socket 프로그래밍&lt;/b&gt;: 클라이언트와 서버 간의 데이터 전송 원리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;멀티스레딩 기초&lt;/b&gt;: 여러 클라이언트 요청을 동시에 처리하는 방법&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HTTP 프로토콜 구조&lt;/b&gt;: HTTP 요청(Request)과 응답(Response)의 동작원리 및 기본적인 웹 서버의 구조&lt;/li&gt;
&lt;li&gt;&lt;b&gt;심지어는 Spring 에서 제공하는 Bean 이나 서블릿도 이해할수 있을것 같다&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 &lt;b&gt;가장 기본적인 HTTP 서버를 직접 구현&lt;/b&gt;해보고, 코드 분석을 통해 중요한 개념들을 하나씩 설명해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;간단한 HTTP 서버 코드&lt;/h3&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;pre id=&quot;code_1740323269130&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * CustomHttpServer 클래스는 간단한 HTTP 서버를 구현합니다.
 * 서버는 지정된 포트에서 클라이언트 요청을 수신하고, 간단한 &quot;Hello World&quot; 응답을 반환합니다.
 * 
 * &amp;lt;p&amp;gt;주요 기능:
 * &amp;lt;ul&amp;gt;
 *   &amp;lt;li&amp;gt;서버 시작 및 클라이언트 연결 수락&amp;lt;/li&amp;gt;
 *   &amp;lt;li&amp;gt;클라이언트 요청 처리 및 응답 전송&amp;lt;/li&amp;gt;
 * &amp;lt;/ul&amp;gt;
 * 
 * &amp;lt;p&amp;gt;사용 예:
 * &amp;lt;pre&amp;gt;
 * {@code
 * public static void main(String[] args) throws IOException {
 *     new CustomHttpServer().start();
 * }
 * }
 * &amp;lt;/pre&amp;gt;
 * 
 * @author 
 * @version 1.0
 */
public class CustomHttpServer {
    private static final int PORT = 8080;

    public void start() throws IOException {
        ServerSocket serverSocket = new ServerSocket(PORT);
        System.out.println(&quot;Custom HTTP Server started on port &quot; + PORT);
        
        while (true) {
            Socket clientSocket = serverSocket.accept();
            Thread thread = new Thread(() -&amp;gt; handleRequest(clientSocket));
            thread.start();
        }
    }
    
    private void handleRequest(Socket socket) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             OutputStream output = socket.getOutputStream()) {
            
            // 요청 읽
            String requestLine = reader.readLine();
            System.out.println(&quot;Received: &quot; + requestLine);
            
            // 간단한 응답 보내기
            String response = &quot;HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello World&quot;;
            output.write(response.getBytes());
            output.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        new CustomHttpServer().start();
    }
}&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;코드 분석 및 핵심 개념 학습&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1 `ServerSocket`을 이용한 서버 생성&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;nbsp;ServerSocket serverSocket = new ServerSocket(PORT);&amp;nbsp;&lt;/blockquote&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;8080번 포트에서 클라이언트 요청을 받을 준비&lt;/b&gt;를 한다. 마치 Spring 처럼&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ServerSocket은 특정 포트에서 네트워크 연결을 수락하는 역할을 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;992&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs68Jz/btsMsSIAXc7/uIdZduFqXNUCPSY1OrCl2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs68Jz/btsMsSIAXc7/uIdZduFqXNUCPSY1OrCl2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs68Jz/btsMsSIAXc7/uIdZduFqXNUCPSY1OrCl2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs68Jz%2FbtsMsSIAXc7%2FuIdZduFqXNUCPSY1OrCl2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1756&quot; height=&quot;992&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;992&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/net/ServerSocket.html#accept--&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/javase/8/docs/api/java/net/ServerSocket.html#accept--&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1740323568678&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;ServerSocket (Java Platform SE 8 )&quot; data-og-description=&quot;Create a server with the specified port, listen backlog, and local IP address to bind to. The bindAddr argument can be used on a multi-homed host for a ServerSocket that will only accept connect requests to one of its addresses. If bindAddr is null, it wil&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/javase/8/docs/api/java/net/ServerSocket.html#accept--&quot; data-og-url=&quot;https://docs.oracle.com/javase/8/docs/api/java/net/ServerSocket.html#accept--&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/net/ServerSocket.html#accept--&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/javase/8/docs/api/java/net/ServerSocket.html#accept--&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;ServerSocket (Java Platform SE 8 )&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Create a server with the specified port, listen backlog, and local IP address to bind to. The bindAddr argument can be used on a multi-homed host for a ServerSocket that will only accept connect requests to one of its addresses. If bindAddr is null, it wil&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;h4 data-ke-size=&quot;size20&quot;&gt;2.2 클라이언트 요청을 기다리기&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Socket clientSocket = serverSocket.accept();&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`accept()` 메서드는 &lt;b&gt;클라이언트가 요청을 보낼 때까지 대기&lt;/b&gt;하며, 연결 요청이 오면 새로운 `Socket` 객체를 반환하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 클라이언트가 웹 브라우저에서 http://localhost:8080에 접속하면, accept() 메서드가 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3 요청을 처리하는 스레드 생성&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Thread thread = new Thread(() -&amp;gt; handleRequest(clientSocket)); thread.start();&amp;nbsp;&lt;/blockquote&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;스레드(Thread)&lt;/b&gt;에서 처리하여 서버가 동시에 여러 요청을 받을 수 있도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 스레드보고 처리를 하라고 할까? &lt;a href=&quot;https://www.quora.com/Why-are-threads-used-in-client-server-programs&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.quora.com/Why-are-threads-used-in-client-server-programs&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1740323439946&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Why are threads used in client/server programs?&quot; data-og-description=&quot;Answer (1 of 2): I like to think of threads as lanes on a road, each lane is a set of code which runs. Imagine you have your User Interaction 'lane' and you then run a HTTP GET in that lane. Unfortunately that GET is really slow. Now you have effectively b&quot; data-og-host=&quot;www.quora.com&quot; data-og-source-url=&quot;https://www.quora.com/Why-are-threads-used-in-client-server-programs&quot; data-og-url=&quot;https://www.quora.com/Why-are-threads-used-in-client-server-programs&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/coie0y/hyYfSDbR2s/JnzOFk5Z1LF3gSNyNtDYm1/img.jpg?width=600&amp;amp;height=315&amp;amp;face=0_0_600_315,https://scrap.kakaocdn.net/dn/u0vKP/hyYjwTibTr/xdOM4BRK0wNZRBOJTUBBB0/img.jpg?width=600&amp;amp;height=315&amp;amp;face=0_0_600_315&quot;&gt;&lt;a href=&quot;https://www.quora.com/Why-are-threads-used-in-client-server-programs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.quora.com/Why-are-threads-used-in-client-server-programs&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/coie0y/hyYfSDbR2s/JnzOFk5Z1LF3gSNyNtDYm1/img.jpg?width=600&amp;amp;height=315&amp;amp;face=0_0_600_315,https://scrap.kakaocdn.net/dn/u0vKP/hyYjwTibTr/xdOM4BRK0wNZRBOJTUBBB0/img.jpg?width=600&amp;amp;height=315&amp;amp;face=0_0_600_315');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Why are threads used in client/server programs?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Answer (1 of 2): I like to think of threads as lanes on a road, each lane is a set of code which runs. Imagine you have your User Interaction 'lane' and you then run a HTTP GET in that lane. Unfortunately that GET is really slow. Now you have effectively b&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.quora.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/cd/E19146-01/821-1834/geeie/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/cd/E19146-01/821-1834/geeie/index.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1740323455478&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Understanding Threads, Processes, and Connections (Oracle iPlanet Web Server 7.0.9 Performance Tuning, Sizing, and Scaling Guide&quot; data-og-description=&quot;Understanding Threads, Processes, and Connections Before tuning your server, you should understand the connection-handling process in Web Server. Request processing threads handle Web Server connections. You can configure Request handling threads from the &quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/cd/E19146-01/821-1834/geeie/index.html&quot; data-og-url=&quot;https://docs.oracle.com/cd/E19146-01/821-1834/geeie/index.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/cd/E19146-01/821-1834/geeie/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/cd/E19146-01/821-1834/geeie/index.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Understanding Threads, Processes, and Connections (Oracle iPlanet Web Server 7.0.9 Performance Tuning, Sizing, and Scaling Guide&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Understanding Threads, Processes, and Connections Before tuning your server, you should understand the connection-handling process in Web Server. Request processing threads handle Web Server connections. You can configure Request handling threads from the&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4 요청을 읽는 방법: `BufferedReader`&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드에서 `BufferedReader`를 사용하는 이유는 &lt;b&gt;네트워크 스트림에서 효율적으로 데이터를 읽기 위해서&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 이걸 썼는지? &lt;a href=&quot;https://www.baeldung.com/java-buffered-reader&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.baeldung.com/java-buffered-reader&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 요약하면 BufferedReader를 사용하면 &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;HTTP 요청의 첫 번째 줄(예: &quot;GET / HTTP/1.1&quot;)을 읽고 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.5 응답 구성 방식&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;String response = &quot;HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello World&quot;;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 응답은 HTTP 명세를 따르고 있으며, 기본적으로 3가지 요소를 포함한다.&lt;br /&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Overview#http_%EA%B8%B0%EB%B0%98_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%9D%98_%EA%B5%AC%EC%84%B1%EC%9A%94%EC%86%8C&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.mozilla.org/ko/docs/Web/HTTP/Overview#http_%EA%B8%B0%EB%B0%98_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%9D%98_%EA%B5%AC%EC%84%B1%EC%9A%94%EC%86%8C&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1740323507548&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;HTTP 개요 - HTTP | MDN&quot; data-og-description=&quot;HTTP는 HTML 문서와 같은 리소스들을 가져올 수 있도록 해주는 프로토콜입니다. HTTP는 웹에서 이루어지는 모든 데이터 교환의 기초이며, 클라이언트-서버 프로토콜이기도 합니다. 클라이언트-서버&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Overview#http_%EA%B8%B0%EB%B0%98_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%9D%98_%EA%B5%AC%EC%84%B1%EC%9A%94%EC%86%8C&quot; data-og-url=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Overview&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Hw97N/hyYjEqbAw1/ObctzZ9Wni7kkcSn59BiKK/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Overview#http_%EA%B8%B0%EB%B0%98_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%9D%98_%EA%B5%AC%EC%84%B1%EC%9A%94%EC%86%8C&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Overview#http_%EA%B8%B0%EB%B0%98_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%9D%98_%EA%B5%AC%EC%84%B1%EC%9A%94%EC%86%8C&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Hw97N/hyYjEqbAw1/ObctzZ9Wni7kkcSn59BiKK/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;HTTP 개요 - HTTP | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;HTTP는 HTML 문서와 같은 리소스들을 가져올 수 있도록 해주는 프로토콜입니다. HTTP는 웹에서 이루어지는 모든 데이터 교환의 기초이며, 클라이언트-서버 프로토콜이기도 합니다. 클라이언트-서버&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;4047&quot; data-start=&quot;3821&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;3899&quot; data-start=&quot;3821&quot;&gt;&lt;b&gt;상태 코드(Status Code)&lt;/b&gt;: HTTP/1.1 200 OK
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3899&quot; data-start=&quot;3871&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3899&quot; data-start=&quot;3871&quot;&gt;200 OK는 요청이 성공했음을 의미&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;3982&quot; data-start=&quot;3900&quot;&gt;&lt;b&gt;헤더(Header)&lt;/b&gt;: Content-Type: text/plain
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3982&quot; data-start=&quot;3951&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3982&quot; data-start=&quot;3951&quot;&gt;응답 본문이 &lt;b&gt;텍스트 파일&lt;/b&gt; 형식임을 나타낸다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;4047&quot; data-start=&quot;3983&quot;&gt;&lt;b&gt;본문(Body)&lt;/b&gt;: &quot;Hello World&quot;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4047&quot; data-start=&quot;4021&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4047&quot; data-start=&quot;4021&quot;&gt;클라이언트에게 전달될 실제 응답 내용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;코드 실행 결과&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;854&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q47ng/btsMtt9lSRo/2Frx6YZ1PFYATKTWfkROK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q47ng/btsMtt9lSRo/2Frx6YZ1PFYATKTWfkROK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q47ng/btsMtt9lSRo/2Frx6YZ1PFYATKTWfkROK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq47ng%2FbtsMtt9lSRo%2F2Frx6YZ1PFYATKTWfkROK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;782&quot; height=&quot;399&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;854&quot;/&gt;&lt;/span&gt;&lt;/figure&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;우리가 response 에 작성해놨던 부분이 클라이언트에게 보여지게 된다.&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;실제로 해당 정보가 HTTP 데이터인건 아니지만? 우리가 만드는건 결국 mock 이기 때문에 이렇게 만들어놓고 서서히 구현해나가면 된다.&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;다음 확장을 고려해야될 부분&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 코드는 보면 알다싶이 GET 요청밖에 못하고 명시해둔 버전이나 타입도 전부 하드코딩해놓은 결과물이다.&lt;br /&gt;따라서 HTTP 명세를 보면서 몇가지를 더 추가해보자&lt;/p&gt;
&lt;h3 data-end=&quot;4174&quot; data-start=&quot;4140&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;HTTP 메서드(GET, POST) 지원&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;4230&quot; data-start=&quot;4175&quot; data-ke-size=&quot;size16&quot;&gt;현재는 모든 요청을 동일하게 처리하지만, 실제 웹 서버는 다양한 HTTP 메서드를 지원해야 합니다.&lt;/p&gt;
&lt;h3 data-end=&quot;4400&quot; data-start=&quot;4363&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;동적인 상태 코드(Status Code) 반환&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;4486&quot; data-start=&quot;4401&quot; data-ke-size=&quot;size16&quot;&gt;지금은 200 OK만 반환하지만, 예외 발생 시 &lt;b&gt;400 Bad Request, 404 Not Found&lt;/b&gt; 등의 상태 코드를 반환할 수 있다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-start=&quot;4488&quot; data-end=&quot;4510&quot;&gt;&lt;b&gt;헤더(Header) 구현&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;4511&quot; data-end=&quot;4599&quot;&gt;&lt;span&gt;현재는 고정된 &lt;/span&gt;&lt;span&gt;Content-Type&lt;/span&gt;&lt;span&gt;만 반환하지만, 다양한 콘텐츠 타입을 지원해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-end=&quot;4510&quot; data-start=&quot;4488&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;요청 파라미터 분석&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;4599&quot; data-start=&quot;4511&quot; data-ke-size=&quot;size16&quot;&gt;현재 코드는 클라이언트의 요청 데이터를 처리하지 않지만,&lt;br /&gt;쿼리 스트링(?name=John)이나 POST 데이터를 분석할 수 있도록 개선할 수 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;4623&quot; data-start=&quot;4601&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;객체지향 설계 적용&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;4711&quot; data-start=&quot;4624&quot; data-ke-size=&quot;size16&quot;&gt;지금은 모든 기능이 &lt;b&gt;하나의 클래스&lt;/b&gt;에 포함되어 있지만, &lt;b&gt;Request 객체, Response 객체를 분리&lt;/b&gt;하여 유지보수성을 높여보자&lt;/p&gt;</description>
      <category>Spring</category>
      <category>http 서버</category>
      <category>tomcat</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/237</guid>
      <comments>https://nstgic3.tistory.com/entry/Spring-Mock-Vanilla-Java%EB%A1%9C-Custom-HTTP-Server-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-1#entry237comment</comments>
      <pubDate>Mon, 24 Feb 2025 00:20:44 +0900</pubDate>
    </item>
    <item>
      <title>해시 충돌과 참조 지역성: 자바 HashMap 성능 저하 테스트</title>
      <link>https://nstgic3.tistory.com/entry/%ED%95%B4%EC%8B%9C-%EC%B6%A9%EB%8F%8C%EA%B3%BC-%EC%B0%B8%EC%A1%B0-%EC%A7%80%EC%97%AD%EC%84%B1-%EC%9E%90%EB%B0%94-HashMap-%EC%84%B1%EB%8A%A5-%EC%A0%80%ED%95%98-%EC%BC%80%EC%9D%B4%EC%8A%A4</link>
      <description>&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로, 우리는 자바 &lt;code&gt;HashMap&lt;/code&gt;이 평균적으로 &lt;b&gt;O(1)&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;ldquo;해시 충돌(Hash Collision)&amp;rdquo;이 심해지면 성능이 급격히 떨어질 수 있다는 사실은 자칫 놓치기 쉽습니다. 또한, CPU 캐시 구조와 &amp;ldquo;참조 지역성(Reference Locality)&amp;rdquo;을 이해하면, 왜 이 문제가 현실에서 더 크게 체감되는지 알 수 있습니다.&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;이 주제는 백준 7453 번 문제를 풀다가 경험하게 되었는데&lt;br /&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/7453&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/7453&lt;/a&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;C++,C 에서는 기존의 방법처럼 2개씩 쌍으로 묶어서 계산한다음에 한쪽 값을 해시 맵에 넣어두고 0을 만들기 위한 보수가 존재하는지 hash key 탐색으로 풀렸지만 자바의 경우에는 그렇지 않았다.&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;탐색 길이인 n은 4000*4000 으로 16,000,000 정도로 1.6천만 정도 되는데 이론상 O(1) 이기에 스무스 하게 통과를 해야만 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅에서 배우겠지만 해시 저격으로 인해 버킷 적중이 8회(기본값)이 넘어가 Red-Black Tree 로 변환되고 이는 O(logN)으로 동작하지만, 그래도 충분히 느리기 때문에 해당 방법으로 끝까지 풀리지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKQzcZ/btsMm4igYrj/TiFZrhKlH16xbVIYO9c5E0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKQzcZ/btsMm4igYrj/TiFZrhKlH16xbVIYO9c5E0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKQzcZ/btsMm4igYrj/TiFZrhKlH16xbVIYO9c5E0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKQzcZ%2FbtsMm4igYrj%2FTiFZrhKlH16xbVIYO9c5E0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;637&quot; height=&quot;418&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;418&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는&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;참조 지역성이란 무엇인지&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;왜 자바 HashMap에 해시 충돌이 발생하면 성능이 크게 떨어지는지&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;직접 해볼 수 있는 &amp;lsquo;악의적 입력(Adversarial Input)&amp;rsquo; 예시&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;1. 참조 지역성(Reference Locality)이란?&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1 정의&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참조 지역성이란 컴퓨터 프로그램이 메모리를 접근할 때, 일정 시점에 &lt;b&gt;가까운 주소&lt;/b&gt;나 &lt;b&gt;최근에 사용한 주소&lt;/b&gt;를 다시 참조하는 경향이 있다는 개념입니다.CPU는 이 패턴을 이용해 &lt;b&gt;캐시(Cache)&lt;/b&gt;라는 작은 저장장치에 데이터를 미리 가져오고, 필요한 데이터를 재활용하여 빠른 접근 속도를 가능하게 합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2 두 가지 주요 형태&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시간적 지역성(Temporal Locality)&lt;/b&gt;: 한 번 참조된 데이터는 가까운 미래에 &lt;b&gt;다시 참조&lt;/b&gt;될 가능성이 높다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공간적 지역성(Spatial Locality)&lt;/b&gt;: 어떤 주소가 참조되면, 그 &lt;b&gt;근처(인접)&lt;/b&gt; 주소를 곧 사용할 가능성이 높다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3 컬렉션 자료구조와 지역성&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;배열(Array)&lt;/b&gt;: 내부가 연속된 메모리로 이뤄져 있으므로, 순차 탐색 시 공간적 지역성이 극대화된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;연결 리스트(LinkedList)&lt;/b&gt;: 노드가 임의 메모리 주소에 산재해 있으므로, 노드를 차례대로 탐색할 때 CPU 캐시에 잘 실리지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해시 테이블(HashMap)&lt;/b&gt;: 해시 버킷(배열)은 연속적일 수 있지만, 충돌이 발생하면 연결 리스트나 트리를 따라가야 한다. 이 과정에서 임의 주소를 점프하므로 지역성이 떨어질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;2. 자바 HashMap, 정말 O(1)일까?&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1 평균 O(1)의 비밀&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 &lt;code&gt;HashMap&lt;/code&gt;은 평균적으로 &lt;code&gt;put&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;containsKey&lt;/code&gt; 연산 모두 &lt;b&gt;O(1)&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;a href=&quot;https://medium.com/geekculture/a-deep-dive-into-java-8-hashmap-a976aca22f9b&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/geekculture/a-deep-dive-into-java-8-hashmap-a976aca22f9b&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1739940813742&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;A Deep Dive into Java 8 HashMap&quot; data-og-description=&quot;The main data structures in HashMap include Array, LinkedList, and Red-Black Tree (an advanced version of a binary search tree). This&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/geekculture/a-deep-dive-into-java-8-hashmap-a976aca22f9b&quot; data-og-url=&quot;https://medium.com/geekculture/a-deep-dive-into-java-8-hashmap-a976aca22f9b&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cnkeZE/hyYfREbpsc/di6RBmf4CRWdoIIEZRBIaK/img.jpg?width=760&amp;amp;height=480&amp;amp;face=0_0_760_480,https://scrap.kakaocdn.net/dn/b3c4qx/hyYfFwUKmp/bpFw61dsE56L03m4wLQ9xK/img.jpg?width=350&amp;amp;height=233&amp;amp;face=0_0_350_233&quot;&gt;&lt;a href=&quot;https://medium.com/geekculture/a-deep-dive-into-java-8-hashmap-a976aca22f9b&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/geekculture/a-deep-dive-into-java-8-hashmap-a976aca22f9b&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cnkeZE/hyYfREbpsc/di6RBmf4CRWdoIIEZRBIaK/img.jpg?width=760&amp;amp;height=480&amp;amp;face=0_0_760_480,https://scrap.kakaocdn.net/dn/b3c4qx/hyYfFwUKmp/bpFw61dsE56L03m4wLQ9xK/img.jpg?width=350&amp;amp;height=233&amp;amp;face=0_0_350_233');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;A Deep Dive into Java 8 HashMap&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The main data structures in HashMap include Array, LinkedList, and Red-Black Tree (an advanced version of a binary search tree). This&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2 최악 O(N) 시나리오&lt;/h4&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;h3 data-end=&quot;1838&quot; data-start=&quot;1812&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;자바 8 이상에서 충돌 처리 방식&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1882&quot; data-start=&quot;1839&quot; data-ke-size=&quot;size16&quot;&gt;자바 8부터는 &lt;b&gt;체이닝을 단순히 연결 리스트로 처리하는 방식에서 개선됨&lt;/b&gt;:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;2057&quot; data-start=&quot;1883&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1911&quot; data-start=&quot;1883&quot;&gt;&lt;b&gt;초기에는 LinkedList를 사용&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2057&quot; data-start=&quot;1912&quot;&gt;&lt;b&gt;충돌이 많이 발생하여 같은 버킷에 8개 이상의 엔트리가 들어가면, Red-Black Tree로 변환&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2057&quot; data-start=&quot;1984&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2057&quot; data-start=&quot;1984&quot;&gt;이로 인해 해시 충돌이 많아도 탐색 성능이 &lt;b&gt;O(log n)&lt;/b&gt; 으로 향상됨 (기존 O(n) &amp;rarr; 개선 O(log n))&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼, 이를 해결 하기위해서 자바 8 부터는 특정 횟수 이상으로 충돌이 일어나면 logN인 트리맵 구조로 찾아내지만 이 또한 특정 상황에서는 부족한 경우가 있다.&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;/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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3545&quot; data-start=&quot;3518&quot;&gt;ab[] 생성: O(N^2)&lt;/li&gt;
&lt;li data-end=&quot;3545&quot; data-start=&quot;3518&quot;&gt;cd[] 돌면서 N^2개 해시 키 서칭: &lt;b&gt;O(1*N^2)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;3545&quot; data-start=&quot;3518&quot;&gt;&lt;b&gt;삽입, 조회시에 O(1)이지만 충돌이 심하면 달라질수 있음.logN ~ 그이상.&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;3545&quot; data-start=&quot;3518&quot;&gt;&lt;b&gt;&lt;b&gt;충돌시에 트리화 비용까지 생각한다면 최악&lt;/b&gt; O(N^3~N^2 log(N^2))&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 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;이진 탐색&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;618&quot; data-start=&quot;588&quot;&gt;ab[], cd[] 생성: 각각 O(N^2)&lt;/li&gt;
&lt;li data-end=&quot;655&quot; data-start=&quot;619&quot;&gt;정렬: O(N^2 log(N^2)) = O(N^2 log N)&lt;/li&gt;
&lt;li data-end=&quot;706&quot; data-start=&quot;656&quot;&gt;ab[] 순회(=N^2) &amp;times; 이분 탐색(log(N^2)) &amp;rarr; O(N^2 log N)&lt;/li&gt;
&lt;li data-end=&quot;731&quot; data-start=&quot;707&quot;&gt;전체적으로 &lt;b&gt;O(N^2 log N)&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 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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3545&quot; data-start=&quot;3518&quot;&gt;ab[], cd[] 생성: O(N^2)&lt;/li&gt;
&lt;li data-end=&quot;3582&quot; data-start=&quot;3546&quot;&gt;정렬: O(N^2 log(N^2)) = O(N^2 log N)&lt;/li&gt;
&lt;li data-end=&quot;3642&quot; data-start=&quot;3583&quot;&gt;투 포인터: &lt;b&gt;O(N^2)&lt;/b&gt; (중간에 i++, j-- 형태로 한쪽만 움직이므로 한 바퀴 돌면 종료)&lt;/li&gt;
&lt;li data-end=&quot;3671&quot; data-start=&quot;3643&quot;&gt;전체적으로 &lt;b&gt;O(N^2 log N)&lt;/b&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&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;h4 data-ke-size=&quot;size20&quot;&gt;2.3 지역성과의 결합 효과&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 충돌이 많이 날수록, &lt;b&gt;버킷&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;3. 직접 해보는 해시 충돌 극단 사례, HashMap/ArrayList 참조지역성 테스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 반 강제적인 해시 충돌 시행&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739941934769&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.HashMap;
import java.util.Map;

public class ExtremeHashCollision {
    // 해시 코드가 항상 같은 '악의적'인 키
    static class BadKey {
        private final int value;
        public BadKey(int value) {
            this.value = value;
        }
        @Override
        public int hashCode() {
            return 42; // 모든 객체가 동일한 해시 코드
        }
        @Override
        public boolean equals(Object o) {
            // value만 같으면 equals true
            if (this == o) return true;
            if (!(o instanceof BadKey)) return false;
            BadKey other = (BadKey) o;
            return this.value == other.value;
        }
    }

    public static void main(String[] args) {
        // N이 클수록 충돌이 극단적으로 많아짐
        int N = 500_000; // 50만, 100만 등으로 늘리면 심각하게 느려질 수 있음

        Map&amp;lt;BadKey, Integer&amp;gt; map = new HashMap&amp;lt;&amp;gt;(N);

        long start = System.nanoTime();
        // (1) put 연산
        for (int i = 0; i &amp;lt; N; i++) {
            map.put(new BadKey(i),i);
        }
        long afterPut = System.nanoTime();

        // (2) get 연산 (전부 있는 키)
        long sum = 0;
        for (int i = 0; i &amp;lt; N; i++) {
            sum += map.get(new BadKey(i));
        }
        long afterGet = System.nanoTime();

        System.out.printf(&quot;Insertion took: %.3f ms\n&quot;, (afterPut - start) / 1e6);
        System.out.printf(&quot;Lookup    took: %.3f ms\n&quot;, (afterGet - afterPut) / 1e6);
        System.out.println(&quot;Sum check = &quot; + sum);
    }
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;213&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rel19/btsMoHeUmRZ/1ETYjG5aeOivWA7dhhsuOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rel19/btsMoHeUmRZ/1ETYjG5aeOivWA7dhhsuOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rel19/btsMoHeUmRZ/1ETYjG5aeOivWA7dhhsuOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frel19%2FbtsMoHeUmRZ%2F1ETYjG5aeOivWA7dhhsuOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;854&quot; height=&quot;213&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;213&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;극단 적인 값(50만개, 전부 같은 해시키) 를 넣긴 했지만 충돌시 많은 비용이 드는걸 알수 있다.&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. HashMap 과 ArrayList 참조 지역성 (접근시간) 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739942478159&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

public class LocalityTest {
    public static void main(String[] args) {
        final int[] SIZES = {10_000, 100_000, 1_000_000, 10_000_000};

        for (int SIZE : SIZES) {
            System.out.println(&quot;Testing with SIZE: &quot; + SIZE);

            // HashMap 준비
            Map&amp;lt;Integer, Integer&amp;gt; hashMap = new HashMap&amp;lt;&amp;gt;(SIZE);
            for (int i = 0; i &amp;lt; SIZE; i++) {
                hashMap.put(i, i);
            }

            // TreeMap 준비
            Map&amp;lt;Integer, Integer&amp;gt; treeMap = new TreeMap&amp;lt;&amp;gt;();
            for (int i = 0; i &amp;lt; SIZE; i++) {
                treeMap.put(i, i);
            }

            // ArrayList 준비
            List&amp;lt;Integer&amp;gt; arrayList = new ArrayList&amp;lt;&amp;gt;(SIZE);
            for (int i = 0; i &amp;lt; SIZE; i++) {
                arrayList.add(i);
            }

            // JIT 최적화 방지 및 GC 영향 제거
            int sum = 0;
            System.gc();

            // HashMap 접근 시간
            long startHash = System.nanoTime();
            for (int i = 0; i &amp;lt; SIZE; i++) {
                sum += hashMap.get(i); // 최적화 방지
            }
            long endHash = System.nanoTime();
            System.out.println(&quot;HashMap 조회 시간(ns): \t\t&quot; + (endHash - startHash));

            // TreeMap 접근 시간
            long startTree = System.nanoTime();
            for (int i = 0; i &amp;lt; SIZE; i++) {
                sum += treeMap.get(i); // 최적화 방지
            }
            long endTree = System.nanoTime();
            System.out.println(&quot;TreeMap 조회 시간(ns): \t\t&quot; + (endTree - startTree) + 
                               &quot; (logN: &quot; + String.format(&quot;%.2f&quot;, Math.log(SIZE) / Math.log(2)) + &quot;)&quot;);

            // ArrayList 접근 시간
            long startList = System.nanoTime();
            for (int i = 0; i &amp;lt; SIZE; i++) {
                sum += arrayList.get(i); // 최적화 방지
            }
            long endList = System.nanoTime();
            System.out.println(&quot;ArrayList 조회 시간(ns): \t&quot; + (endList - startList));

            // 결과 확인
            System.out.println(&quot;검증용 sum 값: &quot; + sum);
            System.out.println();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ArrayList 접근 시간은 gc나 JIT 컴파일러로 인한 오버헤드나 최적화 등을 고려해서 코드를 구성했다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9ETuY/btsMnmXrcPc/Kfhyn8OiseHu2pKP6Z3dPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9ETuY/btsMnmXrcPc/Kfhyn8OiseHu2pKP6Z3dPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9ETuY/btsMnmXrcPc/Kfhyn8OiseHu2pKP6Z3dPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9ETuY%2FbtsMnmXrcPc%2FKfhyn8OiseHu2pKP6Z3dPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;647&quot; height=&quot;393&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&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;TreeMap이 HashMap 에 비해서 터무니없이 느릴수 있다 생각할수 있지만 테스트 1의 경우를 미루어 보면 최악의 HashMap(충돌)에 비해서는 평균적으로 준수한 성능을 낸다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2016&quot; data-start=&quot;1919&quot;&gt;&lt;b&gt;ArrayList (O(1))&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2016&quot; data-start=&quot;1950&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1983&quot; data-start=&quot;1950&quot;&gt;단순한 배열 인덱스 접근 &amp;rarr; &lt;b&gt;캐시 친화적 &amp;amp; 빠름&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2013&quot; data-start=&quot;1987&quot;&gt;데이터 크기 증가해도 성능 저하 거의 없음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;2115&quot; data-start=&quot;2017&quot;&gt;&lt;b&gt;HashMap (O(1) 평균, O(n) 최악)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2115&quot; data-start=&quot;2058&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2080&quot; data-start=&quot;2058&quot;&gt;일반적으로 해시 충돌이 적으면 빠름.&lt;/li&gt;
&lt;li data-end=&quot;2112&quot; data-start=&quot;2084&quot;&gt;충돌이 많아질수록 성능이 저하될 가능성이 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;2295&quot; data-start=&quot;2116&quot;&gt;&lt;b&gt;TreeMap (O(log n))&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2295&quot; data-start=&quot;2149&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2192&quot; data-start=&quot;2149&quot;&gt;내부적으로 &lt;b&gt;Red-Black Tree&lt;/b&gt;(균형 이진 탐색 트리) 사용.&lt;/li&gt;
&lt;li data-end=&quot;2225&quot; data-start=&quot;2196&quot;&gt;조회 성능이 항상 O(log n)으로 유지됨.&lt;/li&gt;
&lt;li data-end=&quot;2295&quot; data-start=&quot;2229&quot;&gt;데이터 크기가 커질수록 HashMap보다 느리지만, 최악의 경우에는 HashMap보다 안정적인 성능을 유지.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;h4 data-ke-size=&quot;size20&quot;&gt;그래서 언제 뭘 써야하나?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2926&quot; data-start=&quot;2835&quot;&gt;&lt;b&gt;데이터 크기가 작을 때&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2926&quot; data-start=&quot;2861&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2895&quot; data-start=&quot;2861&quot;&gt;HashMap &amp;gt; TreeMap (둘 다 빠름)&lt;/li&gt;
&lt;li data-end=&quot;2926&quot; data-start=&quot;2899&quot;&gt;ArrayList는 인덱스 조회용으로 유리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;3096&quot; data-start=&quot;2928&quot;&gt;&lt;b&gt;데이터 크기가 클 때&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3096&quot; data-start=&quot;2953&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3008&quot; data-start=&quot;2953&quot;&gt;TreeMap은 항상 O(log n), 성능이 일정하지만 HashMap보다 느림.&lt;/li&gt;
&lt;li data-end=&quot;3058&quot; data-start=&quot;3012&quot;&gt;HashMap은 충돌이 많으면 TreeMap보다 더 느려질 수 있음.&lt;/li&gt;
&lt;li data-end=&quot;3096&quot; data-start=&quot;3062&quot;&gt;ArrayList는 &lt;b&gt;조회가 많을 때 가장 빠름&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;3168&quot; data-start=&quot;3098&quot;&gt;&lt;b&gt;정렬이 필요하면?&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3168&quot; data-start=&quot;3120&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3168&quot; data-start=&quot;3120&quot;&gt;TreeMap은 정렬된 데이터를 유지하므로 &lt;b&gt;탐색이 빈번한 경우에는 유용&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;4. 해결책 또는 예방법&lt;/h3&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;TreeMap 활용&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HashMap 최적화 파라미터 조정&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;참조 지역성 개선&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이라고 제시를 해주고 있지만 코드포스나 자유게시판의 글을 확인 해보면&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1164&quot; data-start=&quot;1129&quot;&gt;&lt;b&gt;데이터가 지나치게 많거나&lt;/b&gt;(예: 수천만 건 이상),&lt;/li&gt;
&lt;li data-end=&quot;1208&quot; data-start=&quot;1165&quot;&gt;&lt;b&gt;해시 저격 패턴&lt;/b&gt;(Adversarial input)이 의심될 때,&lt;/li&gt;
&lt;li data-end=&quot;1241&quot; data-start=&quot;1209&quot;&gt;&lt;b&gt;N^2 루프&lt;/b&gt;만으로도 충분히 시간을 먹을 때,&lt;/li&gt;
&lt;li data-end=&quot;1362&quot; data-start=&quot;1242&quot;&gt;해시의 상수 오버헤드나 최악 상황이 부담스러울 때,
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1362&quot; data-start=&quot;1277&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1362&quot; data-start=&quot;1277&quot;&gt;이럴 땐 정렬+이분 탐색(O(N^2 log N)), 투 포인터, 혹은 다른 자료구조(Map, TreeMap, Segment Tree 등)를 고려한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&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;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;4645&quot; data-start=&quot;4037&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;4211&quot; data-start=&quot;4037&quot;&gt;&lt;b&gt;입력 데이터 특성 파악&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4211&quot; data-start=&quot;4062&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4135&quot; data-start=&quot;4062&quot;&gt;키가 특정 패턴으로 몰리지 않도록, 혹은 악의적 패턴을 방어하고 싶다면 &lt;b&gt;커스텀 해시 함수&lt;/b&gt;를 강화(더 균등하게)하거나,&lt;/li&gt;
&lt;li data-end=&quot;4211&quot; data-start=&quot;4139&quot;&gt;해싱 대신 &lt;b&gt;정렬 + 이분 탐색(TreeMap, Arrays.binarySearch 등)&lt;/b&gt; 같은 다른 알고리즘을 검토한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;4317&quot; data-start=&quot;4213&quot;&gt;&lt;b&gt;TreeMap 활용&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4317&quot; data-start=&quot;4236&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4276&quot; data-start=&quot;4236&quot;&gt;항상 O(log N) 복잡도이며, 해시 충돌 걱정을 덜 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;4317&quot; data-start=&quot;4280&quot;&gt;다만 평균적으로 HashMap보다는 상수 시간 비용이 크다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;4461&quot; data-start=&quot;4319&quot;&gt;&lt;b&gt;HashMap 최적화 파라미터&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4461&quot; data-start=&quot;4348&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4429&quot; data-start=&quot;4348&quot;&gt;초기 용량(capacity)을 여유롭게 잡고, 적절한 부하율(load factor)을 설정하면 재해시(rehash) 횟수를 줄일 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;4461&quot; data-start=&quot;4433&quot;&gt;그러나 해시 충돌 입력 자체를 해결하진 못한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;4645&quot; data-start=&quot;4463&quot;&gt;&lt;b&gt;참조 지역성 개선&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4645&quot; data-start=&quot;4485&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4568&quot; data-start=&quot;4485&quot;&gt;객체 접근이 분산되지 않도록, 자료구조 선택 시 &lt;b&gt;연속적 메모리&lt;/b&gt;를 최대한 활용하면 캐시 효율이 올라간다(예: 배열, ArrayList).&lt;/li&gt;
&lt;li data-end=&quot;4645&quot; data-start=&quot;4572&quot;&gt;해시맵이 불가피하다면, 무작정 큰 N 데이터가 들어오지 않도록 제한을 두거나, 다른 알고리즘으로 문제를 풀 수 있는지 고려한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Java</category>
      <category>hash 충돌</category>
      <category>treemap 성능 테스트</category>
      <category>자바 해시 충돌</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/236</guid>
      <comments>https://nstgic3.tistory.com/entry/%ED%95%B4%EC%8B%9C-%EC%B6%A9%EB%8F%8C%EA%B3%BC-%EC%B0%B8%EC%A1%B0-%EC%A7%80%EC%97%AD%EC%84%B1-%EC%9E%90%EB%B0%94-HashMap-%EC%84%B1%EB%8A%A5-%EC%A0%80%ED%95%98-%EC%BC%80%EC%9D%B4%EC%8A%A4#entry236comment</comments>
      <pubDate>Wed, 19 Feb 2025 14:19:49 +0900</pubDate>
    </item>
    <item>
      <title>자바8 람다와 함수형 인터페이스 [3] : 디슈거링을 통한 메서드 변환과 MethodHandle, 바이트코드/JVM 분석</title>
      <link>https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%948-%EB%9E%8C%EB%8B%A4%EC%99%80-%ED%95%A8%EC%88%98%ED%98%95-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-3-%EB%94%94%EC%8A%88%EA%B1%B0%EB%A7%81%EC%9D%84-%ED%86%B5%ED%95%9C-%EB%A9%94%EC%84%9C%EB%93%9C-%EB%B3%80%ED%99%98%EA%B3%BC-MethodHandle-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9CJVM-%EB%B6%84%EC%84%9D</link>
      <description>&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8에서 람다 표현식은 기존의 익명 클래스 방식과 다르게&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 익명 클래스를 생성하지 않고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 바이트코드 수준에서 최적화된다.&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;그럼에도 불구하고 개발자들이 람다라는 표현식의 성능 최적화를 위해 어떻게 이를 구현했는지 바이트코드 분석을 통해 알아보자.&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;&lt;b&gt;디슈거링(Desugaring)&lt;/b&gt;이 수행되며, 람다 표현식은 일반적인 정적 메서드로 변환된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후, 실행 시점에서 `invokedynamic` 바이트코드를 활용하여 동적으로 `MethodHandle`을 참조하게 된다.&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;디슈거링(Desugaring) 개념&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8에서 람다 표현식은 내부적으로 &lt;b&gt;익명 클래스를 생성하지 않고&lt;/b&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;디슈거링(desugaring)&lt;/b&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;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;익명 클래스로 변환되는 것이 아니라&lt;/b&gt; 일반적인 정적 메서드나 인스턴스 메서드로 변환&lt;/span&gt;되며, &lt;b&gt;실제 실행될 때는 invokedynamic 바이트코드를 활용하여 메서드 핸들을 참조&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;&lt;b&gt;요약&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;자바 8 이전에는 람다 대신 익명 클래스를 사용해야 했음.&lt;/li&gt;
&lt;li&gt;자바 8 이후 람다는 컴파일러에 의해 일반 메서드로 변환됨.&lt;/li&gt;
&lt;li&gt;실제 실행 시점에는 `invokedynamic`을 활용하여 `MethodHandle`을 참조&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;람다 표현식의 디슈거링 예제&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cygSjH/btsMdrLvs8G/triwOer4YwgKXLGu6IdO20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cygSjH/btsMdrLvs8G/triwOer4YwgKXLGu6IdO20/img.png&quot; data-alt=&quot;단순히 받아온 문자열의 길이를 출력하는 람다식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cygSjH/btsMdrLvs8G/triwOer4YwgKXLGu6IdO20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcygSjH%2FbtsMdrLvs8G%2FtriwOer4YwgKXLGu6IdO20%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;236&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;단순히 받아온 문자열의 길이를 출력하는 람다식&lt;/figcaption&gt;
&lt;/figure&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;위의 람다 표현식 (s -&amp;gt; s.length()) 은 &lt;b&gt;컴파일 후 어떻게 변환될까?&lt;/b&gt;&lt;br /&gt;이를 이해하기 위해,&amp;nbsp; 컴파일 후&lt;b&gt;Javap 도구를 이용해 바이트코드를 분석&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;컴파일 후 바이트코드 분석 (`javap` 활용)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FJM18/btsMetV4QD4/4ndQ47vlozGO7cHl88MsbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FJM18/btsMetV4QD4/4ndQ47vlozGO7cHl88MsbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FJM18/btsMetV4QD4/4ndQ47vlozGO7cHl88MsbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFJM18%2FbtsMetV4QD4%2F4ndQ47vlozGO7cHl88MsbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;835&quot; height=&quot;483&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;`invokedynamic`와 `LambdaMetafactory`&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다 표현식이 사용된 곳에서 &lt;b&gt;invokedynamic 바이트코드가&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;자바 8에서는 invokedynamic을 통해 &lt;b&gt;동적으로 메서드를 찾아 실행&lt;/b&gt;할 수 있으며, &lt;b&gt;람다 표현식의 메서드 핸들을 생성하는 역할&lt;/b&gt;을 LambdaMetafactory가 담당한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;149&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgudH1/btsMd16R6wy/PkezYSmkKBzFcDVeSt0ND1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgudH1/btsMd16R6wy/PkezYSmkKBzFcDVeSt0ND1/img.png&quot; data-alt=&quot;JVM : invokedynamic 이 호출되면 MethodHandle을 사용하여 최적의 메서드를 찾음, DirectMethodHandle 은 메서드 호출을 더욱 빠르게 수행하도록 최적화 .&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgudH1/btsMd16R6wy/PkezYSmkKBzFcDVeSt0ND1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgudH1%2FbtsMd16R6wy%2FPkezYSmkKBzFcDVeSt0ND1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1274&quot; height=&quot;149&quot; data-origin-width=&quot;1274&quot; data-origin-height=&quot;149&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JVM : invokedynamic 이 호출되면 MethodHandle을 사용하여 최적의 메서드를 찾음, DirectMethodHandle 은 메서드 호출을 더욱 빠르게 수행하도록 최적화 .&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1205&quot; data-origin-height=&quot;129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9eWZo/btsMe3QdJl4/B58Wj250bQsufP4LfPsMa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9eWZo/btsMe3QdJl4/B58Wj250bQsufP4LfPsMa0/img.png&quot; data-alt=&quot;JVM : LambdaMetafactory 는 invokedynamic이 실행될 때 호출되는 핵심 클래스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9eWZo/btsMe3QdJl4/B58Wj250bQsufP4LfPsMa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9eWZo%2FbtsMe3QdJl4%2FB58Wj250bQsufP4LfPsMa0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1205&quot; height=&quot;129&quot; data-origin-width=&quot;1205&quot; data-origin-height=&quot;129&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JVM : LambdaMetafactory 는 invokedynamic이 실행될 때 호출되는 핵심 클래스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  &lt;b&gt;컴파일러는 다음과 같은 변환을 수행한다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. LambdaDesugaringExample 클래스에 새로운 정적 메서드를 생성한다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;109&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bf0i89/btsMewZqfzn/efcS6EI1ZxPNJR26ieWZdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bf0i89/btsMewZqfzn/efcS6EI1ZxPNJR26ieWZdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bf0i89/btsMewZqfzn/efcS6EI1ZxPNJR26ieWZdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbf0i89%2FbtsMewZqfzn%2FefcS6EI1ZxPNJR26ieWZdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;809&quot; height=&quot;109&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;109&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1739259759306&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private static Integer lambda$s$0(String s) {
    return s.length();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;156&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbX7vM/btsMffv8kUO/d32e7GQyX6ecSfsiEXwI80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbX7vM/btsMffv8kUO/d32e7GQyX6ecSfsiEXwI80/img.png&quot; data-alt=&quot;JVM: InnerClassLambdaMetafactory 는 람다를 내부 클래스로 변환하는 역할&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbX7vM/btsMffv8kUO/d32e7GQyX6ecSfsiEXwI80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbX7vM%2FbtsMffv8kUO%2Fd32e7GQyX6ecSfsiEXwI80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1220&quot; height=&quot;156&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;156&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JVM: InnerClassLambdaMetafactory 는 람다를 내부 클래스로 변환하는 역할&lt;/figcaption&gt;
&lt;/figure&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;2. invokedynamic을 사용하여 LambdaMetafactory에서 메서드 핸들을 생성하고 이를 Function&amp;lt;String, Integer&amp;gt; 타입으로 반환한다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1095&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eh4mfT/btsMemQiyKT/alHpPfLYKhI04K119J4tK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eh4mfT/btsMemQiyKT/alHpPfLYKhI04K119J4tK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eh4mfT/btsMemQiyKT/alHpPfLYKhI04K119J4tK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Feh4mfT%2FbtsMemQiyKT%2FalHpPfLYKhI04K119J4tK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1095&quot; height=&quot;78&quot; data-origin-width=&quot;1095&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C2R29/btsMe9pbNGv/kcpUnq5Ows55wvYCE6Y290/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C2R29/btsMe9pbNGv/kcpUnq5Ows55wvYCE6Y290/img.png&quot; data-alt=&quot;JVM : MethodHandleImpl : 최적화된 메서드 핸들 구현체&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C2R29/btsMe9pbNGv/kcpUnq5Ows55wvYCE6Y290/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC2R29%2FbtsMe9pbNGv%2FkcpUnq5Ows55wvYCE6Y290%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1172&quot; height=&quot;135&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JVM : MethodHandleImpl : 최적화된 메서드 핸들 구현체&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&lt;b&gt;3. 실제 실행 시, invokedynamic은 lambda$s$0을 호출하도록 MethodHandle을 연결한다.&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1322&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ummXt/btsMe2w0ieb/TMMbY2uLc4gxeIr5DPotz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ummXt/btsMe2w0ieb/TMMbY2uLc4gxeIr5DPotz0/img.png&quot; data-alt=&quot;JVM : 바이트 코드로 변환&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ummXt/btsMe2w0ieb/TMMbY2uLc4gxeIr5DPotz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FummXt%2FbtsMe2w0ieb%2FTMMbY2uLc4gxeIr5DPotz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1322&quot; height=&quot;436&quot; data-origin-width=&quot;1322&quot; data-origin-height=&quot;436&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JVM : 바이트 코드로 변환&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;MethodHandle이 활용되는 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;런타임 성능 최적화 가능&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MethodHandle을 사용하면 &lt;b&gt;JVM이 실행 중에 동적으로 최적화 (Inlining)할 수 있다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;기존의 익명 클래스 방식보다 더 효율적인 코드가 생성된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;람다를 일반 메서드처럼 표현 가능&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;람다는 내부적으로 MethodHandle을 통해 정적 메서드처럼 다룰 수 있어 JVM이 쉽게 인라인(inline)할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;불필요한 익명 클래스 생성을 피함&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존에는 익명 클래스를 사용했으나, invokedynamic을 사용하면 불필요한 클래스 파일이 생성되지 않아 &lt;b&gt;클래스 로딩 비용이 감소&lt;/b&gt;한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8에서 람다는 단순한 문법적 변화가 아니라 &lt;b&gt;JVM 수준에서 최적화된 방식으로 동작&lt;/b&gt;한다.&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;람다 표현식은 컴파일 시점에 일반 메서드로 변환된다 (디슈거링).&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴파일된 바이트코드는 invokedynamic을 사용하여 MethodHandle을 참조한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행 시점에 LambdaMetafactory를 통해 람다 메서드를 연결하고 최적화된 방식으로 실행된다.&lt;/b&gt;&lt;/li&gt;
&lt;/ol&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 1: 바이트 코드 수준에서 함수 호출을 어떻게 표현할 것인가?&lt;/b&gt;&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;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ &lt;b&gt;해결 방법&lt;/b&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;b&gt;invokedynamic + LambdaMetafactory를 사용하여 동적 메서드 핸들링을 수행.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;컴파일러가 &lt;b&gt;람다 표현식을 일반 메서드로 변환(디슈거링)&lt;/b&gt; 하고, &lt;b&gt;바이트코드에서 invokedynamic을 사용해 동적으로 메서드 핸들을 참조&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;&lt;b&gt;문제 2: 함수 타입 변수의 인스턴스는 어떻게 만들 것인가?&lt;/b&gt;&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;Comparator, Runnable 같은 인터페이스를 익명 클래스로 구현하여 객체를 생성.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ &lt;b&gt;해결 방법&lt;/b&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;b&gt;람다는 Functional Interface의 인스턴스로 변환되도록 설계.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;기존의 Comparator, Runnable, Callable 같은 단일 메서드 인터페이스를 활용하여 람다를 쉽게 적용.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기존 API와 호환 가능하도록 유지.&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;&lt;b&gt;문제 3: 변성(Variance) 처리는 어떻게 할 것인가?&lt;/b&gt;&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;익명 클래스 기반의 방식에서는 타입 매개변수(Generics)의 변성이 명확했음.&lt;/li&gt;
&lt;li&gt;람다 표현식을 도입하면, 해당 타입 정보를 정확하게 유지할 필요가 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ &lt;b&gt;해결 방법&lt;/b&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;b&gt;컴파일러가 Functional Interface의 타입 정보를 유지하면서, 람다를 특정 타입으로 변환.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;타입 시스템을 복잡하게 만들지 않기 위해 &lt;b&gt;람다를 항상 Functional Interface의 인스턴스로 변환하도록 설계.&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;&lt;b&gt;문제 4: 새로운 Function Type을 추가하면 어떤 문제가 발생할까?&lt;/b&gt;&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;Callable&amp;lt;T&amp;gt;, Runnable 같은 인터페이스를 사용했지만, 새로운 함수 타입을 추가하려면 새로운 바이트코드 및 시그니처가 필요함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❌ &lt;b&gt;대안 검토 (실패)&lt;/b&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;Function Type&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;/li&gt;
&lt;li&gt;&lt;b&gt;런타임에서 복잡한 타입 추론 문제&lt;/b&gt; 발생.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ &lt;b&gt;해결 방법&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 Function Type을 추가하는 대신, 기존의 &lt;b&gt;인터페이스 기반 Functional Interface를 재활용.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&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;&lt;b&gt;문제 5: JVM에서 람다 표현식을 효율적으로 실행할 방법?&lt;/b&gt;&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;b&gt;클래스 로딩 비용 증가&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;불필요한 객체 생성과 메모리 사용 증가.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ &lt;b&gt;해결 방법&lt;/b&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;b&gt;람다를 MethodHandle을 활용하여 실행할 수 있도록 invokedynamic 사용.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;실행 시점에 LambdaMetafactory를 통해 최적의 구현을 동적으로 결정.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JVM이 필요할 때만 인스턴스를 생성하여 메모리 사용 최적화.&lt;br /&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 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;a href=&quot;https://cr.openjdk.org/~briangoetz/lambda/lambda-translation.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cr.openjdk.org/~briangoetz/lambda/lambda-translation.html&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1739262936856&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Translation of Lambda Expressions&quot; data-og-description=&quot;Translation of Lambda Expressions April 2012 &amp;lt;!-- This document is in Markdown format: http://daringfireball.net/projects/markdown/ [title]: Translation of Lambda Expressions Changes from version dated January 2012 - removed support for recursive lambdas a&quot; data-og-host=&quot;cr.openjdk.org&quot; data-og-source-url=&quot;https://cr.openjdk.org/~briangoetz/lambda/lambda-translation.html&quot; data-og-url=&quot;https://cr.openjdk.org/~briangoetz/lambda/lambda-translation.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://cr.openjdk.org/~briangoetz/lambda/lambda-translation.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cr.openjdk.org/~briangoetz/lambda/lambda-translation.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Translation of Lambda Expressions&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Translation of Lambda Expressions April 2012 &amp;lt;!-- This document is in Markdown format: http://daringfireball.net/projects/markdown/ [title]: Translation of Lambda Expressions Changes from version dated January 2012 - removed support for recursive lambdas a&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cr.openjdk.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>디슈거링</category>
      <category>람다 내부 동작</category>
      <category>메서드 핸들</category>
      <category>바이트 코드 분석</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/235</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%948-%EB%9E%8C%EB%8B%A4%EC%99%80-%ED%95%A8%EC%88%98%ED%98%95-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-3-%EB%94%94%EC%8A%88%EA%B1%B0%EB%A7%81%EC%9D%84-%ED%86%B5%ED%95%9C-%EB%A9%94%EC%84%9C%EB%93%9C-%EB%B3%80%ED%99%98%EA%B3%BC-MethodHandle-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9CJVM-%EB%B6%84%EC%84%9D#entry235comment</comments>
      <pubDate>Tue, 11 Feb 2025 17:27:00 +0900</pubDate>
    </item>
    <item>
      <title>자바8 람다와 함수형 인터페이스 [2] : @FunctionalInterface 구현체 작성법(람다 표현식)</title>
      <link>https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%948-%EB%9E%8C%EB%8B%A4%EC%99%80-%ED%95%A8%EC%88%98%ED%98%95-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-2-FunctionalInterface-%EA%B5%AC%ED%98%84%EC%B2%B4-%EC%9E%91%EC%84%B1%EB%B2%95%EB%9E%8C%EB%8B%A4-%ED%91%9C%ED%98%84%EC%8B%9D</link>
      <description>&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8의 핵심 기능 중 하나인 람다 표현식과 함수형 인터페이스의 개념을 살펴본데에 이어,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@FunctionalInterface 구현체의 작성법과 생략 가능한 메서드 등을 통해서 람다 표현에 대해 익숙해진다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;258&quot; data-start=&quot;177&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;260&quot; data-ke-size=&quot;size16&quot;&gt;또한, 이펙티브 자바 7장 아이템 44에서는 &lt;b&gt;함수형 인터페이스를 직접 만들 경우&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;260&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; @FunctionalInterface 애너테이션을 반드시 사용하라&lt;/b&gt;고 권장한다. 그 이유는 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;532&quot; data-start=&quot;372&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;422&quot; data-start=&quot;372&quot;&gt;&lt;b&gt;의도 명확성&lt;/b&gt; &amp;ndash; 해당 인터페이스가 람다 용도로 설계되었음을 명확히 알린다.&lt;/li&gt;
&lt;li data-end=&quot;475&quot; data-start=&quot;423&quot;&gt;&lt;b&gt;컴파일러 검증&lt;/b&gt; &amp;ndash; 인터페이스가 정확히 하나의 추상 메서드만 가지도록 강제한다.&lt;/li&gt;
&lt;li data-end=&quot;532&quot; data-start=&quot;476&quot;&gt;&lt;b&gt;유지보수성 향상&lt;/b&gt; &amp;ndash; 실수로 메서드를 추가하는 것을 방지하여, 코드의 안정성을 높인다.&lt;/li&gt;
&lt;/ol&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;꼭 직접 만들어야하나? Effective Java Item 44&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아이템 44에서는 람다 표현식을 활용할 때는 &lt;b&gt;표준 함수형 인터페이스&lt;/b&gt;(Consumer&amp;lt;T&amp;gt;, Function&amp;lt;T,R&amp;gt;, Predicate&amp;lt;T&amp;gt;, Supplier&amp;lt;T&amp;gt; 등)를 최대한 활용하는 것이 좋다고 나와있다.&lt;/p&gt;
&lt;p data-end=&quot;246&quot; data-start=&quot;166&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;246&quot; data-start=&quot;166&quot; data-ke-size=&quot;size16&quot;&gt;하지만, &lt;b&gt;표준 인터페이스가 적절하지 않은 경우에는 직접 만들어야 하고 언제 만들어야되는지에 대해서 간단히 나와있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;246&quot; data-start=&quot;166&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;1084&quot; data-start=&quot;1048&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1️⃣ 매개변수가 표준 인터페이스보다 더 많을 때&lt;/b&gt;&lt;/h4&gt;
&lt;p data-end=&quot;1158&quot; data-start=&quot;1085&quot; data-ke-size=&quot;size16&quot;&gt;표준 인터페이스는 최대 2개의 매개변수(BiFunction&amp;lt;T, U, R&amp;gt; 등)만 제공하지만, 그 이상이 필요할 수도 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;1158&quot; data-start=&quot;1085&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;1652&quot; data-start=&quot;1606&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2️⃣ 검사 예외(Checked Exception)를 던져야 할 때&lt;/b&gt;&lt;/h4&gt;
&lt;p data-end=&quot;1717&quot; data-start=&quot;1653&quot; data-ke-size=&quot;size16&quot;&gt;표준 함수형 인터페이스는 throws를 지원하지 않으므로, 검사 예외를 던져야 하는 경우 직접 만들어야 합니다.&lt;/p&gt;
&lt;p data-end=&quot;1717&quot; data-start=&quot;1653&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;2486&quot; data-start=&quot;2452&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3️⃣ 특정 도메인에 특화된 기능을 제공할 때&lt;/b&gt;&lt;/h4&gt;
&lt;p data-end=&quot;2514&quot; data-start=&quot;2487&quot; data-ke-size=&quot;size16&quot;&gt;대표적인 예가 Comparator&amp;lt;T&amp;gt;라고 한다.&lt;/p&gt;
&lt;p data-end=&quot;2639&quot; data-start=&quot;2516&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;표준 인터페이스인 ToIntBiFunction&amp;lt;T, U&amp;gt;로도 비교는 가능하지만, 왜 Comparator&amp;lt;T&amp;gt;가 따로 존재할까라고 질문을 던지고 있는데,&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2639&quot; data-start=&quot;2516&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2639&quot; data-start=&quot;2516&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2882&quot; data-start=&quot;2641&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  Comparator&amp;lt;T&amp;gt;가 별도의 인터페이스로 존재하는 이유&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li data-end=&quot;2882&quot; data-start=&quot;2641&quot;&gt;API에서 매우 자주 사용되며, &quot;Comparator&quot;라는 이름이 &lt;b&gt;용도를 명확하게 설명&lt;/b&gt;해준다.&lt;/li&gt;
&lt;li data-end=&quot;2882&quot; data-start=&quot;2641&quot;&gt;비교 연산은 반드시 대칭성(transitivity)과 일관성을 유지해야 하는 &lt;b&gt;규약이 있다.&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2882&quot; data-start=&quot;2641&quot;&gt;reversed(), thenComparing() 등 비교자 변환 및 조합을 위한 &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: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;커스텀 @FunctionalInterface 생성&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 설명했다싶이,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/reKoq/btsMc1lYWei/wiaKEfHmfeU2X4J3KV3N7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/reKoq/btsMc1lYWei/wiaKEfHmfeU2X4J3KV3N7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/reKoq/btsMc1lYWei/wiaKEfHmfeU2X4J3KV3N7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FreKoq%2FbtsMc1lYWei%2FwiaKEfHmfeU2X4J3KV3N7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;804&quot; height=&quot;238&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;238&quot;/&gt;&lt;/span&gt;&lt;/figure&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;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;&lt;b&gt;@FunctionalInterface 규칙으로 &lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;오직 &lt;/span&gt;&lt;b&gt;하나의 추상 메서드&lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;만 가질 수 있지만 여기서는 &lt;/span&gt;toString(), equals() 또한 존재함을 확인 할수 있다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;오류가 나지 않는 이유는 toString()과 equals()는 사실 Object 클래스에서 기본으로 제공되므로, &lt;b&gt;추상 메서드로 간주되지 않기 때문이다.&lt;br /&gt;&lt;br /&gt;하지만,&amp;nbsp; 원래 Object 클래스에서 제공되므로, 굳이 명시할 필요 없다고 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://dzone.com/articles/java-8-functional-interfaces-sam&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dzone.com/articles/java-8-functional-interfaces-sam&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1739254477944&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Java 8 &amp;mdash; Functional Interfaces (SAM)&quot; data-og-description=&quot; &quot; data-og-host=&quot;dzone.com&quot; data-og-source-url=&quot;https://dzone.com/articles/java-8-functional-interfaces-sam&quot; data-og-url=&quot;https://dzone.com/articles/java-8-functional-interfaces-sam&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eIYbg/hyYfYIsLgM/j0H8H3SUKMhJrth4DBfzP0/img.jpg?width=546&amp;amp;height=341&amp;amp;face=0_0_546_341,https://scrap.kakaocdn.net/dn/eyoNr/hyYfXv1a9F/1wfbCQ3VK0u1UPATuwQZuK/img.jpg?width=546&amp;amp;height=341&amp;amp;face=0_0_546_341&quot;&gt;&lt;a href=&quot;https://dzone.com/articles/java-8-functional-interfaces-sam&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dzone.com/articles/java-8-functional-interfaces-sam&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eIYbg/hyYfYIsLgM/j0H8H3SUKMhJrth4DBfzP0/img.jpg?width=546&amp;amp;height=341&amp;amp;face=0_0_546_341,https://scrap.kakaocdn.net/dn/eyoNr/hyYfXv1a9F/1wfbCQ3VK0u1UPATuwQZuK/img.jpg?width=546&amp;amp;height=341&amp;amp;face=0_0_546_341');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Java 8 &amp;mdash; Functional Interfaces (SAM)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dzone.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;커스텀&amp;nbsp; @FunctionalInterface&lt;span&gt;&amp;nbsp; 구현체 생성&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;397&quot; data-start=&quot;373&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1️⃣ 익명클래스(람다 X)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;326&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I6zIY/btsMe2DCqbC/qQNV9pGFtYDkzXpNO74jxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I6zIY/btsMe2DCqbC/qQNV9pGFtYDkzXpNO74jxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I6zIY/btsMe2DCqbC/qQNV9pGFtYDkzXpNO74jxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI6zIY%2FbtsMe2DCqbC%2FqQNV9pGFtYDkzXpNO74jxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;854&quot; height=&quot;326&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;326&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-end=&quot;397&quot; data-start=&quot;373&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-end=&quot;397&quot; data-start=&quot;373&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2️⃣ 기본 람다 표현식 예제&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCWnqz/btsMc1sLYZM/1rj8JRUqFUx67LjRu9EBlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCWnqz/btsMc1sLYZM/1rj8JRUqFUx67LjRu9EBlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCWnqz/btsMc1sLYZM/1rj8JRUqFUx67LjRu9EBlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCWnqz%2FbtsMc1sLYZM%2F1rj8JRUqFUx67LjRu9EBlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;803&quot; height=&quot;252&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;803&quot; data-start=&quot;719&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;780&quot; data-start=&quot;719&quot;&gt;(String str) -&amp;gt; { System.out.println(str); } 형식으로 람다를 사용.&lt;/li&gt;
&lt;li data-end=&quot;803&quot; data-start=&quot;781&quot;&gt;accept()를 호출하여 실행.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;808&quot; data-start=&quot;805&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;835&quot; data-start=&quot;810&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3️⃣ 매개변수 타입 생략 가능&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKZYmi/btsMfl3Qsm2/f5SKi1whiwK9YMc5pMQfu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKZYmi/btsMfl3Qsm2/f5SKi1whiwK9YMc5pMQfu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKZYmi/btsMfl3Qsm2/f5SKi1whiwK9YMc5pMQfu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKZYmi%2FbtsMfl3Qsm2%2Ff5SKi1whiwK9YMc5pMQfu1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;790&quot; height=&quot;241&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;241&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1160&quot; data-start=&quot;1103&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1160&quot; data-start=&quot;1103&quot;&gt;자바는 타입을 &lt;b&gt;자동 추론&lt;/b&gt;하므로 (String str) 대신 (str) 만 사용 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1165&quot; data-start=&quot;1162&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1210&quot; data-start=&quot;1167&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4️⃣ 매개변수와 실행문이 하나일 경우 괄호와 중괄호 생략 가능&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;165&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GMwnz/btsMdpfLhpf/KHKkFykB8SbKwb5BgC7ge0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GMwnz/btsMdpfLhpf/KHKkFykB8SbKwb5BgC7ge0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GMwnz/btsMdpfLhpf/KHKkFykB8SbKwb5BgC7ge0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGMwnz%2FbtsMdpfLhpf%2FKHKkFykB8SbKwb5BgC7ge0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;809&quot; height=&quot;165&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;165&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;243&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JlyDP/btsMfiMOtc3/Mel5G5w7aveyYKoaSMz4n0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JlyDP/btsMfiMOtc3/Mel5G5w7aveyYKoaSMz4n0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JlyDP/btsMfiMOtc3/Mel5G5w7aveyYKoaSMz4n0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJlyDP%2FbtsMfiMOtc3%2FMel5G5w7aveyYKoaSMz4n0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;755&quot; height=&quot;243&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;243&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;괄호, 중괄호 생략 가능!&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1528&quot; data-start=&quot;1481&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1528&quot; data-start=&quot;1481&quot;&gt;매개변수와 실행문이 &lt;b&gt;각각 하나일 경우&lt;/b&gt;, &lt;b&gt;괄호와 {} 생략 가능&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1533&quot; data-start=&quot;1530&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1569&quot; data-start=&quot;1535&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5️⃣ 리턴이 필요한 경우 return 사용&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chBL9V/btsMevsIEaP/nCFw2N4oxofebeYw0DzMA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chBL9V/btsMevsIEaP/nCFw2N4oxofebeYw0DzMA0/img.png&quot; data-alt=&quot;리턴값이 생성되었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chBL9V/btsMevsIEaP/nCFw2N4oxofebeYw0DzMA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchBL9V%2FbtsMevsIEaP%2FnCFw2N4oxofebeYw0DzMA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;619&quot; height=&quot;180&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;180&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;리턴값이 생성되었다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YIaH7/btsMd5agNLJ/PxYcMLMfE7ThAqwebTpAH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YIaH7/btsMd5agNLJ/PxYcMLMfE7ThAqwebTpAH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YIaH7/btsMd5agNLJ/PxYcMLMfE7ThAqwebTpAH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYIaH7%2FbtsMd5agNLJ%2FPxYcMLMfE7ThAqwebTpAH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;697&quot; height=&quot;387&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;387&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2132&quot; data-start=&quot;2032&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2099&quot; data-start=&quot;2032&quot;&gt;Consumer&amp;lt;T&amp;gt;는 &lt;b&gt;리턴값이 없지만&lt;/b&gt;, 리턴이 필요한 경우 Function&amp;lt;T, R&amp;gt;처럼 변형 가능.&lt;/li&gt;
&lt;li data-end=&quot;2132&quot; data-start=&quot;2100&quot;&gt;return이 필요한 경우 {}을 사용해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2137&quot; data-start=&quot;2134&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2181&quot; data-start=&quot;2139&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6️⃣ 리턴문만 있는 경우 중괄호와 return 생략 가능&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7hJEl/btsMesCKNpW/WRDoEWK7DluZcgS4jz87fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7hJEl/btsMesCKNpW/WRDoEWK7DluZcgS4jz87fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7hJEl/btsMesCKNpW/WRDoEWK7DluZcgS4jz87fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7hJEl%2FbtsMesCKNpW%2FWRDoEWK7DluZcgS4jz87fk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;526&quot; height=&quot;163&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBiGFB/btsMd4WHTfE/7mmua7K5IvxaXyziokeQ81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBiGFB/btsMd4WHTfE/7mmua7K5IvxaXyziokeQ81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBiGFB/btsMd4WHTfE/7mmua7K5IvxaXyziokeQ81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBiGFB%2FbtsMd4WHTfE%2F7mmua7K5IvxaXyziokeQ81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;737&quot; height=&quot;312&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2491&quot; data-start=&quot;2451&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2491&quot; data-start=&quot;2451&quot;&gt;&lt;b&gt;리턴문만 있는 경우&lt;/b&gt;, {} 및 return 생략 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+ String의 length 메서드 하나만을 실행하기 때문에 :: 연산자를 활용해서 메서드 참조하는 경우까지 적용해봤다.&lt;/p&gt;</description>
      <category>Java</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/234</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%948-%EB%9E%8C%EB%8B%A4%EC%99%80-%ED%95%A8%EC%88%98%ED%98%95-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-2-FunctionalInterface-%EA%B5%AC%ED%98%84%EC%B2%B4-%EC%9E%91%EC%84%B1%EB%B2%95%EB%9E%8C%EB%8B%A4-%ED%91%9C%ED%98%84%EC%8B%9D#entry234comment</comments>
      <pubDate>Tue, 11 Feb 2025 15:53:05 +0900</pubDate>
    </item>
    <item>
      <title>자바8 람다와 함수형 인터페이스 [1] : 람다의 등장 배경</title>
      <link>https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%948-%EB%9E%8C%EB%8B%A4%EC%99%80-%ED%95%A8%EC%88%98%ED%98%95-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-1-%EB%9E%8C%EB%8B%A4%EC%9D%98-%EB%93%B1%EC%9E%A5-%EB%B0%B0%EA%B2%BD</link>
      <description>&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8의 핵심 기능 중 하나인 람다 표현식과 함수형 인터페이스의 개념을 살펴본다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;배경: 익명 클래스에서 람다 표현식으로&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8 이전에는 특정 동작을 전달하기 위해 익명 클래스를 사용해야 했다.&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;예를 들어, `Comparator`를 활용하여 정렬을 수행하는 방식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br3gy7/btsMd8YFfPe/z4Ukb85mBfiCzsgfNa3zK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br3gy7/btsMd8YFfPe/z4Ukb85mBfiCzsgfNa3zK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br3gy7/btsMd8YFfPe/z4Ukb85mBfiCzsgfNa3zK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr3gy7%2FbtsMd8YFfPe%2Fz4Ukb85mBfiCzsgfNa3zK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;672&quot; height=&quot;393&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&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;하지만 이 방식은 코드가 장황하고 보일러플레이트 코드가 많다. 자바 8부터는 람다 표현식을 활용하여 이를 간결하게 줄일 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bO1eHP/btsMe1qPCIt/uykvGyCj5EmJ18jSGVqudK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bO1eHP/btsMe1qPCIt/uykvGyCj5EmJ18jSGVqudK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bO1eHP/btsMe1qPCIt/uykvGyCj5EmJ18jSGVqudK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbO1eHP%2FbtsMe1qPCIt%2FuykvGyCj5EmJ18jSGVqudK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;693&quot; height=&quot;255&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;255&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;함수형 인터페이스와 `@FunctionalInterface`&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다 표현식을 적용할 수 있는 &lt;b&gt;함수형 인터페이스(Functional Interface)&lt;/b&gt;&amp;nbsp;개념이 도입되었다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;함수형 인터페이스란?&lt;/h4&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;`Runnable`, `Callable`, `Comparator` 등이 함수형 인터페이스의 예이다.&lt;/li&gt;
&lt;li&gt;람다 표현식은 함수형 인터페이스를 대상으로 적용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`@FunctionalInterface` 어노테이션은 선택 사항이지만, 이를 명시하면 하나의 추상 메서드만 존재하도록 강제할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;583&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwXLjW/btsMcQLfOZK/xJm4p3HzbZCAbjmhri3PKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwXLjW/btsMcQLfOZK/xJm4p3HzbZCAbjmhri3PKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwXLjW/btsMcQLfOZK/xJm4p3HzbZCAbjmhri3PKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwXLjW%2FbtsMcQLfOZK%2FxJm4p3HzbZCAbjmhri3PKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;583&quot; height=&quot;372&quot; data-origin-width=&quot;583&quot; data-origin-height=&quot;372&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;336&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oGJXH/btsMetagRbq/ikNTU1JgevlMT3qu1HmpLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oGJXH/btsMetagRbq/ikNTU1JgevlMT3qu1HmpLk/img.png&quot; data-alt=&quot;설계적으로 해당 어노테이션은 하나의 추상 메서드를 가져야한다고 되어있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oGJXH/btsMetagRbq/ikNTU1JgevlMT3qu1HmpLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoGJXH%2FbtsMetagRbq%2FikNTU1JgevlMT3qu1HmpLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;740&quot; height=&quot;336&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;336&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;설계적으로 해당 어노테이션은 하나의 추상 메서드를 가져야한다고 되어있다.&lt;/figcaption&gt;
&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;람다가 함수형 인터페이스에 적용되는 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;람다 표현식은 &lt;/span&gt;&lt;span&gt;&lt;b&gt;익명 클래스의 단순화된 표현&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이 아니라 &lt;/span&gt;&lt;span&gt;&lt;b&gt;함수형 프로그래밍 개념을 도입&lt;/b&gt;&lt;/span&gt;&lt;span&gt;한 결과물이다.&lt;/span&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;span&gt;그렇다면 왜 람다가 함수형 인터페이스와 밀접한 관계를 가지게 되었을까?&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 메서드 전달 개념 도입 (First-class Function의 유사 개념)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-pm-slice=&quot;3 3 [&amp;quot;ordered_list&amp;quot;,{&amp;quot;spread&amp;quot;:true,&amp;quot;startingNumber&amp;quot;:1,&amp;quot;start&amp;quot;:1375,&amp;quot;end&amp;quot;:1750},&amp;quot;regular_list_item&amp;quot;,{&amp;quot;start&amp;quot;:1375,&amp;quot;end&amp;quot;:1521}]&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;기존 자바는 메서드를 직접 전달할 수 없었고, 이를 위해 객체(익명 클래스)를 생성해야 했다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;람다를 통해 객체 없이 함수를 직접 전달하는 효과를 얻을 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 정적 타입 시스템 유지&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-pm-slice=&quot;3 3 [&amp;quot;ordered_list&amp;quot;,{&amp;quot;spread&amp;quot;:true,&amp;quot;startingNumber&amp;quot;:1,&amp;quot;start&amp;quot;:1375,&amp;quot;end&amp;quot;:1750},&amp;quot;regular_list_item&amp;quot;,{&amp;quot;start&amp;quot;:1523,&amp;quot;end&amp;quot;:1649}]&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;자바는 정적 타입 언어이므로, 람다 표현식도 특정한 타입을 가져야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;함수형 인터페이스를 사용하면 람다 표현식이 어떤 메서드 시그니처를 따르는지 명확히 할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 가독성과 유지보수성 개선&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;익명 클래스보다 훨씬 간결한 코드 작성이 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;핵심 로직만 표현하고, 불필요한 보일러플레이트 코드를 줄일 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;Java 아키텍트들의 고민과 람다의 표현 방식&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;아키텍트들의 고민&lt;/h4&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;변성(variance) 문제를 어떻게 해결할 것인가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;대안 검토&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;기존의 익명 클래스를 개선하는 방식&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;List&amp;lt;String&amp;gt; -&amp;gt; int&lt;/span&gt;&lt;span&gt; 같은 함수 표현 문제 발생&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Boxing 문제&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;언어 차원의 표현과 JVM에서의 표현 간 갭 발생&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Function Type을 직접 추가하는 방식&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;새로운 함수 시그니처, 새로운 바이트코드 호출 방식 도입 필요&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;복잡도 증가, corner case 발생 가능성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;구형/신형 라이브러리의 호환 문제 발생&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;람다의 외부적 표현: Functional Interface&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;람다 표현을 위해 기존의 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Functional Interface&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 개념을 활용하게 된 이유:&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;기존 개발자들이 익숙한 &lt;/span&gt;&lt;span&gt;&lt;b&gt;추상 메서드가 하나인 인터페이스 모델&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 유지할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;기존 인터페이스(&lt;/span&gt;&lt;span&gt;Comparator&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;Runnable&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;Callable&lt;/span&gt;&lt;span&gt; 등)를 활용 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;타입 시스템을 복잡하게 만들지 않고, 람다를 항상 Functional Interface 인스턴스로 변환하도록 설계&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;컴파일러가 람다를 구조적으로 Functional Interface로 치환 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;람다의 내부적 표현: MethodHandle&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자바 7에서는 &lt;/span&gt;&lt;span&gt;&lt;b&gt;MethodHandle&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이라는 새로운 바이트코드 도구가 추가되었다. 이는 다음과 같은 특징을 갖는다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;Constant Pool에 있는 메서드의 레퍼런스를 저장 가능 (&lt;/span&gt;&lt;span&gt;LDC&lt;/span&gt;&lt;span&gt;로 로드 가능)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;특정 메서드나 필드의 핸들을 얻을 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;MethodHandle&lt;/span&gt;&lt;span&gt;을 통해 VM이 인라인 최적화 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;강력한 Combinator API 제공 (인자 추가/제거/재배열, Boxing/Casting, 함수 합성)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span&gt;초기 자바 8 개발에서는 MethodHandle을 직접 사용하여 람다를 표현하려 했지만, 다음과 같은 문제가 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;MethodHandle이 VM 모델 수준에서 동작하는 객체이므로, 언어 차원에서 필요한 정보가 많이 생략됨&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;따라서, &lt;/span&gt;&lt;span&gt;&lt;b&gt;람다를 디슈거링(desugaring)하여 일반 메서드로 변환한 후, 바이트코드 시그니처에서 MethodHandle을 활용하여 람다를 표현&lt;/b&gt;&lt;/span&gt;&lt;span&gt;하는 방식으로 정리됨&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8의 람다와 함수형 인터페이스는 코드의 간결화와 유지보수성 개선을 위한 필수적인 변화였다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;br /&gt;&lt;a href=&quot;https://dzone.com/articles/java-8-functional-interfaces-sam&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dzone.com/articles/java-8-functional-interfaces-sam&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tourspace.tistory.com/11&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://tourspace.tistory.com/11&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Effective Java&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>람다의 출현</category>
      <category>자바</category>
      <category>함수형 프로그래밍</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/233</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%948-%EB%9E%8C%EB%8B%A4%EC%99%80-%ED%95%A8%EC%88%98%ED%98%95-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-1-%EB%9E%8C%EB%8B%A4%EC%9D%98-%EB%93%B1%EC%9E%A5-%EB%B0%B0%EA%B2%BD#entry233comment</comments>
      <pubDate>Tue, 11 Feb 2025 13:52:15 +0900</pubDate>
    </item>
    <item>
      <title>JAVA 문법 QUIZ [2]</title>
      <link>https://nstgic3.tistory.com/entry/JAVA-%EB%AC%B8%EB%B2%95-QUIZ-2</link>
      <description>&lt;!-- 문제 1 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 1: 추상 클래스에서 static 메서드?&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;abstract class Parent {
    static void show() {
        System.out.println(&quot;Parent 클래스&quot;);
    }
    
    abstract void display();
}

class Child extends Parent {
    void display() {
        System.out.println(&quot;Child 클래스&quot;);
    }
}

public class Test {
    public static void main(String[] args) {
        Parent.show();
    }
}
&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;b&gt;Q1&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&quot;Parent 클래스&quot;&lt;/li&gt;
&lt;li&gt;&quot;Child 클래스&quot;&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) &quot;Parent 클래스&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;static&lt;/code&gt; 메서드는 클래스 소속 &amp;rarr; 인스턴스 없이 &lt;code&gt;Parent.show()&lt;/code&gt;로 직접 호출 가능&lt;/li&gt;
&lt;li&gt;추상 클래스도 &lt;code&gt;static&lt;/code&gt; 메서드를 가질 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 유사 문제:&lt;/b&gt; 이전 11번(추상 클래스 일반 메서드)와 유사하지만, 여기서는 &lt;b&gt;static 메서드&lt;/b&gt;를 다룸&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 2 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 2: super()의 호출 순서&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A {
    A() {
        System.out.println(&quot;A 생성자&quot;);
    }
}

class B extends A {
    B() {
        System.out.println(&quot;B 생성자&quot;);
    }
}

class C extends B {
    C() {
        System.out.println(&quot;C 생성자&quot;);
    }
}

public class Test {
    public static void main(String[] args) {
        C obj = new C();
    }
}
&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;b&gt;Q2&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;A 생성자 B 생성자 C 생성자&lt;/li&gt;
&lt;li&gt;C 생성자 B 생성자 A 생성자&lt;/li&gt;
&lt;li&gt;B 생성자 C 생성자 A 생성자&lt;/li&gt;
&lt;li&gt;A 생성자 C 생성자 B 생성자&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) A 생성자 B 생성자 C 생성자&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;C()&lt;/code&gt; 호출 &amp;rarr; 내부적으로 &lt;code&gt;super()&lt;/code&gt; &amp;rarr; &lt;code&gt;B()&lt;/code&gt; &amp;rarr; 그 내부 &lt;code&gt;super()&lt;/code&gt; &amp;rarr; &lt;code&gt;A()&lt;/code&gt; 순&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 3 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 3: 인터페이스 다중 상속과 default 메서드&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface A {
    default void show() {
        System.out.println(&quot;A 인터페이스&quot;);
    }
}

interface B {
    default void show() {
        System.out.println(&quot;B 인터페이스&quot;);
    }
}

class C implements A, B {
    public void show() {
        System.out.println(&quot;C 클래스&quot;);
    }
}

public class Test {
    public static void main(String[] args) {
        A obj = new C();
        obj.show();
    }
}
&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;b&gt;Q3&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&quot;A 인터페이스&quot;&lt;/li&gt;
&lt;li&gt;&quot;B 인터페이스&quot;&lt;/li&gt;
&lt;li&gt;&quot;C 클래스&quot;&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 3) &quot;C 클래스&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;인터페이스 다중 상속 시, 같은 시그니처의 default 메서드가 충돌&lt;/li&gt;
&lt;li&gt;클래스 &lt;code&gt;C&lt;/code&gt;에서 &lt;code&gt;show()&lt;/code&gt;를 오버라이딩해 충돌 해결 &amp;rarr; &quot;C 클래스&quot; 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 유사 문제:&lt;/b&gt; 이전 12번에서 &lt;b&gt;오버라이딩하지 않아서 컴파일 에러&lt;/b&gt;가 났던 예시와 대조됨 (여긴 직접 오버라이딩)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 4 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 4: instanceof와 null&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Parent {}

public class Test {
    public static void main(String[] args) {
        Parent obj = null;
        System.out.println(obj instanceof Parent);
    }
}
&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;b&gt;Q4&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;true&lt;/li&gt;
&lt;li&gt;false&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) false&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;null instanceof Parent&lt;/code&gt;는 &lt;code&gt;false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;null&lt;/code&gt;은 어떠한 객체도 아니기 때문&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 5 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 5: try-with-resources와 AutoCloseable&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MyResource implements AutoCloseable {
    public void use() {
        System.out.println(&quot;리소스 사용&quot;);
    }

    @Override
    public void close() {
        System.out.println(&quot;리소스 해제&quot;);
    }
}

public class Test {
    public static void main(String[] args) {
        try (MyResource res = new MyResource()) {
            res.use();
        }
    }
}
&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;b&gt;Q5&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&quot;리소스 사용&quot; &quot;리소스 해제&quot;&lt;/li&gt;
&lt;li&gt;&quot;리소스 사용&quot;&lt;/li&gt;
&lt;li&gt;&quot;리소스 해제&quot;&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) &quot;리소스 사용&quot; &quot;리소스 해제&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;try-with-resources&lt;/code&gt; 구문은 &lt;code&gt;AutoCloseable&lt;/code&gt; 구현체를 자동으로 &lt;code&gt;close()&lt;/code&gt; 호출함&lt;/li&gt;
&lt;li&gt;코드 내 &lt;code&gt;res.use()&lt;/code&gt; 실행 후 블록을 벗어날 때 &lt;code&gt;close()&lt;/code&gt;가 자동 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 유사 문제:&lt;/b&gt; 이전 16번(BufferedReader 예시)과 동일한 &lt;b&gt;try-with-resources&lt;/b&gt; 개념, 여기서는 &lt;i&gt;직접 만든 리소스&lt;/i&gt; 사용&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 6 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 6: final 변수의 동작&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Test {
    public static void main(String[] args) {
        final int x;
        System.out.println(x);
    }
}
&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;b&gt;Q6&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;0&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;li&gt;아무것도 출력되지 않음&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) 컴파일 에러 발생&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;final&lt;/code&gt; 변수는 선언과 동시에 혹은 생성자/블록 안에서 반드시 초기화해야 함&lt;/li&gt;
&lt;li&gt;초기화 없이 &lt;code&gt;System.out.println(x)&lt;/code&gt;로 사용하려 하면 컴파일 에러&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 7 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 7: try-catch-finally와 return&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Test {
    public static int testMethod() {
        try {
            return 1;
        } catch (Exception e) {
            return 2;
        } finally {
            return 3;
        }
    }

    public static void main(String[] args) {
        System.out.println(testMethod());
    }
}
&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;b&gt;Q7&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;1&lt;/li&gt;
&lt;li&gt;2&lt;/li&gt;
&lt;li&gt;3&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 3) 3&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;finally&lt;/code&gt; 구문에서 &lt;code&gt;return&lt;/code&gt;을 실행하면 &lt;code&gt;try&lt;/code&gt;&amp;middot;&lt;code&gt;catch&lt;/code&gt; 블록의 &lt;code&gt;return&lt;/code&gt;은 무시&lt;/li&gt;
&lt;li&gt;최종적으로 &lt;code&gt;3&lt;/code&gt;이 반환됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 8 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 8: throws와 throw의 차이&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MyException extends Exception {
    MyException(String message) {
        super(message);
    }
}

public class Test {
    public static void main(String[] args) throws MyException {
        method();
    }

    static void method() throws MyException {
        throw new MyException(&quot;예외 발생!&quot;);
    }
}
&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;b&gt;Q8&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&quot;예외 발생!&quot; 출력 후 프로그램 종료&lt;/li&gt;
&lt;li&gt;&quot;예외 발생!&quot; 출력 후 정상 종료&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;아무것도 출력되지 않음&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) &quot;예외 발생!&quot; 출력 후 프로그램 종료&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;throws&lt;/code&gt;는 예외를 메서드 밖으로 던지겠다고 선언한 것일 뿐, 처리(catch)하지 않으면 프로그램 종료&lt;/li&gt;
&lt;li&gt;&lt;code&gt;throw&lt;/code&gt;는 실제 예외 객체 발생. &lt;code&gt;catch&lt;/code&gt;가 없으니 종료&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 중복 개념:&lt;/b&gt;&amp;nbsp;15번(throws vs throw)과 유사 예제. &lt;b&gt;예외 처리&lt;/b&gt;가 없으면 그대로 종료&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 9 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*문제 9: Integer 캐싱 범위&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Test {
    public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        Integer c = 200;
        Integer d = 200;

        System.out.println(a == b);
        System.out.println(c == d);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q9&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;true true&lt;/li&gt;
&lt;li&gt;false false&lt;/li&gt;
&lt;li&gt;true false&lt;/li&gt;
&lt;li&gt;false true&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 3) true false&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;Integer&lt;/code&gt;는 -128 ~ 127 범위를 캐싱하므로 100은 동일 객체 &amp;rarr; &lt;code&gt;a == b&lt;/code&gt; &amp;rarr; true&lt;/li&gt;
&lt;li&gt;200은 캐싱 범위 바깥이므로 다른 객체 &amp;rarr; &lt;code&gt;c == d&lt;/code&gt; &amp;rarr; false&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 10 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 10: hashCode()와 equals()&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.HashSet;

class Person {
    String name;

    Person(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Person) {
            return this.name.equals(((Person) obj).name);
        }
        return false;
    }
}

public class Test {
    public static void main(String[] args) {
        HashSet set = new HashSet&amp;lt;&amp;gt;();
        set.add(new Person(&quot;Alice&quot;));
        set.add(new Person(&quot;Alice&quot;));

        System.out.println(set.size());
    }
}
&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;b&gt;Q10&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;1&lt;/li&gt;
&lt;li&gt;2&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) 2&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;equals()&lt;/code&gt;는 재정의했지만 &lt;code&gt;hashCode()&lt;/code&gt;는 재정의하지 않아, 서로 다른 해시값으로 인식됨&lt;/li&gt;
&lt;li&gt;HashSet은 내부적으로 &lt;code&gt;hashCode()&lt;/code&gt; 비교 후 &lt;code&gt;equals()&lt;/code&gt;를 확인하므로, 중복 판정 실패 &amp;rarr; 원소 2개&lt;/li&gt;
&lt;li&gt;중복을 제대로 제거하려면 &lt;code&gt;hashCode()&lt;/code&gt;도 함께 재정의 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 11 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 11: 추상 클래스 내 메서드 상속&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;abstract class Parent {
    void show() { // 일반 메서드
        System.out.println(&quot;Parent 클래스&quot;);
    }
    
    abstract void display(); // 추상 메서드
}

class Child extends Parent {
    void display() {
        System.out.println(&quot;Child 클래스&quot;);
    }
}

public class Test {
    public static void main(String[] args) {
        Parent obj = new Child();
        obj.show();
        obj.display();
    }
}
&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;b&gt;Q11&lt;/b&gt;: 실행 결과는 무엇인가?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Parent 클래스 Child 클래스&lt;/li&gt;
&lt;li&gt;Child 클래스 Parent 클래스&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) Parent 클래스 Child 클래스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;Parent&lt;/code&gt;의 일반 메서드(&lt;code&gt;show()&lt;/code&gt;)는 자식이 재정의할 필요 없이 그대로 사용 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;display()&lt;/code&gt;는 추상 메서드이므로 &lt;code&gt;Child&lt;/code&gt;에서 구현&lt;/li&gt;
&lt;li&gt;실행 순서: &lt;code&gt;obj.show()&lt;/code&gt; &amp;rarr; &quot;Parent 클래스&quot;, &lt;code&gt;obj.display()&lt;/code&gt; &amp;rarr; &quot;Child 클래스&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 12 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 12: 인터페이스 default 메서드 &amp;amp; 다중 상속&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface A {
    default void show() {
        System.out.println(&quot;A 인터페이스&quot;);
    }
}

interface B {
    default void show() {
        System.out.println(&quot;B 인터페이스&quot;);
    }
}

class C implements A, B {
    // show() 오버라이딩 없이 비워둠
}

public class Test {
    public static void main(String[] args) {
        C obj = new C();
        obj.show();
    }
}
&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;b&gt;Q12&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;A 인터페이스&lt;/li&gt;
&lt;li&gt;B 인터페이스&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 3) 컴파일 에러 발생&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;A&lt;/code&gt;와 &lt;code&gt;B&lt;/code&gt;가 동일한 시그니처의 &lt;code&gt;default&lt;/code&gt; 메서드를 제공 &amp;rarr; 충돌 발생&lt;/li&gt;
&lt;li&gt;클래스 &lt;code&gt;C&lt;/code&gt;에서 반드시 &lt;code&gt;show()&lt;/code&gt;를 오버라이딩해 충돌 해결 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 13 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 13: 인터페이스의 static 메서드&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface A {
    static void show() {
        System.out.println(&quot;A 인터페이스&quot;);
    }
}

class B implements A {}

public class Test {
    public static void main(String[] args) {
        B obj = new B();
        obj.show();
    }
}
&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;b&gt;Q13&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;A 인터페이스&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;li&gt;아무것도 출력되지 않음&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) 컴파일 에러 발생&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;static&lt;/code&gt; 메서드는 &lt;b&gt;인스턴스&lt;/b&gt;로 호출할 수 없음&lt;/li&gt;
&lt;li&gt;정확한 호출 방법: &lt;code&gt;A.show();&lt;/code&gt; (인터페이스명으로 직접 호출)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 14 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 14: Checked vs Unchecked 예외&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Test {
    public static void main(String[] args) {
        try {
            method();
        } catch (Exception e) {
            System.out.println(&quot;예외 발생!&quot;);
        }
    }

    static void method() throws RuntimeException {
        throw new RuntimeException(&quot;런타임 예외 발생!&quot;);
    }
}
&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;b&gt;Q&lt;/b&gt;&lt;b&gt;14&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&quot;예외 발생!&quot;&lt;/li&gt;
&lt;li&gt;&quot;런타임 예외 발생!&quot;&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;예외 발생 후 프로그램 종료&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) &quot;예외 발생!&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;RuntimeException&lt;/code&gt;은 &lt;i&gt;Unchecked Exception&lt;/i&gt;으로, &lt;code&gt;catch (Exception e)&lt;/code&gt;가 이를 잡음&lt;/li&gt;
&lt;li&gt;catch 블록에서 &quot;예외 발생!&quot; 출력 후 정상 흐름으로 진행&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 15 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 15: throws vs throw&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MyException extends Exception {
    MyException(String message) {
        super(message);
    }
}

public class Test {
    public static void main(String[] args) throws MyException {
        System.out.println(&quot;프로그램 실행&quot;);
        throw new MyException(&quot;커스텀 예외 발생!&quot;);
    }
}
&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;b&gt;Q15&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&quot;프로그램 실행&quot; 후 &quot;커스텀 예외 발생!&quot;&lt;/li&gt;
&lt;li&gt;&quot;커스텀 예외 발생!&quot; 후 프로그램 종료&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;&quot;프로그램 실행&quot; 후 정상 종료&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) &quot;프로그램 실행&quot; 후 &quot;커스텀 예외 발생!&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;throws MyException&lt;/code&gt;로 예외를 던질 수 있다고 선언했고, 실제로 &lt;code&gt;throw&lt;/code&gt;로 예외 발생&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&quot;프로그램 실행&quot;&lt;/b&gt;이 먼저 출력되고, 예외가 던져지면서 프로그램이 종료됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 16 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 16: try-with-resources&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;

public class Test {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader(&quot;test.txt&quot;)))//파일이 없음 {
            System.out.println(br.readLine());
        } catch (IOException e) {
            System.out.println(&quot;예외 발생!&quot;);
        }
    }
}&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;b&gt;Q16&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&quot;test.txt&quot; 파일의 첫 번째 줄 출력&lt;/li&gt;
&lt;li&gt;&quot;예외 발생!&quot;&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 예외 발생 후 프로그램 종료&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) &quot;예외 발생!&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;test.txt&lt;/code&gt;가 없거나 IO 에러가 발생 시 &lt;code&gt;IOException&lt;/code&gt;을 잡아 &quot;예외 발생!&quot; 출력&lt;/li&gt;
&lt;li&gt;만약 실제로 파일이 존재하고 정상 읽기가 가능하다면 1번 상황이 될 수도 있음 (문제 예시상 정답은 2번 가정)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 17 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 17: finally 블록과 System.exit()&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Test {
    public static void main(String[] args) {
        try {
            System.out.println(&quot;try 블록 실행&quot;);
            System.exit(0);
        } finally {
            System.out.println(&quot;finally 블록 실행&quot;);
        }
    }
}
&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;b&gt;Q17&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&quot;try 블록 실행&quot; 후 &quot;finally 블록 실행&quot;&lt;/li&gt;
&lt;li&gt;&quot;try 블록 실행&quot; 후 프로그램 종료&lt;/li&gt;
&lt;li&gt;&quot;finally 블록 실행&quot; 후 프로그램 종료&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) &quot;try 블록 실행&quot; 후 프로그램 종료&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;System.exit(0)&lt;/code&gt;는 JVM을 종료하므로 &lt;code&gt;finally&lt;/code&gt; 블록이 실행되지 않음&lt;/li&gt;
&lt;li&gt;일반적으로 &lt;code&gt;finally&lt;/code&gt;는 항상 실행되지만, &lt;code&gt;System.exit()&lt;/code&gt;는 예외&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 18: String Pool과 &lt;code&gt;new String()&lt;/code&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Test {
    public static void main(String[] args) {
        String s1 = &quot;Java&quot;;
        String s2 = &quot;Java&quot;;
        String s3 = new String(&quot;Java&quot;);

        System.out.println(s1 == s2);
        System.out.println(s1 == s3);
    }
}
&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;b&gt;Q&lt;/b&gt;: 위 코드 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;true / true&lt;/li&gt;
&lt;li&gt;true / false&lt;/li&gt;
&lt;li&gt;false / true&lt;/li&gt;
&lt;li&gt;false / false&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) true / false&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;s1&lt;/code&gt;과 &lt;code&gt;s2&lt;/code&gt;는 같은 String Pool 영역을 참조하므로 &lt;code&gt;s1 == s2&lt;/code&gt; &amp;rarr; &lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;new String(&quot;Java&quot;)&lt;/code&gt;는 새로운 객체를 생성하므로 &lt;code&gt;s1 == s3&lt;/code&gt; &amp;rarr; &lt;code&gt;false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;문자열 내용을 비교하려면 &lt;code&gt;equals()&lt;/code&gt; 메서드를 사용해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 19 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 19: instanceof &amp;amp; 인터페이스&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface A {}

class B implements A {}

public class Test {
    public static void main(String[] args) {
        A obj = new B();
        System.out.println(obj instanceof B);
        System.out.println(obj instanceof A);
        System.out.println(obj instanceof Object);
    }
}
&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;b&gt;Q19&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;true true true&lt;/li&gt;
&lt;li&gt;true false true&lt;/li&gt;
&lt;li&gt;false true true&lt;/li&gt;
&lt;li&gt;true true false&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) true true true&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;obj instanceof B&lt;/code&gt; &amp;rarr; &lt;code&gt;obj&lt;/code&gt;는 &lt;code&gt;B&lt;/code&gt; 객체이므로 &lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;obj instanceof A&lt;/code&gt; &amp;rarr; &lt;code&gt;B&lt;/code&gt;가 &lt;code&gt;A&lt;/code&gt;를 구현했으므로 &lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;obj instanceof Object&lt;/code&gt; &amp;rarr; 자바의 모든 클래스는 &lt;code&gt;Object&lt;/code&gt; 상속 &amp;rarr; &lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;!-- 문제 20 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*문제 20: enum &amp;amp; 생성자&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum Color {
    RED, GREEN, BLUE;

    Color() {
        System.out.println(&quot;Color 생성자 실행!&quot;);
    }
}

public class Test {
    public static void main(String[] args) {
        Color c1 = Color.RED;
        Color c2 = Color.GREEN;
    }
}
&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;b&gt;Q20&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&quot;Color 생성자 실행!&quot; 1번 출력&lt;/li&gt;
&lt;li&gt;&quot;Color 생성자 실행!&quot; 2번 출력&lt;/li&gt;
&lt;li&gt;&quot;Color 생성자 실행!&quot; 3번 출력&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 3) &quot;Color 생성자 실행!&quot; 3번 출력&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;enum은 선언된 모든 상수가 처음 로드될 때 생성자를 실행&lt;/li&gt;
&lt;li&gt;따라서 &lt;code&gt;RED, GREEN, BLUE&lt;/code&gt; 세 상수 각각에 대해 한 번씩 호출 &amp;rarr; 총 3번 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;</description>
      <category>Java</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/232</guid>
      <comments>https://nstgic3.tistory.com/entry/JAVA-%EB%AC%B8%EB%B2%95-QUIZ-2#entry232comment</comments>
      <pubDate>Tue, 4 Feb 2025 14:50:50 +0900</pubDate>
    </item>
    <item>
      <title>Java 문법 QUIZ [1]</title>
      <link>https://nstgic3.tistory.com/entry/Java-%EC%A1%B0%EA%B0%81%EB%AA%A8%EC%9D%8C-Quiz1</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 1: 접근제어자 &amp;amp; 상속&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Parent {
	private void show() {
    	System.out.println(&quot;Parent 클래스&quot;);
    }
}

class Child extends Parent {
	public void show() {
    	System.out.println(&quot;Child 클래스&quot;);
    }
}

public class Test {
	public static void main(String[] args) {
		Parent obj = new Child(); obj.show();
    }
}&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;b&gt;Q1&lt;/b&gt;: 위 코드의 실행 결과는 무엇인가?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Child 클래스 출력&lt;/li&gt;
&lt;li&gt;Parent 클래스 출력&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 에러 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 3) 컴파일 에러 발생&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;Parent&lt;/code&gt;의 &lt;code&gt;show()&lt;/code&gt; 메서드는 &lt;code&gt;private&lt;/code&gt;이라 상속되지 않음.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Child&lt;/code&gt;의 &lt;code&gt;show()&lt;/code&gt;는 완전히 다른 메서드(오버라이딩이 아님).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Parent obj = new Child();&lt;/code&gt; 이후 &lt;code&gt;obj.show()&lt;/code&gt;는 컴파일 시점에 &lt;code&gt;Parent&lt;/code&gt;가 가진 &lt;code&gt;show()&lt;/code&gt;를 찾는데, &lt;code&gt;private&lt;/code&gt; 때문에 존재하지 않아 오류가 발생함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 2: final 변수와 참조형 변수&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.ArrayList;
import java.util.List;

public class Test {
	public static void main(String[] args) {
    	final List list = new ArrayList&amp;lt;&amp;gt;();
        list.add(&quot;A&quot;);
        list.add(&quot;B&quot;);
        list.add(&quot;C&quot;);
    	list = new ArrayList&amp;lt;&amp;gt;(); // 문제 발생?
	}
}&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;b&gt;Q2&lt;/b&gt;: 위 코드에서 어떤 문제가 발생할까?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;final인데 &lt;code&gt;list.add()&lt;/code&gt;가 가능하므로 오류 발생&lt;/li&gt;
&lt;li&gt;&lt;code&gt;list = new ArrayList&amp;lt;&amp;gt;();&lt;/code&gt;에서 컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;정상적으로 실행됨&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) &lt;code&gt;list = new ArrayList&amp;lt;&amp;gt;();&lt;/code&gt;에서 컴파일 에러 발생&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;final&lt;/code&gt;은 &lt;b&gt;재할당&lt;/b&gt;을 막을 뿐, 내부 요소 변경(&lt;code&gt;add()&lt;/code&gt;)은 허용함.&lt;/li&gt;
&lt;li&gt;하지만 &lt;code&gt;list = new ArrayList&amp;lt;&amp;gt;();&lt;/code&gt;처럼 &lt;b&gt;새 객체로 재할당&lt;/b&gt;은 불가능하기 때문에 컴파일 에러.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;문제 3: for-loop와 i++ 값 예측&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Test {

	public static void main(String[] args) {
    	int i = 0;
        for (int j = 0; j &amp;lt; 5; j++) {
        	if (j % 2 == 0) {
            	i++;
            }
        }
    	System.out.println(i);
    }
}&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;b&gt;Q3&lt;/b&gt;: 위 코드 실행 후 i의 값은 무엇인가?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;2&lt;/li&gt;
&lt;li&gt;3&lt;/li&gt;
&lt;li&gt;4&lt;/li&gt;
&lt;li&gt;5&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) 3&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;j % 2 == 0&lt;/code&gt;이 참인 경우는 j=0,2,4 &amp;rarr; 총 3번 &lt;code&gt;i++&lt;/code&gt; 진행.&lt;/li&gt;
&lt;li&gt;따라서 최종 &lt;code&gt;i&lt;/code&gt;는 3.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 4: String, StringBuilder 차이점&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Test {

	public static void main(String[] args) {
    	String str = &quot;Hello&quot;;
        str.concat(&quot; World&quot;);
        System.out.println(str);
    }
}&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;b&gt;Q4&lt;/b&gt;: 위 코드 실행 후 출력 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Hello World&lt;/li&gt;
&lt;li&gt;Hello&lt;/li&gt;
&lt;li&gt;World&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) Hello&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;String&lt;/code&gt;은 불변(Immutable) 객체이므로 &lt;code&gt;concat()&lt;/code&gt;은 새로운 문자열을 반환하지만, 반환값을 &lt;code&gt;str&lt;/code&gt;에 다시 할당하지 않으면 원본은 바뀌지 않음.&lt;/li&gt;
&lt;li&gt;따라서 콘솔엔 &lt;code&gt;Hello&lt;/code&gt;가 그대로 출력됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 5: 예외 발생 여부&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Test {

	public static void main(String[] args) {
    	try {
         	int result = 10 / 0;
            	System.out.println(&quot;결과: &quot; + result);
        } catch (ArithmeticException e) {
        	System.out.println(&quot;예외 발생!&quot;);
        } finally {
        	System.out.println(&quot;Finally 블록 실행!&quot;);
    	} 
    } 
}&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;b&gt;Q5&lt;/b&gt;: 위 코드 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;결과: 0&lt;/li&gt;
&lt;li&gt;예외 발생!&lt;/li&gt;
&lt;li&gt;예외 발생! + Finally 블록 실행!&lt;/li&gt;
&lt;li&gt;런타임 에러 발생 후 프로그램 종료&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 3) 예외 발생! + Finally 블록 실행!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;10 / 0&lt;/code&gt;으로 &lt;code&gt;ArithmeticException&lt;/code&gt; 발생 &amp;rarr; catch 블록에서 &quot;예외 발생!&quot; 출력&lt;/li&gt;
&lt;li&gt;&lt;code&gt;finally&lt;/code&gt; 블록은 예외와 상관없이 무조건 실행되므로 &quot;Finally 블록 실행!&quot;도 출력됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 6: static 변수와 인스턴스 변수&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Test {
    static int a = 0; int b = 0;
    
    public Test() {
        a++;
        b++;
    }

    public static void main(String[] args) {
        Test obj1 = new Test();
        Test obj2 = new Test();

        System.out.println(&quot;a: &quot; + obj1.a + &quot;, b: &quot; + obj1.b);
    }
}&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;b&gt;Q6&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;a: 2, b: 1&lt;/li&gt;
&lt;li&gt;a: 2, b: 2&lt;/li&gt;
&lt;li&gt;a: 1, b: 1&lt;/li&gt;
&lt;li&gt;a: 2, b: 0&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) a: 2, b: 1&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;a&lt;/code&gt;는 &lt;code&gt;static&lt;/code&gt;이므로 인스턴스를 여러 개 만들어도 공유 &amp;rarr; 최종 2&lt;/li&gt;
&lt;li&gt;&lt;code&gt;b&lt;/code&gt;는 인스턴스 변수이므로 &lt;code&gt;obj1&lt;/code&gt;과 &lt;code&gt;obj2&lt;/code&gt; 각각 1씩 가지고 있음. 출력 시점에는 &lt;code&gt;obj1&lt;/code&gt; 기준으로 &lt;code&gt;b = 1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 7: 자바의 다형성&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Animal {
	void makeSound() {
    	System.out.println(&quot;동물이 소리를 낸다&quot;);
    }
}

class Dog extends Animal { 
	void makeSound() { 
    	System.out.println(&quot;멍멍&quot;); 
    } 
}

public class Test { 
	
    public static void main(String[] args) {
    	Animal myDog = new Dog();
        myDog.makeSound();
    } 
}&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;b&gt;Q7&lt;/b&gt;: 위 코드 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;동물이 소리를 낸다&lt;/li&gt;
&lt;li&gt;멍멍&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) 멍멍&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;다형성(polymorphism)으로 &lt;code&gt;Animal&lt;/code&gt; 타입 &lt;code&gt;myDog&lt;/code&gt;이지만, 실제 객체는 &lt;code&gt;Dog&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;오버라이딩된 &lt;code&gt;makeSound()&lt;/code&gt; &amp;rarr; &quot;멍멍&quot; 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 8: 예외 처리와 return&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Test {

    public static void main(String[] args) {
    	System.out.println(testMethod());
    }
    
    public static int testMethod() {
        try {
            return 1;
        } finally {
            return 2;
        }
    }
}&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;b&gt;Q8&lt;/b&gt;: 위 코드 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;1&lt;/li&gt;
&lt;li&gt;2&lt;/li&gt;
&lt;li&gt;예외 발생 후 종료&lt;/li&gt;
&lt;li&gt;컴파일 에러&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) 2&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;finally&lt;/code&gt; 블록에서 &lt;code&gt;return 2&lt;/code&gt;를 호출하면, &lt;code&gt;try&lt;/code&gt; 블록의 &lt;code&gt;return 1&lt;/code&gt;은 무시됨.&lt;/li&gt;
&lt;li&gt;결과적으로 &lt;code&gt;2&lt;/code&gt;가 최종 반환됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 9: 생성자 호출 순서&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Parent { 
    Parent() { 
    	System.out.println(&quot;Parent 생성자&quot;); 
    } 
}

class Child extends Parent {
    Child() {
    	System.out.println(&quot;Child 생성자&quot;);
    }
}

public class Test {

	public static void main(String[] args) {
		Child obj = new Child(); 
    }
}&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;b&gt;Q9&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Child 생성자&lt;/li&gt;
&lt;li&gt;Parent 생성자&lt;/li&gt;
&lt;li&gt;Parent 생성자 + Child 생성자&lt;/li&gt;
&lt;li&gt;컴파일 에러&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 3) Parent 생성자 + Child 생성자&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;출력 순서: &quot;Parent 생성자&quot; &amp;rarr; &quot;Child 생성자&quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 10: 인터페이스와 메서드 호출&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface A {
    default void show() {
    	System.out.println(&quot;A 인터페이스&quot;);
    } 
}

class B implements A {
    public void show() { 
    	System.out.println(&quot;B 클래스&quot;);
    } 
}

public class Test {

    public static void main(String[] args) { 
    	A obj = new B(); obj.show(); 
    }
}&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;b&gt;Q10&lt;/b&gt;: 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;A 인터페이스&lt;/li&gt;
&lt;li&gt;B 클래스&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 에러 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) B 클래스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;default&lt;/code&gt; 메서드는 오버라이딩이 없을 때만 실행됨.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;B&lt;/code&gt; 클래스에서 &lt;code&gt;show()&lt;/code&gt;를 오버라이딩했으므로 &quot;B 클래스&quot;가 출력됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;문제 11: 오버로딩과 자동 타입 변환&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;
class OverloadTest {
  static String process(int x) {
  	return &quot;int 버전 호출: &quot; + x; 
  }

  static String process(long x) {
      return &quot;long 버전 호출: &quot; + x;
  }

  public static void main(String[] args) {
      System.out.println(process(10));
  }
} &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;b&gt;Q11&lt;/b&gt;: 위 코드 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;int 버전 호출: 10&lt;/li&gt;
&lt;li&gt;long 버전 호출: 10&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) int 버전 호출: 10&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;10&lt;/code&gt;은 기본적으로 &lt;code&gt;int&lt;/code&gt; 형으로 인식&lt;/li&gt;
&lt;li&gt;메서드 오버로딩 시, &lt;code&gt;int&lt;/code&gt;에 더 적합한 메서드가 우선 선택됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 12: 배열 vs 가변인자(Varargs)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class VarargsTest {
    static int sum(int[] nums) {
        int total = 0;

        for(int n : nums) {
            total += n;
        }
        return total;
    }

    static int sumVarargs(int... nums) {
        int total = 0;
        for(int n : nums) {
            total += n;
        }
        return total;
    }

    public static void main(String[] args) {
        int[] arr = {1,2,3};
        System.out.println(sum(arr));
        System.out.println(sumVarargs(1,2,3));
    }
}&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;b&gt;Q12&lt;/b&gt;: 위 코드 실행 결과로 옳은 것은?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;6&lt;br /&gt;6&lt;/li&gt;
&lt;li&gt;오류 발생&lt;/li&gt;
&lt;li&gt;1&lt;br /&gt;2&lt;/li&gt;
&lt;li&gt;6&lt;br /&gt;3&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) 6, 6&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;sum(int[])&lt;/code&gt;는 배열을 받아 합계 계산&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sumVarargs(int...)&lt;/code&gt;는 가변인자로 합계 계산&lt;/li&gt;
&lt;li&gt;둘 다 {1,2,3}의 합이므로 6&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 13: 재귀 호출과 StackOverflowError&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class RecursionTest { public static void main(String[] args) { recurse(); }

static void recurse() {
    System.out.println(&quot;재귀 호출 중...&quot;);
    recurse();
}
} &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;b&gt;Q13&lt;/b&gt;: 위 코드 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;무한히 &quot;재귀 호출 중...&quot; 출력 후 프로그램 정상 종료&lt;/li&gt;
&lt;li&gt;&quot;재귀 호출 중...&quot;가 한 번만 출력&lt;/li&gt;
&lt;li&gt;StackOverflowError 발생&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 3) StackOverflowError 발생&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;StackOverflowError&lt;/code&gt; 발생&lt;/li&gt;
&lt;li&gt;재귀 종료 조건이 없으므로 무조건 에러로 종료&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 14: Generics - &amp;lt;? extends Number&amp;gt; vs &amp;lt;? super Number&amp;gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

public class GenericsTest {
    public static void main(String[] args) {
        List listInt = new ArrayList&amp;lt;&amp;gt;();
        listInt.add(100);

        List&amp;lt;? extends Number&amp;gt; listExtends = listInt;
        // listExtends.add(200);  // ?

        List&amp;lt;? super Number&amp;gt; listSuper = new ArrayList&amp;lt;&amp;gt;();
        listSuper.add(300);      // ?

        System.out.println(listInt.get(0));
    }
}&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;b&gt;Q14&lt;/b&gt;: 위 코드에서 주석(&lt;code&gt;// ?&lt;/code&gt;) 부분에 대한 설명으로 옳은 것은?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;listExtends.add(200)&lt;/code&gt;은 컴파일 에러가 발생하지 않는다&lt;/li&gt;
&lt;li&gt;&lt;code&gt;listSuper.add(300)&lt;/code&gt;은 컴파일 에러가 발생한다&lt;/li&gt;
&lt;li&gt;&lt;code&gt;listExtends.add(200)&lt;/code&gt;은 컴파일 에러, &lt;code&gt;listSuper.add(300)&lt;/code&gt;은 정상 동작&lt;/li&gt;
&lt;li&gt;둘 다 정상 컴파일되며 실행 시 에러&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 3) &lt;code&gt;listExtends.add(200)&lt;/code&gt;은 컴파일 에러, &lt;code&gt;listSuper.add(300)&lt;/code&gt;은 정상 동작&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;? extends Number&lt;/code&gt;는 &amp;ldquo;읽기 전용&amp;rdquo;으로 사용, add 시 컴파일 에러&lt;/li&gt;
&lt;li&gt;&lt;code&gt;? super Number&lt;/code&gt;는 &amp;ldquo;Number 이상의 타입&amp;rdquo; 추가 가능, &lt;code&gt;listSuper.add()&lt;/code&gt; 문제 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 15: 내부 클래스(Inner Class)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class InnerClassTest {
	private String message = &quot;Outer&quot;;

    class Inner {
        void printMessage() {
            System.out.println(message);
        }
    }	

    public static void main(String[] args) {
        InnerClassTest outer = new InnerClassTest();
        InnerClassTest.Inner inner = outer.new Inner();
        inner.printMessage();
    }
}&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;b&gt;Q15&lt;/b&gt;: 위 코드 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Outer&lt;/li&gt;
&lt;li&gt;null&lt;/li&gt;
&lt;li&gt;Inner&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) Outer&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;내부 클래스는 외부 클래스의 private 멤버에 직접 접근 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;outer.new Inner()&lt;/code&gt;를 통해 인스턴스 생성 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 16: 익명 클래스(Anonymous Class)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Greeting {
	void sayHello();
}

public class AnonymousClassTest {
	public static void main(String[] args) {
            Greeting g = new Greeting() {
        
            @Override
            public void sayHello() {
            	System.out.println(&quot;Hello from Anonymous!&quot;);
            }
        };
        g.sayHello();
    }
}&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;b&gt;Q16&lt;/b&gt;: 위 코드 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Hello from Anonymous!&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;익명 클래스라 아무것도 출력되지 않음&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) Hello from Anonymous!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;new 인터페이스() { ... }&lt;/code&gt; 형태로 구현&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sayHello()&lt;/code&gt; 오버라이딩 후 호출 시 메시지 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*문제 17: Thread 사용&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ThreadTest extends Thread {
    @Override
    public void run() {
    	System.out.println(&quot;Thread 실행 중&quot;);
    }

    public static void main(String[] args) {
        ThreadTest t = new ThreadTest();
        t.start();
        System.out.println(&quot;main 메서드&quot;);
    }
}&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;b&gt;Q17&lt;/b&gt;: 실행 결과가 &quot;main 메서드&quot;가 먼저 출력될 수도 있는 이유는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;t.start()가 컴파일 에러를 유발해서&lt;/li&gt;
&lt;li&gt;Thread는 별도 실행 흐름이므로 main이 먼저 끝날 수 있음&lt;/li&gt;
&lt;li&gt;JVM 버그&lt;/li&gt;
&lt;li&gt;시스템 환경 변수 문제&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) Thread는 별도 실행 흐름이므로 main이 먼저 끝날 수 있음&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;start()&lt;/code&gt; 호출 시 새로운 쓰레드가 생성되어 &lt;code&gt;run()&lt;/code&gt; 실행&lt;/li&gt;
&lt;li&gt;메인 쓰레드와 병렬로 실행되므로 순서가 보장되지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*문제 18: Callable &amp;amp; Future&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.concurrent.*;

public class CallableTest {

    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        Future&amp;lt;String&amp;gt; future = executor.submit(new Callable&amp;lt;String&amp;gt;() {
            @Override
            public String call() {
                return &quot;Callable 결과&quot;;
            }
        });

        System.out.println(&quot;메인 진행 중...&quot;);
        System.out.println(future.get());

        executor.shutdown();
    }
}&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;b&gt;Q18&lt;/b&gt;: &lt;code&gt;future.get()&lt;/code&gt;의 역할은?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;비동기로 결과를 가져오지만 &lt;i&gt;대기&lt;/i&gt; 없이 즉시 반환&lt;/li&gt;
&lt;li&gt;스레드 실행 결과를 &lt;i&gt;대기&lt;/i&gt; 후 받아옴&lt;/li&gt;
&lt;li&gt;Runtime 예외를 발생시킴&lt;/li&gt;
&lt;li&gt;컴파일 시 에러를 발생시킴&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) 스레드 실행 결과를 &lt;i&gt;대기&lt;/i&gt; 후 받아옴&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;future.get()&lt;/code&gt;은 작업이 완료될 때까지 블로킹(대기)&lt;/li&gt;
&lt;li&gt;완료된 후 Callable의 반환값을 가져옴&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*문제 19: 람다 표현식&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Arrays;
import java.util.List;

public class LambdaTest {
	public static void main(String[] args) {
    	List list = Arrays.asList(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;);
        list.forEach(s -&amp;gt; System.out.println(s));
    }
}&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;&lt;b&gt;Q19&lt;/b&gt;: 위 코드 실행 결과로 옳은 것은?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;A B C&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;빈 출력&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 1) A B C&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;list.forEach(s -&amp;gt; System.out.println(s));&lt;/code&gt; 람다식으로 각 요소를 출력&lt;/li&gt;
&lt;li&gt;결과적으로 A, B, C가 순차적으로 콘솔 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*문제 20: 스트림 중간 연산과 최종 연산&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Arrays;

public class StreamTest {
    public static void main(String[] args) {
    	long count = Arrays.asList(&quot;apple&quot;, &quot;banana&quot;, &quot;avocado&quot;, &quot;cherry&quot;).stream()
        					.filter(s -&amp;gt; s.startsWith(&quot;a&quot;))
                            .map(String::toUpperCase)
                            .count();

        System.out.println(&quot;결과: &quot; + count);
    }
}&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;b&gt;Q20&lt;/b&gt;: 위 코드 실행 결과는?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;결과: 1&lt;/li&gt;
&lt;li&gt;결과: 2&lt;/li&gt;
&lt;li&gt;컴파일 에러 발생&lt;/li&gt;
&lt;li&gt;런타임 예외 발생&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;✅ 정답: 2) 결과: 2&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  설명:&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;code&gt;startsWith(&quot;a&quot;)&lt;/code&gt;를 만족하는 문자열: &quot;apple&quot;, &quot;avocado&quot;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;map(String::toUpperCase)&lt;/code&gt;는 대문자로 변환하지만 개수엔 영향 없음&lt;/li&gt;
&lt;li&gt;최종 연산인 &lt;code&gt;count()&lt;/code&gt;로 2 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Java</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/231</guid>
      <comments>https://nstgic3.tistory.com/entry/Java-%EC%A1%B0%EA%B0%81%EB%AA%A8%EC%9D%8C-Quiz1#entry231comment</comments>
      <pubDate>Tue, 4 Feb 2025 14:17:36 +0900</pubDate>
    </item>
    <item>
      <title>예제로 배우는 싱글턴 패턴; 싱글턴은 왜 배울까?</title>
      <link>https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%8B%B1%EA%B8%80%ED%84%B4-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%84%B4%EC%9D%80-%EC%99%9C-%EB%B0%B0%EC%9A%B8%EA%B9%8C</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;왜 우리는 자바를 배우고 있는 와중에 싱글턴 패턴을 배울까? 많은 디자인 패턴이 있지만 왜 싱글턴부터 배우게 될까?&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;싱글턴 패턴은 &lt;b&gt;한 번만 생성되는 객체&lt;/b&gt;를 보장하는 기법으로 많은 자바 개발자들이 싱글턴을 직접 구현하는 것보다 더 자주 접하는 경우가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;바로 &lt;b&gt;스프링에서 제공하는 &quot;싱글턴 빈&quot; 개념&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링을 처음 접하는 주니어 개발자들은 &quot;@Component, @Service, @Bean으로 등록하면 알아서 객체를 관리해준다!&quot;&lt;br /&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;싱글턴 패턴의 기본 원리를 먼저 이해한 후&lt;/b&gt;, 마지막에 스프링이 어떻게 이를 활용하는지 살펴보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;&lt;!-- 싱글턴: 오직 하나의 객체만 보장하자 --&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;싱글턴: 오직 하나의 객체만 보장하자&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt; 먼저 아무런 제약이 없는 일반 클래스에서 시작해보자.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt; 여기서 &amp;ldquo;&lt;b&gt;객체가 하나만 존재해야 하는&lt;/b&gt;&amp;rdquo; 필요성이 어떻게 생기는지 과정을 살펴볼 것입니다.&lt;/span&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;!-- 1. 일반 클래스 --&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1. 일반 클래스&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt; 아래처럼 생성자를 제한하지 않은 일반 클래스는 new 키워드를 통해 원하는 만큼 객체를 만들 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class NormalClass {
    // 생성자를 따로 제한하지 않음
}
&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;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;이 클래스를 테스트할 때 &lt;code&gt;new NormalClass()&lt;/code&gt;로 여러 객체를 만들면, 서로 다른 인스턴스가 생성됩니다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738307402687&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class NormalClassTest {
    public static void main(String[] args) {
        NormalClass obj1 = new NormalClass();
        NormalClass obj2 = new NormalClass();

        System.out.println(&quot;obj1: &quot; + obj1);
        System.out.println(&quot;obj2: &quot; + obj2);

        System.out.println(&quot;두 객체는 같은가? &quot; + (obj1 == obj2));
    }
}&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;new NormalClass()로 생성하면 객체가 계속 새로 만들어집니다.&lt;/li&gt;
&lt;li&gt;obj1 == obj2는 당연히 false입니다.&lt;/li&gt;
&lt;/ul&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;!-- 2. 생성자 접근 제한 --&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2. 생성자 접근 제한&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt; 싱글턴 패턴을 위해서는 생성자를 외부에서 막아야 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;-&amp;gt; 생성자를 private으로 만들면, 외부에서 함부로 &lt;code&gt;new&lt;/code&gt;로 객체를 생성할 수 없게 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class NotSingleton {
    private NotSingleton() {
        // 외부에서 new 불가
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 코드는 &amp;ldquo;new&amp;rdquo;로 객체를 만들 수 없게 막았지만, 이제 객체를 전혀 만들 수 없다는 문제가 생깁니다.&lt;/li&gt;
&lt;li&gt;이대로는 클래스 내부에서만 객체를 만들수 있고, 외부에 반환하는 무언가가 필요합니다.&lt;/li&gt;
&lt;/ul&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;외부에 반환할 방법이 없다면 인스턴스 사용 자체가 불가능&lt;/b&gt;해집니다.&lt;/span&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;!-- 3. 특정 메서드로 인스턴스 반환하기 --&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;3. 특정 메서드로 인스턴스 반환하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 객체를 내부에서 생성하고, 이를 반환하는 정적 메서드를 마련해 봅시다. 그래야 외부에서도 사용할 수 있죠.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class NotSingleton {
    private static NotSingleton instance;
    
    private NotSingleton() {
        // 외부에서 new 불가
    }

    public static NotSingleton getInstance() {
        if (instance == null) {
            instance = new NotSingleton();
        }
        return instance;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;생성자는 여전히 private이므로 new NotSingleton()은 외부에서 불가능합니다.&lt;/li&gt;
&lt;li&gt;getInstance()가 있는 이상, &amp;ldquo;최대 하나의 인스턴스&amp;rdquo;만 만들어지는 구조입니다&lt;/li&gt;
&lt;/ul&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_1738307563732&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class NotSingletonTest {
    public static void main(String[] args) {
        NotSingleton obj1 = NotSingleton.getInstance();
        NotSingleton obj2 = NotSingleton.getInstance();

        System.out.println(&quot;obj1: &quot; + obj1);
        System.out.println(&quot;obj2: &quot; + obj2);
        System.out.println(&quot;두 객체는 같은가? &quot; + (obj1 == obj2));
    }
}&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최초 getInstance() 호출 시 객체가 생성되고, 이후에는 재사용됩니다.&lt;/li&gt;
&lt;li&gt;이제 obj1 == obj2는 true가 됩니다.&lt;/li&gt;
&lt;/ul&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;지연 초기화(Lazy Initialization)&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;/p&gt;
&lt;!-- 4. 이른 초기화(Eager Initialization)로 더 간단하게 --&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;4. 이른 초기화(Eager Initialization)로 더 간단하게&lt;/span&gt;&lt;/h3&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;&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;static final 변수는 클래스가 &lt;b&gt;메모리에 로드될 때 단 한 번 초기화&lt;/b&gt;되기 때문에 static final 변수에 new Singleton()을 바로 할당하여 &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;/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;a href=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EA%B2%B0%EA%B5%AD-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%88%9C%ED%95%9C%EB%A7%9B&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.01.22 - [Java] - 예제로 배우는 결국 알아야하는 JVM 메모리 구조(순한맛)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1738307637697&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;예제로 배우는 결국 알아야하는 JVM 메모리 구조(순한맛)&quot; data-og-description=&quot;개요&amp;nbsp;&amp;nbsp;매운맛은 하단에2024.06.25 - [Java] - 자바가상머신의 메모리 구조: JVM Runtime Data Area&amp;nbsp;자바가상머신의 메모리 구조: JVM Runtime Data Area개요자바가 제공하는 메모리 관리는 할당과 해제를 하여 &quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EA%B2%B0%EA%B5%AD-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%88%9C%ED%95%9C%EB%A7%9B&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EA%B2%B0%EA%B5%AD-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%88%9C%ED%95%9C%EB%A7%9B&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bGWVvA/hyX7S3EDIv/VH6mkCnbUpUlH1lXTqGr4K/img.png?width=594&amp;amp;height=596&amp;amp;face=0_0_594_596,https://scrap.kakaocdn.net/dn/rD91w/hyX7RRb6HE/SjFle1W7KM0vaXpuVceV40/img.png?width=594&amp;amp;height=596&amp;amp;face=0_0_594_596&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EA%B2%B0%EA%B5%AD-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%88%9C%ED%95%9C%EB%A7%9B&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EA%B2%B0%EA%B5%AD-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%88%9C%ED%95%9C%EB%A7%9B&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bGWVvA/hyX7S3EDIv/VH6mkCnbUpUlH1lXTqGr4K/img.png?width=594&amp;amp;height=596&amp;amp;face=0_0_594_596,https://scrap.kakaocdn.net/dn/rD91w/hyX7RRb6HE/SjFle1W7KM0vaXpuVceV40/img.png?width=594&amp;amp;height=596&amp;amp;face=0_0_594_596');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;예제로 배우는 결국 알아야하는 JVM 메모리 구조(순한맛)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요&amp;nbsp;&amp;nbsp;매운맛은 하단에2024.06.25 - [Java] - 자바가상머신의 메모리 구조: JVM Runtime Data Area&amp;nbsp;자바가상머신의 메모리 구조: JVM Runtime Data Area개요자바가 제공하는 메모리 관리는 할당과 해제를 하여&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Singleton {
    private static final Singleton instance = new Singleton();

    private Singleton() {
        // 외부에서 new 불가
    }

    public static Singleton getInstance() {
        return instance;
    }
}&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;private static final Singleton instance에서 이미 new로 객체가 만들어집니다.&lt;/li&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;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;이렇게 하면 &amp;ldquo;오직 하나의 객체만 보장&amp;rdquo;이라는 &lt;b&gt;싱글턴의 핵심 특징&lt;/b&gt;을 만족합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;!-- 최종 코드: 싱글턴 패턴(이른 초기화) --&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;최종 코드: 싱글턴 패턴(이른 초기화)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Singleton {
    private static final Singleton instance = new Singleton();
    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}




public class SingletonTest {
    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        
        System.out.println(&quot;s1: &quot; + s1);
        System.out.println(&quot;s2: &quot; + s2);
        System.out.println(&quot;두 객체는 같은가? &quot; + (s1 == s2));
    }
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;!-- 성능과 간단함 비교 --&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;성능과 장단점 비교&lt;/span&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;이른 초기화(Eager Initialization)&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지연 초기화(Lazy Initialization)&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ol&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;ldquo;한 번만 쓸&amp;rdquo; 확률이 높은 경우가 많아, 이른 초기화를 많이 사용합니다.&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;!-- 정리 --&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;마무리&lt;/span&gt;&lt;/h3&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;로 시작하면 new 키워드로 계속 객체가 생성되어 싱글턴이 아님.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;생성자 private&lt;/b&gt; + 정적 메서드(getInstance) 로 &amp;ldquo;하나의 객체&amp;rdquo;를 강제한다.&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;우리가 스프링에서 @Component나 @Service 같은 어노테이션을 붙이면 &lt;b&gt;스프링 컨테이너(ApplicationContext)가 자동으로 싱글턴 객체를 생성&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;즉, 직접 new로 객체를 만들지 않아도 스프링 내에서&amp;nbsp;&lt;b&gt;한 번만 생성된 인스턴스를 재사용&lt;/b&gt;한다.&lt;br /&gt;(이런 동작이 &lt;b&gt;스프링의 기본적인 &quot;빈 스코프&quot;가 싱글턴인 이유&lt;/b&gt;다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;싱글턴 패턴을 이해하면, 스프링이 어떻게 객체를 효율적으로 관리하는지 자연스럽게 이해할 수 있고,&lt;/b&gt;&lt;br /&gt;&lt;b&gt;자바에서 싱글턴을 직접 구현할 일은 많지 않지만, 원리를 알아두면 스프링의 동작을 더 깊이 이해할 수 있다.&lt;/b&gt;&lt;/p&gt;</description>
      <category>CS</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/230</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%8B%B1%EA%B8%80%ED%84%B4-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%84%B4%EC%9D%80-%EC%99%9C-%EB%B0%B0%EC%9A%B8%EA%B9%8C#entry230comment</comments>
      <pubDate>Fri, 31 Jan 2025 16:41:43 +0900</pubDate>
    </item>
    <item>
      <title>Kent Beck 구현패턴 Ch02-03; 원칙과 패턴: 복잡성을 다루는 방법</title>
      <link>https://nstgic3.tistory.com/entry/Kent-Beck-%EA%B5%AC%ED%98%84%ED%8C%A8%ED%84%B4-Ch02-03-%EC%9B%90%EC%B9%99%EA%B3%BC-%ED%8C%A8%ED%84%B4-%EB%B3%B5%EC%9E%A1%EC%84%B1%EC%9D%84-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
      <description>&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&lt;b&gt;왜 이런 개념을 배워야할까? &lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;개발을 하다 보면 단순히 코드를 작성하는 것뿐만 아니라, &lt;b&gt;코드를 수정하고 유지보수하는 과정&lt;/b&gt;이 점점 더 중요해진다는 것을 깨닫게 된다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt; 간단한 프로그램을 만들 때는 크게 상관없지만, 프로젝트가 커지고 팀 단위로 협업하게 되면 코드가 복잡해지고 수정이 어려워진다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;이때 객체 지향 프로그래밍(OOP)의 핵심 원칙과 패턴을 이해하고 활용하면 &lt;b&gt;코드를 더 쉽게 이해하고, 수정할 때 최소한의 영향을 주면서도 확장 가능하게 만들 수 있다&lt;/b&gt;.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;예를 들어, 단순히 extends 키워드를 사용해서 상속을 적용하는 것만으로는 좋은 OOP 설계를 했다고 할 수 없다. 상속을 왜 해야 하는지, 언제 하면 안 되는지, 그리고 더 좋은 방법은 무엇인지 고민해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;이 글에서는 OOP의 주요 가치(커뮤니케이션, 단순성, 유연성)와 원칙(지역적 변화, 최소 중복, 로직과 데이터 결합, 대칭성, 선언적 표현, 변화율)을 이해하고, 이를 코드에서 어떻게 구현할 수 있는지 예제와 함께 설명할 것이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;패턴이란 무엇인가?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;프로그래밍이란 무엇인가? 왜 변수가 존재하는가? 메서드는? 상속 관계는? 접근 제한자는? 클래스의 개념과 인스턴스의 개념은 왜 탄생했는가?&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;사실 객체지향뿐만 아니라 여러 디자인 패턴을 이해하려면 위의 의문이 와닿아야 한다. &lt;b&gt;우리는 왜 시스템을 더 복잡하게 만드는가?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;켄트 백의 말을 빌리면&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;프로그램은 새로 짜는 것보다 기존의 것을 읽는 게 더 많다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;프로그램은 완성되지 않는다. 계속된 수정만이 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;수많은 상태와 흐름이 존재하고 이를 프로그램으로 명시하고 제어해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;함께 일하고, 함께 일할 동료들이 개념을 이해하고 세부 사항에 대해서 이해해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;세부 사항을 이해해야 전체 그림이 보이고, 전체 그림이 보여야 세부 사항을 이해할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;이미 많은 사람들이 경험으로 축적한 &lt;b&gt;디자인 패턴&lt;/b&gt;들은 이런 과정을 더 빠르고 효율적으로 만들어준다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;적절한 패턴 사용은 불필요한 재개발 비용을 줄이고, 새로운 기능에 집중할 시간을 벌어준다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;패턴을 통해 빠르고 저렴하게 문제 해결이 가능하며, 실질적으로 시간이 필요한 기능을 개발할 시간을 확보할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #ffffff;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;프로그래밍 이론&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;완벽한 패턴은 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;br /&gt;담백한 후라이드와 매콤달콤한 양념치킨처럼 &lt;b&gt;모든 상황을 커버하는 패턴은 존재하지 않는다.&lt;/b&gt;&lt;/span&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;span style=&quot;background-color: #ffffff; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;상황마다 요구사항과 제약이 다르기 때문에, &amp;lsquo;최적&amp;rsquo;이라 여겨지는 패턴도 다른 맥락에선 적합하지 않을 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;결국 우리가 고려해야 할 핵심 기준은 &lt;b&gt;가치(value)&lt;/b&gt;와 &lt;b&gt;원칙(principle)&lt;/b&gt;이다.&lt;/span&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;과연 어떤 것이 가치 있는 프로그램일까?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;말 그대로 코드가, 패턴이 가질수 있고 보여지고 있는 가치이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;1. 커뮤니케이션&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;코드가 명확하다면, 개발자가 빠르게 이해하고 수정할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;이는 곧 &lt;b&gt;시간&amp;middot;비용 절감&lt;/b&gt;으로 이어진다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;주석, 함수명, 구조를 통해 &lt;b&gt;의도를 분명히 드러내고, 복잡도를 줄여야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;코드가 팀원과 소통하듯, 의도를 선명히 전하는 것이 중요하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;예: int cost = 0; &amp;rarr; int의 초기값이 0임을 알면서도 선언하는 이유는 가독성 때문이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;잘못된 예시 (가독성이 떨어지는 코드)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class User {
    int a;
    boolean b;

    public User(int a, boolean b) {
        this.a = a;
        this.b = b;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; letter-spacing: 0px;&quot;&gt;&amp;gt; a와 b가 무엇을 의미하는지 전혀 알 수 없다. 이런 코드는 협업 시 가독성을 떨어뜨린다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;개선된 예시 (명확한 네이밍과 의미 부여)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class User {
    private int age;
    private boolean isActive;

    public User(int age, boolean isActive) {
        this.age = age;
        this.isActive = isActive;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;의미를 알 수 있도록 필드명을 변경했다.&lt;/span&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;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&amp;gt; 이제 이 클래스를 처음 보는 사람도 User 객체가 age와 isActive &lt;b&gt;상태를 가진다는 것&lt;/b&gt;을 이해할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;2. 단순성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;복잡도를 낮추면 유지보수가 쉬워진다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;불필요한 코드와 과도한 설계를 제거하라.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;단순한 구조는 오류 가능성을 줄이고, 변경 시 다른 부분에 미치는 영향을 최소화한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;잘못된 예시 (과도한 설계)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public abstract class Animal {
    abstract void makeSound();
}

public class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println(&quot;Bark&quot;);
    }
}

public class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println(&quot;Meow&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;이 코드에서는 makeSound()를 위한 상속이 과도하게 사용되었다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt; &amp;gt; 단순히 메서드 하나만 다르게 동작하는 경우라면 굳이 &lt;b&gt;상속을 사용할 필요가 없다.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;개선된 예시 (단순한 구조로 변경)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Animal {
    private String sound;

    public Animal(String sound) {
        this.sound = sound;
    }

    public void makeSound() {
        System.out.println(sound);
    }
}

// 사용 예시
Animal dog = new Animal(&quot;Bark&quot;);
Animal cat = new Animal(&quot;Meow&quot;);
dog.makeSound();
cat.makeSound();
&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;단순히 sound 속성만 다를 경우, &lt;b&gt;상속을 사용할 필요 없이 하나의 클래스로 표현&lt;/b&gt;할 수 있다.&lt;/span&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;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&amp;gt; 불필요한 클래스를 줄여 코드의 복잡도를 낮췄다.&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;3. 유연성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;수정이 쉽게 이루어질 수 있도록 구조를 유연하게 설계하는 것이 중요하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;필요 이상으로 확장에 대비해 복잡도를 높이는 것은 피해야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;당장 유용하고, 미래에 발전 가능성이 높은 부분부터 유연성을 적용해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;실제 운영 경험을 쌓아야 어떤 서비스인지, 어떤 클라이언트와 함께 작업하는지에 따라서 설계의 방향이 명확해진다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;잘못된 예시 (변경에 취약한 코드)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class PaymentProcessor {
    public void processCreditCardPayment() {
        System.out.println(&quot;Processing credit card payment&quot;);
    }

    public void processPaypalPayment() {
        System.out.println(&quot;Processing PayPal payment&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #f6e199;&quot;&gt;&amp;gt; 새로운 결제 방식이 추가될 때마다 새로운 메서드를 만들어야 하므로 확장성이 떨어진다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;*개선된 예시 (전략 패턴 적용으로 유연성 증가)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface PaymentStrategy {
    void pay();
}

class CreditCardPayment implements PaymentStrategy {
    @Override
    public void pay() {
        System.out.println(&quot;Processing credit card payment&quot;);
    }
}

class PaypalPayment implements PaymentStrategy {
    @Override
    public void pay() {
        System.out.println(&quot;Processing PayPal payment&quot;);
    }
}

class PaymentProcessor {
    private PaymentStrategy strategy;

    public PaymentProcessor(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void processPayment() {
        strategy.pay();
    }
}

// 사용 예시
PaymentProcessor processor = new PaymentProcessor(new CreditCardPayment());
processor.processPayment();
&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;새로운 결제 방식이 추가될 때 기존 코드를 수정할 필요 없이 새로운 클래스를 추가하면 된다.&lt;/span&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;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&amp;gt; OCP(개방-폐쇄 원칙, Open-Closed Principle)를 준수하여 &lt;b&gt;확장에는 열려 있고, 변경에는 닫혀 있는 구조&lt;/b&gt;를 만든다.&lt;/span&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;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #ffffff;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #ffffff;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;원칙: 어떤 원칙을 지켜야 할까?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;패턴이 생기고 정립된 데에는 이유가 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;위에서 설명한 &lt;b&gt;가치(value)&lt;/b&gt; 중 하나 이상을 확실하게 내포하고 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;대부분 &lt;b&gt;코드 수정 비용을 낮추고 가치를 극대화하는 목적&lt;/b&gt;을 갖는다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;1. 지역적 변화 (Local Consequences)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;핵심 요점:&lt;/b&gt; &lt;b&gt;수정 범위를 최소화하라.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;프로그램 일부만 고쳐도 여러 곳이 연쇄적으로 깨진다면, 유지보수 비용이 기하급수적으로 올라간다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;관심사가 명확히 분리된 구조는 &lt;b&gt;&amp;lsquo;지역적&amp;rsquo; 변화&lt;/b&gt;가 가능하게 하며, 개발자 간 커뮤니케이션도 쉬워진다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;소프트웨어는 변경될 수밖에 없다. 그러나 변경이 필요할 때 &lt;b&gt;한 곳을 수정하면 연쇄적으로 다른 여러 부분을 수정해야 한다면 유지보수 비용이 기하급수적으로 증가한다.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;따라서, 코드 구조를 설계할 때 &lt;b&gt;변경이 필요한 범위를 최소화하고, 다른 코드에 미치는 영향을 줄이는 것이 중요하다.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;잘못된 예시 (변경이 여러 곳에 영향을 주는 코드)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;예를 들어, 직원(Employee)의 급여를 계산하는 시스템이 있다고 가정하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738285896085&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Employee {
    private String name;
    private double baseSalary;

    public Employee(String name, double baseSalary) {
        this.name = name;
        this.baseSalary = baseSalary;
    }

    public double calculateSalary(String type) {
        if (type.equals(&quot;Manager&quot;)) {
            return baseSalary * 1.2; // 관리자 보너스
        } else if (type.equals(&quot;Engineer&quot;)) {
            return baseSalary * 1.1; // 엔지니어 보너스
        } else {
            return baseSalary; // 기본 급여
        }
    }
}&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #f6e199;&quot;&gt;&amp;gt; 새로운 직원 유형이 추가되면 calculateSalary() 메서드를 수정해야 한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;calculateSalary()를 수정할 때 기존의 로직을 건드려야 하므로, &lt;b&gt;사이드 이펙트(부작용)가 발생할 가능성이 높다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;급여 계산 로직이 Employee 클래스 내부에 있으므로, &lt;b&gt;급여 정책이 변경되면 모든 Employee 객체에 영향을 미친다.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;개선된 예시 (변경 범위를 최소화한 코드 - 개방/폐쇄 원칙 적용)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;이제 &lt;b&gt;변경이 필요한 범위를 한 곳으로 모으고&lt;/b&gt;, 기존의 코드를 수정하지 않고 새로운 기능을 추가할 수 있도록 설계해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738285940407&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface SalaryCalculator {
    double calculateSalary(double baseSalary);
}

class ManagerSalary implements SalaryCalculator {
    @Override
    public double calculateSalary(double baseSalary) {
        return baseSalary * 1.2;
    }
}

class EngineerSalary implements SalaryCalculator {
    @Override
    public double calculateSalary(double baseSalary) {
        return baseSalary * 1.1;
    }
}

class DefaultSalary implements SalaryCalculator {
    @Override
    public double calculateSalary(double baseSalary) {
        return baseSalary;
    }
}

public class Employee {
    private String name;
    private double baseSalary;
    private SalaryCalculator salaryCalculator;

    public Employee(String name, double baseSalary, SalaryCalculator salaryCalculator) {
        this.name = name;
        this.baseSalary = baseSalary;
        this.salaryCalculator = salaryCalculator;
    }

    public double calculateSalary() {
        return salaryCalculator.calculateSalary(baseSalary);
    }
}&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #f6e199;&quot;&gt;&lt;b&gt;&amp;gt; &lt;/b&gt;새로운 직원 &lt;b&gt;유형이 추가되더라도 기존 Employee 클래스를 수정할 필요가 없다&lt;/b&gt;.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;예를 들어 InternSalary 클래스를 추가하면, Employee 클래스는 그대로 유지된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;즉, &lt;b&gt;변경이 필요한 범위를 SalaryCalculator 인터페이스 구현체로 한정했다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #f6e199;&quot;&gt;&amp;gt; 급여 &lt;b&gt;정책이 변경되더라도 기존 직원 객체(Employee)에는 영향이 없다&lt;/b&gt;.&lt;/span&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;span style=&quot;background-color: #ffffff; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&lt;b&gt;객체 간 책임이 분리되어 있어 유지보수가 쉬워진다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;항상 생각해야되는 케이스이기 때문에 또 다른 예제도 확인해보자.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;잘못된 예시 2 (변경이 여러 곳에 영향을 주는 코드)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738286039660&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Product {
    private String name;
    private double price;
    private String currency; // USD, EUR, KRW

    public Product(String name, double price, String currency) {
        this.name = name;
        this.price = price;
        this.currency = currency;
    }

    public double getPriceInUSD() {
        if (currency.equals(&quot;EUR&quot;)) {
            return price * 1.1; // 유로 -&amp;gt; 달러 환율
        } else if (currency.equals(&quot;KRW&quot;)) {
            return price * 0.0008; // 원 -&amp;gt; 달러 환율
        } else {
            return price; // 이미 달러라면 변환 없음
        }
    }
}&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;새로운 통화가 추가되면 getPriceInUSD() 메서드를 수정해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;환율 변경 시 Product 클래스 자체를 수정해야 하므로 &lt;b&gt;수정 범위가 커진다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&amp;gt; 통화 변환 로직이 Product와&lt;b&gt; 강하게 결합&lt;/b&gt;되어 있어 변경에 취약하다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;개선된 예시 2 (변경 범위를 최소화한 코드 - 개방/폐쇄 원칙 적용)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738286095178&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface CurrencyConverter {
    double convertToUSD(double amount);
}

class KRWConverter implements CurrencyConverter {
    @Override
    public double convertToUSD(double amount) {
        return amount * 0.0008;
    }
}

class EURConverter implements CurrencyConverter {
    @Override
    public double convertToUSD(double amount) {
        return amount * 1.1;
    }
}

class DefaultConverter implements CurrencyConverter {
    @Override
    public double convertToUSD(double amount) {
        return amount; // USD 그대로 유지
    }
}

public class Product {
    private String name;
    private double price;
    private CurrencyConverter currencyConverter;

    public Product(String name, double price, CurrencyConverter currencyConverter) {
        this.name = name;
        this.price = price;
        this.currencyConverter = currencyConverter;
    }

    public double getPriceInUSD() {
        return currencyConverter.convertToUSD(price);
    }
}&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;새로운 통화가 추가되더라도 기존 Product 클래스를 수정할 필요가 없다.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;예를 들어 JPYConverter 클래스를 추가하면 Product는 수정 없이 사용할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&amp;gt; 환율이 바뀌어도 CurrencyConverter 인터페이스 &lt;b&gt;구현체만 변경&lt;/b&gt;하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&amp;gt; Product는 가격과 제품 정보만 관리하며, &lt;b&gt;통화 변환 로직을 분리하여 관심사 분리를 실현&lt;/b&gt;했다.&lt;/span&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;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;변경이 필요한 범위를 최소화하면, 사이드 이펙트(부작용) 없이 기존 코드의 안정성을 유지할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;OCP(개방-폐쇄 원칙, Open-Closed Principle)를 적용하면, 확장에는 열려 있고, 변경에는 닫혀 있는 구조가 된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;관심사를 분리하여 변경이 필요한 부분만 수정하면 되도록 설계하면 유지보수가 훨씬 쉬워진다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;지역적 변화를 최소화하는 것은 단순한 설계 기법이 아니라, 코드 유지보수성을 극대화하는 핵심 원칙이다.이 원칙을 잘 이해하고 적용하면, 변경이 필요할 때마다 기존 코드를 수정하지 않고도 확장할 수 있는 유연한 시스템을 만들 수 있다.&lt;/span&gt;&lt;/blockquote&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;2. 최소 중복 (Minimize Duplication)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;핵심 요점:&lt;/b&gt; &lt;b&gt;중복 코드는 수정 비용을 높인다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;프로그램을 작은 단위(짧은 메서드, 작은 객체, 모듈 등)로 나누면 &lt;b&gt;중복을 찾고 제거하기 쉬워진다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;잘못된 예시 (중복된 코드 사용)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class UserService {
    public void createUser(String name) {
        System.out.println(&quot;User &quot; + name + &quot; created.&quot;);
    }

    public void updateUser(String name) {
        System.out.println(&quot;User &quot; + name + &quot; updated.&quot;);
    }
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #f6e199;&quot;&gt;&amp;gt; User 관련 로직이 중복되어 있다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;개선된 예시 (중복 제거)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class UserService {
    private void logUserAction(String action, String name) {
        System.out.println(&quot;User &quot; + name + &quot; &quot; + action + &quot;.&quot;);
    }

    public void createUser(String name) {
        logUserAction(&quot;created&quot;, name);
    }

    public void updateUser(String name) {
        logUserAction(&quot;updated&quot;, name);
    }
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&amp;gt; 공통 로직을 logUserAction &lt;b&gt;메서드로 분리하여 중복을 제거&lt;/b&gt;했다.&lt;/span&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;3. 로직과 데이터의 결합 (Keep Logic and Data Together)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;핵심 요점:&lt;/b&gt; &lt;b&gt;함께 변하는 로직과 데이터는 가까운 범위에 둬라.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;관련된 데이터와 로직이 서로 떨어져 있으면, 변경 시 양쪽을 수정해야 하므로 부담이 커진다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;같은 객체나 패키지 내에서 로직과 데이터를 밀접하게 유지하면 &lt;b&gt;수정 비용이 줄어든다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;로직과 데이터가 분리되어 있으면, 변경 시 여러 곳을 수정해야 하고, 코드 이해가 어려워진다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;예를 들어, 학생 정보를 관리하는 시스템에서 학생의 성적을 평가하는 로직이 별도의 유틸리티 클래스에 존재한다고 해보자.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;잘못된 예시 (성적 평가와 관리가 동시에 존재)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Student {
    private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public int getScore() {
        return score;
    }
}

public class GradeUtil {
    public static String getGrade(int score) {
        if (score &amp;gt;= 90) return &quot;A&quot;;
        if (score &amp;gt;= 80) return &quot;B&quot;;
        if (score &amp;gt;= 70) return &quot;C&quot;;
        return &quot;F&quot;;
    }
}


&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #f6e199;&quot;&gt;&amp;gt; 학생이 &lt;b&gt;성적을 평가하는 방법이 바뀌면 GradeUtil과 Student 클래스를 함께 수정&lt;/b&gt;해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;로직과 데이터를 함께 묶어 Student 클래스 내에서 관리하면 유지보수가 훨씬 용이하다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;개선된 예시 (로직과 데이터를 분리)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Student {
    private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public String getGrade() {
        if (score &amp;gt;= 90) return &quot;A&quot;;
        if (score &amp;gt;= 80) return &quot;B&quot;;
        if (score &amp;gt;= 70) return &quot;C&quot;;
        return &quot;F&quot;;
    }
}


&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&amp;gt; 이제 성적 평가 방식이 변경되더라도 &lt;b&gt;Student 클래스만 수정&lt;/b&gt;&lt;/span&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;4. 대칭성 (Symmetry)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;핵심 요점:&lt;/b&gt; &lt;b&gt;한 객체 안의 필드들은 함께 생성되고 함께 소멸된다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;대칭적인 구조를 고려하면 코드가 왜 그렇게 작성되었는지 이해하기 쉬워진다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;예: count++ 대신 incrementCount() 사용 &amp;rarr; &lt;b&gt;의도가 더 명확해진다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;코드를 작성할 때 객체의 생성과 소멸이 비대칭적으로 이루어지면 &lt;b&gt;메모리 누수나 예측하기 어려운 버그&lt;/b&gt;가 발생할 수 있다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;예를 들어, 데이터베이스 연결을 관리하는 코드에서 &lt;b&gt;객체가 명확하게 해제되지 않는 경우&lt;/b&gt;를 생각해보자.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;잘못된 예시 (연결에 대한 메서드만 구현)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class DatabaseConnection {
    private Connection connection;

    public DatabaseConnection() throws SQLException {
        this.connection = DriverManager.getConnection(&quot;jdbc:mysql://localhost:3306/mydb&quot;, &quot;user&quot;, &quot;password&quot;);
    }

    public Connection getConnection() {
        return connection;
    }
}



&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&amp;gt; 이 경우, DatabaseConnection 객체를 생성한 후, &lt;b&gt;연결을 닫지 않으면 계속 유지되어 메모리 누수가 발생할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;이를 해결하기 위해서는 &lt;b&gt;생성과 소멸을 대칭적으로 유지&lt;/b&gt;해야 한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;개선된 예시 (생성과 소멸을 대칭적으로 유지)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class DatabaseConnection implements AutoCloseable {
    private Connection connection;

    public DatabaseConnection() throws SQLException {
        this.connection = DriverManager.getConnection(&quot;jdbc:mysql://localhost:3306/mydb&quot;, &quot;user&quot;, &quot;password&quot;);
    }

    public Connection getConnection() {
        return connection;
    }

    @Override
    public void close() throws SQLException {
        if (connection != null) {
            connection.close();
        }
    }
}

// 사용 예시
try (DatabaseConnection dbConn = new DatabaseConnection()) {
    Connection conn = dbConn.getConnection();
    // 데이터베이스 작업 수행
} catch (SQLException e) {
    e.printStackTrace();
}


&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&amp;gt; 이제 try-with-resources를 사용하여&lt;b&gt; DatabaseConnection 객체가 자동으로 닫히도록 보장&lt;/b&gt;할 수 있다.&lt;/span&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;5. 선언적 표현 (Declarative Expression)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;핵심 요점:&lt;/b&gt; &lt;b&gt;순서가 중요하지 않을 땐 선언형이 이해하기 쉽다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;명령형 코드는 유연성이 높지만, 제어 흐름을 따라가며 상태 변화를 추적해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;예: JUnit 4의 @RunWith(Suite.class) &amp;rarr; &lt;b&gt;무엇을 하는지 직관적으로 파악 가능하다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;절차지향적인 코드(명령형 프로그래밍)는 동작을 세세하게 기술하지만, &lt;b&gt;선언적 코드&lt;/b&gt;는 &quot;무엇을 해야 하는지&quot;에 집중하여 가독성을 높인다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;예를 들어, 리스트에서 짝수를 찾아 제곱한 후 출력하는 로직을 명령형 방식으로 작성하면 다음과 같다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;잘못된 예시 (명령형 방식으로 짜여진 코드)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List&amp;lt;Integer&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();

for (int number : numbers) {
    if (number % 2 == 0) {
        result.add(number * number);
    }
}

for (int num : result) {
    System.out.println(num);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #f6e199;&quot;&gt;&amp;gt; &lt;b&gt;반복문과 조건문을 따라가며 로직을 해석해야 하므로 가독성이 떨어진다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;같은 기능을 선언형 방식으로 개선하면 다음과 같다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;개선된 예시 (의도를 코드에 녹여낸 선언적 방식)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
numbers.stream()
       .filter(n -&amp;gt; n % 2 == 0)
       .map(n -&amp;gt; n * n)
       .forEach(System.out::println);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #f6e199;&quot;&gt;&amp;gt; &lt;b&gt;&quot;짝수를 필터링하고(map), 제곱한 후(forEach) 출력한다&quot;는 의도가 즉시 파악 가능하다.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;따라서 Collection이 일반for 문보다 성능이 안좋지만 실무에서 사용되는 이유도 선언적 방식으로 작성이 가능하기에 해당 메서드를 작성하는 의도가 보여진다 라는 장점에 의해 사용되는것이다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;6. 변화율 (Rate of Change)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;핵심 요점:&lt;/b&gt; &lt;b&gt;함께 변하는 것끼리 묶고, 다른 주기로 변하는 것들은 분리하라.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;코드나 데이터가 변할 때마다 &lt;b&gt;엮인 부분 전체를 고쳐야 한다면 유지보수성이 크게 떨어진다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;불필요한 필드는 &lt;b&gt;지역 변수로 내리거나&lt;/b&gt;, 여러 파라미터 대신 Money 객체처럼 의미 단위로 합치는 방식을 사용하면 수정이 간단해진다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;변화율을 고려하지 않으면 코드 수정이 있을 때 불필요한 부분까지 수정해야 하고, 유지보수 비용이 증가한다. 함께 변하는 것들은 한 곳에 모으고, 서로 다른 주기로 변하는 것들은 분리해야 한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;예를 들어, 쇼핑몰에서 &lt;b&gt;배송비 계산 방식&lt;/b&gt;이 자주 바뀌지만, &lt;b&gt;주문 정보&lt;/b&gt;는 거의 변하지 않는다고 가정해 보자. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;변화를 고려하지 않고 코드를 작성하면 다음과 같다&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;잘못된 예시 ( 변화주기를 고려하지 않은 코드)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Order {
    private double totalPrice;

    public Order(double totalPrice) {
        this.totalPrice = totalPrice;
    }

    public double calculateFinalPrice(String shippingMethod) {
        double shippingCost = 0;
        if (shippingMethod.equals(&quot;standard&quot;)) {
            shippingCost = 5.0;
        } else if (shippingMethod.equals(&quot;express&quot;)) {
            shippingCost = 10.0;
        }
        return totalPrice + shippingCost;
    }
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&amp;gt; 이 코드에서 &lt;b&gt;배송비 정책이 바뀔 때마다 Order 클래스를 수정해야 하는 문제&lt;/b&gt;가 발생한다.&lt;/span&gt; &lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;하지만 Order는 주문과 관련된 로직만을 다뤄야 하며, 배송비 정책은 별도의 개념이므로 따로 분리하는 것이 바람직하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;변화율을 고려하여 리팩토링하면 다음과 같이 개선할 수 있다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;개선된 예시 (변화율을 고려한 분리- 배송비 정책과 주문 정보의 분리)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738284080227&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface ShippingStrategy {
    double calculateShippingCost();
}

class StandardShipping implements ShippingStrategy {
    @Override
    public double calculateShippingCost() {
        return 5.0;
    }
}

class ExpressShipping implements ShippingStrategy {
    @Override
    public double calculateShippingCost() {
        return 10.0;
    }
}

public class Order {
    private double totalPrice;
    private ShippingStrategy shippingStrategy;

    public Order(double totalPrice, ShippingStrategy shippingStrategy) {
        this.totalPrice = totalPrice;
        this.shippingStrategy = shippingStrategy;
    }

    public double calculateFinalPrice() {
        return totalPrice + shippingStrategy.calculateShippingCost();
    }
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #ffffff;&quot;&gt; 이제 &lt;b&gt;배송비 정책이 바뀌어도 ShippingStrategy만 수정하면 되고, Order 클래스는 그대로 유지된다&lt;/b&gt;.&lt;br /&gt;&lt;/span&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;span style=&quot;color: #333333; background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;gt; 즉, 주문 정보와 배송비&lt;b&gt; 정책의 변화율이 다르므로 이를 분리하여 유지보수를 쉽게 만든다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #ffffff;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #ffffff;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;이 글에서 다룬 OOP 원칙과 예제들은 단순히 이론이 아니라 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;&lt;b&gt;실제 프로젝트에서 코드를 더 읽기 쉽게 만들고 유지보수성을 높이기 위한 필수적인 개념&lt;/b&gt;이다.&lt;/span&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;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;처음에는 이 원칙들이 다소 &lt;b&gt;추상적으로 느껴질 수 있지만&lt;/b&gt;, 코드를 작성하고 리뷰받는 과정을 거치면서 점점 더 필요성을 체감하게 될 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;좋은 코드는 혼자 읽을 때뿐만 아니라, 팀원과 함께 협업할 때도 이해하기 쉬운 코드이다.&lt;/span&gt;&lt;/blockquote&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;&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333; background-color: #ffffff;&quot;&gt;이 원칙들을 염두에 두고 개발하면, 더 나은 코드 품질을 유지하면서도 성장할 수 있을 것이다&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS</category>
      <category>OOP</category>
      <category>객체지향</category>
      <category>구현패턴</category>
      <category>디자인패턴</category>
      <category>켄트백</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/229</guid>
      <comments>https://nstgic3.tistory.com/entry/Kent-Beck-%EA%B5%AC%ED%98%84%ED%8C%A8%ED%84%B4-Ch02-03-%EC%9B%90%EC%B9%99%EA%B3%BC-%ED%8C%A8%ED%84%B4-%EB%B3%B5%EC%9E%A1%EC%84%B1%EC%9D%84-%EB%8B%A4%EB%A3%A8%EB%8A%94-%EB%B0%A9%EB%B2%95#entry229comment</comments>
      <pubDate>Fri, 31 Jan 2025 10:21:12 +0900</pubDate>
    </item>
    <item>
      <title>Java 조각모음 [4]</title>
      <link>https://nstgic3.tistory.com/entry/Java-%EC%A1%B0%EA%B0%81%EB%AA%A8%EC%9D%8C-4</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;이번 포스팅에서 나오는 주요 키워드&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;함수 (Function)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;클래스 (Class)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변수 (Variable)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메서드 (Method)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;추상화 (Abstraction)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;캡슐화 (Encapsulation)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JVM (Java Virtual Machine)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴파일 (Compile)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;런타임 (Runtime)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;static 키워드 (Static Keyword)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;this 키워드 (This Keyword)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;call by value / call by reference&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다형성 (Polymorphism)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상속 (Inheritance)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;접근 제어자 (Access Modifier)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가비지 컬렉션 (Garbage Collection)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;본문&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q1. 자바에서 함수가 무엇인지 설명하시오.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A1. 함수는 &lt;br /&gt;입력값을 받아서 출력값을 반환하는 기능을 수행하는 코드의 묶음&lt;br /&gt;코드의 재사용성을 높이고, 코드의 가독성을 높이며, 유지보수를 쉽게 만들어준다.&amp;nbsp;&lt;br /&gt;메소드라고도 불리며, 클래스 내부에 선언되어 사용된다. &lt;br /&gt;반환값이 없을 수도 있고, 여러 개의 입력값을 받을 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q2. 클래스란 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A2. 클래스는 객체를 생성하기 위한 설계도나 청사진입니다. 객체의 상태(속성)와 행위(기능)를 정의하는 틀로, 변수와 메서드로 구성됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q3. 클래스에서 '변수'와 '메서드'는 각각 무엇을 의미하나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A3. &lt;br /&gt;변수: 객체의 상태나 속성을 나타내며, 클래스 내에서 선언된 필드(Field)&lt;br /&gt;예를 들어, 자동차 클래스의 변수로는 color, speed 등이 있을 수 있습니다.&lt;br /&gt;&lt;br /&gt;메서드: 객체가 수행할 수 있는 동작이나 기능&lt;br /&gt;예를 들어, 자동차 클래스에서 drive()나 stop() 같은 메서드가 있을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q4. 추상화란 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A4. 추상화는 필요한 정보만 남기고 불필요한 세부사항을 제거하는 과정이다, 이를 통해 현실 세계의 개념을 클래스 형태로 모델링한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예를 들어, 자동차라는 현실 개념에서 색상, 속도, 브랜드만 남기고 나머지 세부사항은 제외하는 것을 의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q5. 클래스와 객체의 관계는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A5. 클래스는 설계도이고, 객체는 그 설계도를 기반으로 생성된 구체적인 인스턴스다.&lt;br /&gt;예를 들어, Car라는 클래스가 있다면, Car myCar = new Car();로 생성된 myCar는 클래스의 객체다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q6. 클래스의 접근 제어자에 대해서 설명하고 이를 활용해서 어떤 전략을 세울 수 있을까요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A6. 클래스의 접근 제어자는 클래스의 외부로부터의 접근을 제어하는 키워드, 클래스의 멤버 변수나 메서드에 대한 접근 범위를 설정할 수 있다. &lt;br /&gt;&lt;br /&gt;이를 통해 캡슐화를 구현하고, 정보 은닉을 통해 객체의 무결성을 보호할 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public: 어디서든 접근 가능
protected: 같은 패키지 내에서, 그리고 상속받은 클래스에서 접근 가능
default: 같은 패키지 내에서만 접근 가능
private: 같은 클래스 내에서만 접근 가능&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vVpHo/btsLYwk337K/uRm4goMUZeFJLxjnoZwVp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vVpHo/btsLYwk337K/uRm4goMUZeFJLxjnoZwVp1/img.png&quot; data-alt=&quot;https://stackoverflow.com/questions/215497/what-is-the-difference-between-public-protected-package-private-and-private-in&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vVpHo/btsLYwk337K/uRm4goMUZeFJLxjnoZwVp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvVpHo%2FbtsLYwk337K%2FuRm4goMUZeFJLxjnoZwVp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1000&quot; height=&quot;500&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://stackoverflow.com/questions/215497/what-is-the-difference-between-public-protected-package-private-and-private-in&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q7. 클래스가 적재되고, 실행되는 과정을 JVM 메모리 구조를 기반으로 순차적으로 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A7. JVM 메모리 구조는 크게 Method Area, Heap, Stack, PC Register, Native Method Stack으로 구성된다.&lt;br /&gt;&lt;br /&gt;클래스 파일 로딩 후 Method Area에 클래스 메타데이터가 저장되고, 객체 생성 시 Heap에 인스턴스가 생성되며, 메서드 호출 시 Stack에서 실행된다.&lt;br /&gt;더 이상 사용되지 않는 객체는 GC에 의해 정리됩니다.&lt;br /&gt;&lt;br /&gt;자세히 알아보기 &lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;⬇️&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EA%B2%B0%EA%B5%AD-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%88%9C%ED%95%9C%EB%A7%9B&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.01.22 - [Java] - 예제로 배우는 결국 알아야하는 JVM 메모리 구조(순한맛)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737620600623&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;예제로 배우는 결국 알아야하는 JVM 메모리 구조(순한맛)&quot; data-og-description=&quot;개요&amp;nbsp;&amp;nbsp;매운맛은 하단에2024.06.25 - [Java] - 자바가상머신의 메모리 구조: JVM Runtime Data Area&amp;nbsp;자바가상머신의 메모리 구조: JVM Runtime Data Area개요자바가 제공하는 메모리 관리는 할당과 해제를 하여 &quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EA%B2%B0%EA%B5%AD-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%88%9C%ED%95%9C%EB%A7%9B&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EA%B2%B0%EA%B5%AD-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%88%9C%ED%95%9C%EB%A7%9B&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/2QbF8/hyX4tJ1iBy/mq5dPrAm8trzzRyb4KhAok/img.png?width=594&amp;amp;height=596&amp;amp;face=0_0_594_596,https://scrap.kakaocdn.net/dn/bgqg5t/hyX4uhQ0CK/ak5KT2znl123RDmxqH6RY0/img.png?width=594&amp;amp;height=596&amp;amp;face=0_0_594_596,https://scrap.kakaocdn.net/dn/csm4VB/hyX4mRD8Lj/R3FzyHErkfksx6Gr8DKS70/img.png?width=594&amp;amp;height=596&amp;amp;face=0_0_594_596&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EA%B2%B0%EA%B5%AD-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%88%9C%ED%95%9C%EB%A7%9B&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EA%B2%B0%EA%B5%AD-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%88%9C%ED%95%9C%EB%A7%9B&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/2QbF8/hyX4tJ1iBy/mq5dPrAm8trzzRyb4KhAok/img.png?width=594&amp;amp;height=596&amp;amp;face=0_0_594_596,https://scrap.kakaocdn.net/dn/bgqg5t/hyX4uhQ0CK/ak5KT2znl123RDmxqH6RY0/img.png?width=594&amp;amp;height=596&amp;amp;face=0_0_594_596,https://scrap.kakaocdn.net/dn/csm4VB/hyX4mRD8Lj/R3FzyHErkfksx6Gr8DKS70/img.png?width=594&amp;amp;height=596&amp;amp;face=0_0_594_596');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;예제로 배우는 결국 알아야하는 JVM 메모리 구조(순한맛)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요&amp;nbsp;&amp;nbsp;매운맛은 하단에2024.06.25 - [Java] - 자바가상머신의 메모리 구조: JVM Runtime Data Area&amp;nbsp;자바가상머신의 메모리 구조: JVM Runtime Data Area개요자바가 제공하는 메모리 관리는 할당과 해제를 하여&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q8. 자바에서 위치별 변수 종류와 메모리 할당에 대해 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A8. 인스턴스 변수는 Heap에, 클래스 변수는 Method Area에, 지역 변수와 매개변수는 Stack에 할당된다. &lt;br /&gt;인스턴스 변수는 객체마다 별도로 생성되며, 클래스 변수는 모든 객체가 공유한다.&lt;br /&gt;지역 변수와 매개변수는 메서드 실행 시에만 유효하다.&lt;br /&gt;&lt;br /&gt;자세히 알아보기 ⬇️&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%A0%9C%ED%95%9C%EC%9E%90%EC%99%80-%EC%9E%90%EB%B0%94%EB%B3%80%EC%88%98-%EC%84%A4%EA%B3%84-%EC%A0%84%EB%9E%B5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.01.22 - [Java] - 예제로 배우는 제한자와 자바변수 설계 전략&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737620642298&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;예제로 배우는 제한자와 자바변수 설계 전략&quot; data-og-description=&quot;개요자바에서 변수는 선언 위치와 제한자에 따라 특성과 용도가 달라집니다.&amp;nbsp;이를 이해하면 코드 설계에서 효율적인 전략을 세울 수 있습니다.&amp;nbsp;스프링을 이용해 서버를 구현할때 더 효율적인 &quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%A0%9C%ED%95%9C%EC%9E%90%EC%99%80-%EC%9E%90%EB%B0%94%EB%B3%80%EC%88%98-%EC%84%A4%EA%B3%84-%EC%A0%84%EB%9E%B5&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%A0%9C%ED%95%9C%EC%9E%90%EC%99%80-%EC%9E%90%EB%B0%94%EB%B3%80%EC%88%98-%EC%84%A4%EA%B3%84-%EC%A0%84%EB%9E%B5&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bHcJCp/hyX4mD88oI/228qVgng67bnFFv0RGccCK/img.png?width=589&amp;amp;height=588&amp;amp;face=0_0_589_588,https://scrap.kakaocdn.net/dn/4S1u2/hyX4relnl4/GAVBWLJ9YHlFfef4Nfbvhk/img.png?width=589&amp;amp;height=588&amp;amp;face=0_0_589_588,https://scrap.kakaocdn.net/dn/bglAO6/hyX4xr8682/b0nKniEGA47MnlMpJnfMhk/img.png?width=589&amp;amp;height=588&amp;amp;face=0_0_589_588&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%A0%9C%ED%95%9C%EC%9E%90%EC%99%80-%EC%9E%90%EB%B0%94%EB%B3%80%EC%88%98-%EC%84%A4%EA%B3%84-%EC%A0%84%EB%9E%B5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%A0%9C%ED%95%9C%EC%9E%90%EC%99%80-%EC%9E%90%EB%B0%94%EB%B3%80%EC%88%98-%EC%84%A4%EA%B3%84-%EC%A0%84%EB%9E%B5&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bHcJCp/hyX4mD88oI/228qVgng67bnFFv0RGccCK/img.png?width=589&amp;amp;height=588&amp;amp;face=0_0_589_588,https://scrap.kakaocdn.net/dn/4S1u2/hyX4relnl4/GAVBWLJ9YHlFfef4Nfbvhk/img.png?width=589&amp;amp;height=588&amp;amp;face=0_0_589_588,https://scrap.kakaocdn.net/dn/bglAO6/hyX4xr8682/b0nKniEGA47MnlMpJnfMhk/img.png?width=589&amp;amp;height=588&amp;amp;face=0_0_589_588');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;예제로 배우는 제한자와 자바변수 설계 전략&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요자바에서 변수는 선언 위치와 제한자에 따라 특성과 용도가 달라집니다.&amp;nbsp;이를 이해하면 코드 설계에서 효율적인 전략을 세울 수 있습니다.&amp;nbsp;스프링을 이용해 서버를 구현할때 더 효율적인&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q9. 메서드의 정의와 필요성은? (DRY, WET 원칙 등)&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A9. 메서드는 클래스 내에서 특정 기능을 수행하는 코드 블록입니다. 메서드를 사용하면 코드의 재사용성을 높이고, 가독성을 높일 수 있다. &lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DRY(Don't Repeat Yourself) 원칙: 중복 코드를 최소화하고, 코드의 일관성을 유지한다.&lt;br /&gt;WET(Write Everything Twice) 원칙: 중복 코드를 피하고, 코드의 재사용성을 높인다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q10. 무조건 메서드를 만들어서 캡슐화를 진행하는게 좋은가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A10. 메서드를 만들어 캡슐화를 진행하는 것은 좋은 설계 방법입니다.&lt;br /&gt;하지만, &lt;b&gt;과도한 메서드 분리&lt;/b&gt;는 오히려 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;가독성을 떨어뜨릴 수 있으므로 적절한 수준의 캡슐화를 유지하는 것이 중요&lt;/span&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q11. 메서드의 시그니처란 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A11. 메서드의 시그니처는 메서드의 이름과 매개변수의 타입, 개수로 구성된다.&lt;br /&gt;메서드 시그니처가 다르면 &lt;b&gt;오버로딩&lt;/b&gt;으로 여겨집니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q12. 메서드에서 Variable Arguments를 사용하는 방법과 이를 활용한 예시를 작성해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A12. Variable Arguments는 메서드의 매개변수로 가변 개수의 인자를 전달할 수 있도록 하는 기능입니다.&lt;br /&gt;메서드 선언 시 타입 뒤에 ...을 붙여 사용합니다. &lt;br /&gt;&lt;br /&gt;예: public void printNumbers(int... numbers) { }&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q13. call by value와 call by reference에 대해 알고 있나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A13. 자바는 기본적으로 Call by Value 방식을 사용합니다. &lt;br /&gt;메서드 호출 시 매개변수로 값이 복사되어 전달되므로 원본 값은 변경되지 않습니다. &lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;&lt;br /&gt;자세히 알아보기 ⬇️&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94-String-Pool-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.01.20 - [Java] - 예제로 배우는 자바 String Pool 이해하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737620762722&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;예제로 배우는 자바 String Pool 이해하기&quot; data-og-description=&quot;개요 이번 글에서는 예제를 통해 자바의 String Pool과 intern() 메서드 개념을 자세히 알아봅니다.&amp;nbsp;문자열 리터럴과 new 연산자를 통한 객체 생성, 그리고 intern() 메서드 사용 시 String Pool 내의 객체 &quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94-String-Pool-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94-String-Pool-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/yFeM0/hyX4oBXhve/5q3Iz47kEIZQBUkuVjKB1K/img.png?width=800&amp;amp;height=794&amp;amp;face=0_0_800_794,https://scrap.kakaocdn.net/dn/WZkDS/hyX4q7AVAJ/LNvU6q3xJ8gDN1WkP5Uzm0/img.png?width=750&amp;amp;height=744&amp;amp;face=0_0_750_744&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94-String-Pool-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94-String-Pool-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/yFeM0/hyX4oBXhve/5q3Iz47kEIZQBUkuVjKB1K/img.png?width=800&amp;amp;height=794&amp;amp;face=0_0_800_794,https://scrap.kakaocdn.net/dn/WZkDS/hyX4q7AVAJ/LNvU6q3xJ8gDN1WkP5Uzm0/img.png?width=750&amp;amp;height=744&amp;amp;face=0_0_750_744');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;예제로 배우는 자바 String Pool 이해하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요 이번 글에서는 예제를 통해 자바의 String Pool과 intern() 메서드 개념을 자세히 알아봅니다.&amp;nbsp;문자열 리터럴과 new 연산자를 통한 객체 생성, 그리고 intern() 메서드 사용 시 String Pool 내의 객체&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;참조 타입을 사용하면 Call by Reference처럼 동작할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q14. 기본형 변수와 참조형 변수에서 메서드 호출 시 각각 파라미터로 입력된 값이 어떻게 다르게 전달되는지 설명해주세요. (call by value)&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A14. 기본형 변수는 값 자체가 복사되어 전달되므로 메서드 내에서 값을 변경해도 원본 값은 변하지 않습니다.&lt;br /&gt;참조형 변수는 주소값이 복사되어 전달되므로 메서드 내에서 객체의 상태를 변경하면 원본 객체도 변경됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q15. 객체를 생성하면 this. 라는 키워드가 생기는데, this. 키워드의 의미는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A15. this 키워드는 인스턴스 자신을 가리키는 참조 변수입니다. &lt;br /&gt;인스턴스 변수와 지역 변수의 이름이 같을 때, this를 사용해 인스턴스 변수를 구분할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q16. static 키워드의 의미와 사용하는 이유에 대해 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A16. static 키워드는 클래스 변수와 메서드에 사용되며, 클래스가 로딩될 때 Method Area에 할당됩니다.&lt;br /&gt;static 변수는 모든 객체가 공유하며, static 메서드는 인스턴스 생성 없이 호출할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q17. 위 this, static 키워드의 특성을 고려하면, static 메서드에서 this 키워드를 사용할 수 있을까요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A17. static 메서드는 인스턴스 생성 없이 호출되므로 this 키워드를 사용할 수 없습니다.&lt;br /&gt;this는 인스턴스를 가리키는 참조 변수이므로, static 메서드에서는 사용할 수 없습니다.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;자세히 알아보기 ⬇️&lt;br /&gt;포스팅 예정&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q18. 자바 환경으로 작성된 코드에서 아무리 많은 수의 import가 있어도 컴파일 시간에 영향을 미치지 않는 이유는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A18. 자바 컴파일러는 import 문을 통해 클래스를 참조할 때, 해당 클래스의 전체 내용을 가져오는 것이 아니라, 단순히 클래스의 &lt;b&gt;위치를 참조하는 역할&lt;/b&gt;을 합니다. 따라서 import 문의 수가 많아도 컴파일 시간에 영향을 미치지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q19. 자바에서 import java.util.*; 과 import java.util.ArrayList; 의 차이점은 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A19. import java.util.*;은 java.util 패키지 내의 모든 클래스를 참조하겠다는 의미이며,&lt;br /&gt;import java.util.ArrayList;은 java.util 패키지 내의 ArrayList 클래스만 참조하겠다는 의미입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q20. 자바에서 import 문을 사용하는 이유는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A20. import 문을 사용하면 패키지 내의 클래스를 참조할 때 패키지명을 생략할 수 있습니다.&lt;br /&gt;이를 통해 코드의 가독성을 높이고, 중복된 패키지명을 줄여 코드를 간결하게 작성할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q21. 자바에서 import 문을 사용할 때 주의할 점은 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A21.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 중복된 클래스명: 서로 다른 패키지에 같은 이름의 클래스가 있을 경우, 충돌이 발생할 수 있습니다.&lt;br /&gt;2. 와일드카드 사용: 와일드카드(*)를 사용하면 모든 클래스를 참조할 수 있지만, 가독성이 떨어질 수 있습니다. &lt;br /&gt;3. 불필요한 import: 사용하지 않는 클래스를 import하면 컴파일 시간이 늘어날 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q22. 자바에서 import 문을 사용하지 않고도 클래스를 참조할 수 있는 방법은 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A22. 패키지명을 포함한 클래스의 전체 경로를 사용하여 클래스를 참조할 수 있습니다. &lt;br /&gt;&lt;br /&gt;예를 들어, java.util.ArrayList를 사용할 때, import java.util.ArrayList; 대신 &lt;br /&gt;java.util.ArrayList list = new java.util.ArrayList();와 같이 패키지명을 포함하여 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q23. protected 를 사용하는 예시를 들어서 활용법을 알려주세요. (MSA)&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A23. protected 접근 제어자는 같은 패키지 내에서는 접근 가능하며, 상속받은 클래스에서도 접근 가능합니다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서비스 간 통신: 서비스 간의 통신을 위해 인터페이스를 제공하고, protected 메서드를 통해 구현을 숨길 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;상속 관계: 상속 관계에서 부모 클래스의 protected 메서드를 자식 클래스에서 오버라이딩하여 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;출처 &amp;amp; 추가로 알아보면 좋은것&lt;/span&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;자바에서의 객체지향 개념에 대한 이해&lt;/b&gt;&lt;br /&gt;&lt;a&gt;&lt;span&gt;https&lt;/span&gt;&lt;span&gt;://www&lt;/span&gt;&lt;span&gt;.javatpoint&lt;/span&gt;&lt;span&gt;.com&lt;/span&gt;&lt;span&gt;/java&lt;/span&gt;&lt;span&gt;-oops&lt;/span&gt;&lt;span&gt;-concepts&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JVM 메모리 구조&lt;/b&gt;&lt;br /&gt;&lt;a&gt;&lt;span&gt;https&lt;/span&gt;&lt;span&gt;://www&lt;/span&gt;&lt;span&gt;.baeldung&lt;/span&gt;&lt;span&gt;.com&lt;/span&gt;&lt;span&gt;/jvm&lt;/span&gt;&lt;span&gt;-memory&lt;/span&gt;&lt;span&gt;-structure&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;자바의 메모리 관리와 가비지 컬렉션 (Garbage Collection)&lt;/b&gt;&lt;br /&gt;자바에서는 객체가 더 이상 사용되지 않으면 가비지 컬렉션에 의해 메모리가 자동으로 회수됩니다. 가비지 컬렉션의 동작 원리와 그 성능 최적화에 대해 알아보면 메모리 관리에 대한 이해가 쉬워집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자바 Stream API와 람다 (Lambda) 활용&lt;/b&gt;&lt;br /&gt;자바 8부터 도입된 Stream API와 람다는 컬렉션 처리의 편리함을 제공하며 코드의 간결성 및 가독성을 높여줍니다. 이를 활용하여 코드를 어떻게 더 효율적으로 작성할 수 있는지 배울 필요가 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자바의 동시성 (Concurrency) 및 멀티스레딩 (Multithreading)&lt;/b&gt;&lt;br /&gt;자바에서 멀티스레딩과 동시성 처리는 성능을 최적화하고 리소스를 효율적으로 활용하는 중요한 개념입니다. 스레드 간의 동기화, 병렬 처리 방법 등에 대해 알아보는 것이 유익합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디자인 패턴 (Design Patterns)&lt;/b&gt;&lt;br /&gt;객체지향 설계를 잘 이해하고 적용할 수 있는 다양한 디자인 패턴을 배우면, 재사용 가능한 코드 작성이 가능합니다. Singleton, Factory, Observer 등 다양한 패턴에 대해 공부할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Java</category>
      <category>면접 대비</category>
      <category>자바 기본</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/228</guid>
      <comments>https://nstgic3.tistory.com/entry/Java-%EC%A1%B0%EA%B0%81%EB%AA%A8%EC%9D%8C-4#entry228comment</comments>
      <pubDate>Thu, 23 Jan 2025 17:32:36 +0900</pubDate>
    </item>
    <item>
      <title>예제로 배우는 결국 알아야하는 JVM 메모리 구조(순한맛)</title>
      <link>https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EA%B2%B0%EA%B5%AD-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%88%9C%ED%95%9C%EB%A7%9B</link>
      <description>&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; text-align: start;&quot;&gt;매운맛은 하단에&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0-JVM-Runtime-Data-Area&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2024.06.25 - [Java] - 자바가상머신의 메모리 구조: JVM Runtime Data Area&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737520255123&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;자바가상머신의 메모리 구조: JVM Runtime Data Area&quot; data-og-description=&quot;개요자바가 제공하는 메모리 관리는 할당과 해제를 하여 관리해야하는 다른 언어들과는 달리 개발자의 편의성 측면에서 많은 이점을 가져온다. 하지만 그 이면으로 내가 직접 관리를 하지 않기&quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0-JVM-Runtime-Data-Area&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0-JVM-Runtime-Data-Area&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/YZTjt/hyX4q7gAq9/TopHKbitQrbUqE8klSk5vK/img.png?width=800&amp;amp;height=793&amp;amp;face=0_0_800_793,https://scrap.kakaocdn.net/dn/hIWzg/hyX4rrz2Br/pn9GEotEGcNFPRkNLUkim1/img.png?width=800&amp;amp;height=793&amp;amp;face=0_0_800_793,https://scrap.kakaocdn.net/dn/cjFcCA/hyX4rkPziX/CdKEXHRymVxWq8qKlUGUUk/img.png?width=1750&amp;amp;height=658&amp;amp;face=0_0_1750_658&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0-JVM-Runtime-Data-Area&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0-JVM-Runtime-Data-Area&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/YZTjt/hyX4q7gAq9/TopHKbitQrbUqE8klSk5vK/img.png?width=800&amp;amp;height=793&amp;amp;face=0_0_800_793,https://scrap.kakaocdn.net/dn/hIWzg/hyX4rrz2Br/pn9GEotEGcNFPRkNLUkim1/img.png?width=800&amp;amp;height=793&amp;amp;face=0_0_800_793,https://scrap.kakaocdn.net/dn/cjFcCA/hyX4rkPziX/CdKEXHRymVxWq8qKlUGUUk/img.png?width=1750&amp;amp;height=658&amp;amp;face=0_0_1750_658');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;자바가상머신의 메모리 구조: JVM Runtime Data Area&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요자바가 제공하는 메모리 관리는 할당과 해제를 하여 관리해야하는 다른 언어들과는 달리 개발자의 편의성 측면에서 많은 이점을 가져온다. 하지만 그 이면으로 내가 직접 관리를 하지 않기&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2024.06.25 - [Java] - JVM스택메모리 구조 이해를 위한 바이트코드 예시&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737520269871&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;JVM스택메모리 구조 이해를 위한 바이트코드 예시&quot; data-og-description=&quot;개요JVM의 메모리 영역 구성 요소중 하나인 자바가상머신 스택에 대한 이해를 위해 예제를 통해 각 구역에 데이터가 할당되고 해제되는것을 javap 명령어를 통해 알아본다.&amp;nbsp;&amp;nbsp;*해당 포스팅에서 나&quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/KQd3j/hyX4pN2697/JXAnmTLeqXNsWah6Fmk1B0/img.png?width=800&amp;amp;height=797&amp;amp;face=0_0_800_797,https://scrap.kakaocdn.net/dn/dcbugH/hyX4xL5zsR/smfWLoPDxMqlJhEXDCMYN1/img.png?width=800&amp;amp;height=797&amp;amp;face=0_0_800_797,https://scrap.kakaocdn.net/dn/bFbkWX/hyX4s433QC/9tAiYlC3wCLqCznYcwyZKk/img.png?width=1694&amp;amp;height=486&amp;amp;face=0_0_1694_486&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/KQd3j/hyX4pN2697/JXAnmTLeqXNsWah6Fmk1B0/img.png?width=800&amp;amp;height=797&amp;amp;face=0_0_800_797,https://scrap.kakaocdn.net/dn/dcbugH/hyX4xL5zsR/smfWLoPDxMqlJhEXDCMYN1/img.png?width=800&amp;amp;height=797&amp;amp;face=0_0_800_797,https://scrap.kakaocdn.net/dn/bFbkWX/hyX4s433QC/9tAiYlC3wCLqCznYcwyZKk/img.png?width=1694&amp;amp;height=486&amp;amp;face=0_0_1694_486');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;JVM스택메모리 구조 이해를 위한 바이트코드 예시&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요JVM의 메모리 영역 구성 요소중 하나인 자바가상머신 스택에 대한 이해를 위해 예제를 통해 각 구역에 데이터가 할당되고 해제되는것을 javap 명령어를 통해 알아본다.&amp;nbsp;&amp;nbsp;*해당 포스팅에서 나&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;클래스(static) 변수, 인스턴스 변수, 지역 변수의 특성 및 예제&lt;/b&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;/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;1. 나는 성능충이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;예를 들어, static 변수는 클래스 로드 시 한 번만 메모리에 올라가는데, 이를 잘못 사용하면 객체마다 중복된 메모리 낭비가 발생한다.&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;p data-ke-size=&quot;size16&quot;&gt;아래 코드를 봐보자&lt;/p&gt;
&lt;pre id=&quot;code_1737526507474&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class PerformanceExample {
    static int sharedCounter = 0; // 클래스 변수 (메모리 1회 할당)
    int instanceCounter = 0;     // 인스턴스 변수 (객체마다 힙 메모리에 따로 할당)

    public void incrementCounters() {
        sharedCounter++;         // 모든 객체에서 공유
        instanceCounter++;       // 객체별로 독립적
    }

    public static void main(String[] args) {
        PerformanceExample obj1 = new PerformanceExample();
        PerformanceExample obj2 = new PerformanceExample();

        obj1.incrementCounters();
        obj2.incrementCounters();

        System.out.println(&quot;Static Counter: &quot; + sharedCounter); // 출력: 2
        System.out.println(&quot;Instance Counter (obj1): &quot; + obj1.instanceCounter); // 출력: 1
        System.out.println(&quot;Instance Counter (obj2): &quot; + obj2.instanceCounter); // 출력: 1
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sharedCounter는 모든 객체가 공유하는 값이므로 힙 메모리 낭비를 줄임.&lt;/li&gt;
&lt;li&gt;하지만 instanceCounter는 객체마다 따로 생성되므로 힙 메모리를 더 차지한다.&lt;/li&gt;
&lt;li&gt;이런 차이를 이해하면 더 효율적인 메모리 관리를 할 수 있다. (알고리즘 풀이때 static 해두고 초기화해서 쓰면 굳)&lt;/li&gt;
&lt;/ul&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 오류를 디버깅하기 쉽다.(결국 원리를 알아야 고장난걸 고침)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NullPointerException, OutOfMemoryError 같은 오류의 근본 원인을 알기 위해선 메모리 구조를 이해해야 한다.&lt;/li&gt;
&lt;li&gt;예를 들어, 지역 변수는 스택에 저장되고 메서드 실행이 끝나면 사라지기 때문에, 이를 잘못 참조하면 오류를 뜬다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1737526608582&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class DebugExample {
    static String sharedData = &quot;Shared&quot;;
    String instanceData;

    public void printData() {
        String localData = &quot;Local&quot;; // 지역 변수 (스택에 저장됨)
        System.out.println(&quot;Local Data: &quot; + localData);
        System.out.println(&quot;Instance Data: &quot; + instanceData); // NullPointerException 가능성
        System.out.println(&quot;Shared Data: &quot; + sharedData);
    }

    public static void main(String[] args) {
        DebugExample example = new DebugExample();
        example.printData(); // instanceData가 초기화되지 않아 NullPointerException 발생 가능

        DebugExample.sharedData = &quot;Modified&quot;;
        DebugExample anotherExample = new DebugExample();
        anotherExample.printData(); // sharedData는 모든 객체에서 수정된 값을 공유
    }
}&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;stanceData는 초기화되지 않았으므로 NullPointerException이 발생 가능.&lt;/li&gt;
&lt;li&gt;sharedData는 static으로 선언되어 모든 객체에서 값이 공유됨.&lt;/li&gt;
&lt;li&gt;이런 메모리 동작을 이해하면 문제 원인을 빠르게 찾아 고칠 수 있다.&lt;/li&gt;
&lt;/ul&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;코드 분석&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1737530879613&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Car {
	static double speed = 0;
	String color;
	void drive(String to) {
		System.out.println(&quot;Driving to &quot; + to);
		String msg = &quot;Driving at &quot; + speed + &quot; km/h&quot;;
		for (int i = 0; i &amp;lt; 3; i++) {
			System.out.println(msg);
		}
	}
}


public class CarDriveTest {
	public static void main(String[] args) {
		Car myCar = new Car();
		myCar.color = &quot;Red&quot;;
		System.out.println(&quot;My car is &quot; + myCar.color);
		myCar.drive(&quot;New York&quot;);
		
		Car yourCar = new Car();
		yourCar.color = &quot;Blue&quot;;
		System.out.println(&quot;Your car is &quot; + yourCar.color);
		yourCar.drive(&quot;Chicago&quot;);
		
		Car.speed = 100;
		myCar.drive(&quot;New York2&quot;);
		yourCar.drive(&quot;Chicago2&quot;);
		
	}
}&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;&lt;b&gt;클래스 변수 (static 키워드)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static double speed = 0;&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;프로그램 실행 시 클래스가 로드될 때 초기화 되어 메모리에 한 번 할당되며, 모든 객체가 공유한다.&lt;/li&gt;
&lt;li&gt;클래스 변수는 &lt;b&gt;메타스페이스(Metaspace)&lt;/b&gt;에 할당된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인스턴스 변수&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String color;&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;인스턴스 변수는 &lt;code&gt;new  Car()&lt;/code&gt; 호출 시 &lt;b&gt;힙(Heap)&lt;/b&gt; 메모리에 할당됩니다.&lt;/li&gt;
&lt;li&gt;각 객체(&lt;code&gt;myCar&lt;/code&gt;, &lt;code&gt;yourCar&lt;/code&gt;)가 자신의 &lt;code&gt;color&lt;/code&gt; 인스턴스 변수가 각 객체 내부의 힙 메모리에 존재한다.&lt;/li&gt;
&lt;/ul&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;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String msg = &quot;Driving at &quot; + speed + &quot; km/h&quot;;
int i = 0;&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;지역 변수는 메서드 실행 중 &lt;b&gt;스택(Stack)&lt;/b&gt; 메모리에 할당됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;drive()&lt;/code&gt; 메서드의 매개변수 &lt;code&gt;to&lt;/code&gt;와 반복문 내 &lt;code&gt;i&lt;/code&gt; 변수도 스택에 저장됩니다.&lt;/li&gt;
&lt;li&gt;메서드 실행이 끝나면 지역 변수는 사라집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;클래스로드 - 인스턴스 생성 메모리 동작&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JVM은 &lt;code&gt;Car&lt;/code&gt; 클래스를 메타스페이스에 로드합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;speed&lt;/code&gt; 변수가 메타스페이스에 생성되고 초기값 &lt;code&gt;0.0&lt;/code&gt;을 가집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인스턴스 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Car myCar = new Car();&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;&lt;code&gt;new Car()&lt;/code&gt; 호출 시 힙에 객체가 생성됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;myCar.color&lt;/code&gt;의 초기값은 &lt;code&gt;null&lt;/code&gt;로 설정됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인스턴스 변수 문자열 참조&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737534350714&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;main.Car myCar = new Car();
myCar.color = &quot;Red&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; &quot;Red&quot; 는 문자열 리터럴로, 클래스로더가 읽을때 String Constant Pool (메타 스페이스에 인접해서 적재하기에 용이하다.)&lt;/li&gt;
&lt;li&gt;myCar 객체의&amp;nbsp;&lt;b&gt;힙 메모리&amp;nbsp;&lt;/b&gt;내부에 있던 초기값 null 이 &quot;Red&quot; 문자열 참조로 대체된다.&lt;/li&gt;
&lt;li&gt;myCar 은 스택에 존재하는 로컬 변수로서, 힙에 있는 Car 객체 주소를 참조한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;메서드 호출과 스택 내부 지역변수&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메서드 호출과 스택 내 지역 변수&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;System.out.println(&quot;My car is &quot; + myCar.color);&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;&quot;My car is &quot;와 myCar.color의 문자열 결합 과정에서 새 String 객체가 &lt;b&gt;힙에 생성될 수 있다&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;println 호출 시, 내부적으로 &lt;b&gt;PrintStream 객체(System.out)가 사용&lt;/b&gt;된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스택 프레임&lt;/b&gt;에서 임시 지역 변수(결합된 문자열 주소)가 잡힐 수 있고, 메서드 실행이 끝나면 해제된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1737534752973&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;myCar.drive(&quot;New York&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;drive(&quot;New York&quot;) 호출 시 새로운 스택 프레임이 생성된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;this &amp;rarr; myCar 객체 주소(힙에 있는)를 스택에 참조(주소) 형태로 저장&lt;/li&gt;
&lt;li&gt;매개변수 to &amp;rarr; &quot;New York&quot; 참조&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;System.out.println(&quot;Driving to &quot; + to);에서 &quot;Driving to &quot; + &quot;New York&quot;에 대한 문자열 처리가 이루어진다(임시 객체 또는 컴파일 최적화).&lt;/li&gt;
&lt;li&gt;msg = &quot;Driving at &quot; + speed 구문에서 &quot;Driving at &quot; 문자열을 String Constant Pool에서 가져오고, speed(현재 0.0)과 결합해 임시 문자열을 힙에 생성할 수 있다.&lt;/li&gt;
&lt;li&gt;for (int i = 0; i &amp;lt; 3; i++) 구문 안에서 i는 스택에 저장된다. 각 반복마다 System.out.println(msg)가 실행되고, msg는 이미 만들어진 임시 문자열을 참조한다.&lt;/li&gt;
&lt;li&gt;drive 메서드가 종료되면 스택 프레임은 해제된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;정적 필드 변경&lt;/span&gt;&lt;/h3&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;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Car.speed = 100;&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;이미 &lt;b&gt;메타스페이스&lt;/b&gt;에 있던 Car 클래스의 speed 값이 0에서 100으로 변경된다.&lt;/li&gt;
&lt;li&gt;이는 모든 Car 인스턴스가 공유한다.&lt;/li&gt;
&lt;/ul&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;&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;/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;b&gt; 메모리에는 어떤 정보들이 저장되었는지&lt;/b&gt; 또 한번 더 정리합시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;* 흐름 최종정리&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. &lt;b&gt;클래스 로딩&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Car와 CarDriveTest 클래스가 JVM에 로드되며 메타스페이스에 클래스 메타데이터 저장.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 필드 Car.speed는 초기값 0으로 설정(메타스페이스/Method Area).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. &lt;b&gt;main 메서드 실행&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(1) main 메서드 시작&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JVM이 &lt;b&gt;스택 프레임&lt;/b&gt; 생성.&lt;/li&gt;
&lt;li&gt;지역 변수 args 배열은 힙에 저장되고 스택에서 참조.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; (2) myCar 객체 생성&lt;/span&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;힙&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Car 객체(myCar) 생성.&lt;/li&gt;
&lt;li&gt;myCar.color &amp;rarr; 초기값 null.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스택&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지역 변수 myCar는 힙의 Car 객체 참조.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&quot;Red&quot; 문자열:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;String Pool&lt;/b&gt;에 저장.&lt;/li&gt;
&lt;li&gt;myCar.color &amp;rarr; &quot;Red&quot; 참조.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(3) myCar.drive(&quot;New York&quot;) 호출&lt;/span&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;스택&lt;/b&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;this &amp;rarr; 힙의 myCar 객체 참조.&lt;/li&gt;
&lt;li&gt;to &amp;rarr; &quot;New York&quot;(String Pool 참조).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;출력:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;Driving to New York&quot;.&lt;/li&gt;
&lt;li&gt;&quot;Driving at 0.0 km/h&quot; 3번 출력.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(4) yourCar 객체 생성&lt;/span&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;힙&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새 Car 객체(yourCar) 생성.&lt;/li&gt;
&lt;li&gt;yourCar.color &amp;rarr; 초기값 null.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스택&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지역 변수 yourCar는 힙의 Car 객체 참조.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&quot;Blue&quot; 문자열:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;String Pool&lt;/b&gt;에 저장.&lt;/li&gt;
&lt;li&gt;yourCar.color &amp;rarr; &quot;Blue&quot; 참조.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(5) yourCar.drive(&quot;Chicago&quot;) 호출&lt;/span&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;스택&lt;/b&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;this &amp;rarr; 힙의 yourCar 객체 참조.&lt;/li&gt;
&lt;li&gt;to &amp;rarr; &quot;Chicago&quot;(String Pool 참조).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;출력:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;Driving to Chicago&quot;.&lt;/li&gt;
&lt;li&gt;&quot;Driving at 0.0 km/h&quot; 3번 출력.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;h4 data-ke-size=&quot;size20&quot;&gt;3. &lt;b&gt;정적 필드 업데이트&lt;/b&gt;&lt;/h4&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;메타스페이스&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Car.speed 값이 0 &amp;rarr; 100으로 변경.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;모든 Car 객체가 이 값을 공유.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. &lt;b&gt;메서드 재호출&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) myCar.drive(&quot;New York2&quot;)&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;스택&lt;/b&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;this &amp;rarr; 힙의 myCar 객체 참조.&lt;/li&gt;
&lt;li&gt;to &amp;rarr; &quot;New York2&quot;(String Pool 참조).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;출력:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;Driving to New York2&quot;.&lt;/li&gt;
&lt;li&gt;&quot;Driving at 100.0 km/h&quot; 3번 출력.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) yourCar.drive(&quot;Chicago2&quot;)&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;스택&lt;/b&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;this &amp;rarr; 힙의 yourCar 객체 참조.&lt;/li&gt;
&lt;li&gt;to &amp;rarr; &quot;Chicago2&quot;(String Pool 참조).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;출력:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;Driving to Chicago2&quot;.&lt;/li&gt;
&lt;li&gt;&quot;Driving at 100.0 km/h&quot; 3번 출력.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;* 메모리 내부 최종정리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 메타스페이스&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 정보:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Car, CarDriveTest 메타데이터.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정적 필드:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Car.speed &amp;rarr; 초기값 0 &amp;rarr; 최종값 100.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;String Pool:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;Red&quot;, &quot;Blue&quot;, &quot;New York&quot;, &quot;Chicago&quot;, &quot;New York2&quot;, &quot;Chicago2&quot;, &quot;Driving at &quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 힙&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 개의 Car 객체:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;myCar.color &amp;rarr; &quot;Red&quot;(String Pool 참조).&lt;/li&gt;
&lt;li&gt;yourCar.color &amp;rarr; &quot;Blue&quot;(String Pool 참조).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 스택&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;main 메서드:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지역 변수:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;myCar &amp;rarr; 힙의 첫 번째 Car 객체 참조.&lt;/li&gt;
&lt;li&gt;yourCar &amp;rarr; 힙의 두 번째 Car 객체 참조.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;drive 메서드 호출:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;this &amp;rarr; 힙의 호출된 Car 객체 참조.&lt;/li&gt;
&lt;li&gt;to &amp;rarr; String Pool의 문자열 참조.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;출력값 결과&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1737535959766&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;My car is Red
Driving to New York
Driving at 0.0 km/h
Driving at 0.0 km/h
Driving at 0.0 km/h
Your car is Blue
Driving to Chicago
Driving at 0.0 km/h
Driving at 0.0 km/h
Driving at 0.0 km/h
Driving to New York2
Driving at 100.0 km/h
Driving at 100.0 km/h
Driving at 100.0 km/h
Driving to Chicago2
Driving at 100.0 km/h
Driving at 100.0 km/h
Driving at 100.0 km/h&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 이번 포스팅을 통해 JVM 메모리 구조를 상세히 살펴보았고, 예제인 Car 클래스의 실행 흐름을 통해 메모리 관리가 코드 동작에 어떻게 영향을 미치는지 확인했습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다시 정리하면&lt;/span&gt;&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;클래스 변수 (static)&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;String Pool&lt;/b&gt;에 저장되어 중복을 줄이고 메모리 사용을 최적화합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마무리 하면서, 만약 main 메서드가 종료된 이후, 힙에 있던 myCar, yourCar 객체는 더 이상 쓰이지 않는데 비효율적(자원낭비) 이지 않을까요?&lt;br /&gt;&lt;br /&gt;그래서 자바에서는 이걸 자동으로 치우는 역할을 하는 관리 시스템이 있습니다. 가비지 컬렉터(GC)라는 것이 메모리를 자동으로 관리해주는데 다음에 알아봅시다&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;매운맛으로 알아보고 싶다면 ⬇️&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94-%EA%B0%80%EB%B9%84%EC%A7%80-%EC%BB%AC%EB%A0%89%ED%84%B0GC%EC%9D%98-%EB%B0%9C%EC%A0%84-%EC%8B%9C%EB%A6%AC%EC%96%BC-%EC%BB%AC%EB%A0%89%ED%84%B0%EB%B6%80%ED%84%B0-ZGC%EA%B9%8C%EC%A7%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2024.07.20 - [Java] - 자바 가비지 컬렉터(GC)의 발전; 시리얼 컬렉터부터 ZGC까지&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737545784981&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;자바 가비지 컬렉터(GC)의 발전; 시리얼 컬렉터부터 ZGC까지&quot; data-og-description=&quot;개요자바를 공부하다보면 가비지 컬렉터(GC)에 대해 자주 접하게 된다.&amp;nbsp;대부분 GC과정이 메모리 관리를 위해 사용된 객체를 해제하고 메모리 관리를 최적화 하기 위해서 여러 세대로 나누어 자&quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94-%EA%B0%80%EB%B9%84%EC%A7%80-%EC%BB%AC%EB%A0%89%ED%84%B0GC%EC%9D%98-%EB%B0%9C%EC%A0%84-%EC%8B%9C%EB%A6%AC%EC%96%BC-%EC%BB%AC%EB%A0%89%ED%84%B0%EB%B6%80%ED%84%B0-ZGC%EA%B9%8C%EC%A7%80&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94-%EA%B0%80%EB%B9%84%EC%A7%80-%EC%BB%AC%EB%A0%89%ED%84%B0GC%EC%9D%98-%EB%B0%9C%EC%A0%84-%EC%8B%9C%EB%A6%AC%EC%96%BC-%EC%BB%AC%EB%A0%89%ED%84%B0%EB%B6%80%ED%84%B0-ZGC%EA%B9%8C%EC%A7%80&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ePNAZ/hyX4xk8b3f/HoaCCSdKeV16ytH3EgOD9K/img.png?width=800&amp;amp;height=452&amp;amp;face=0_0_800_452,https://scrap.kakaocdn.net/dn/bqxWqN/hyX4m4XvlZ/5Du7B3y2KRk4DwHxm5YAy1/img.png?width=800&amp;amp;height=452&amp;amp;face=0_0_800_452,https://scrap.kakaocdn.net/dn/UXIY4/hyX4nv2uYc/yVTpziuSk0vQTkz8EkVMIk/img.png?width=2174&amp;amp;height=1210&amp;amp;face=0_0_2174_1210&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94-%EA%B0%80%EB%B9%84%EC%A7%80-%EC%BB%AC%EB%A0%89%ED%84%B0GC%EC%9D%98-%EB%B0%9C%EC%A0%84-%EC%8B%9C%EB%A6%AC%EC%96%BC-%EC%BB%AC%EB%A0%89%ED%84%B0%EB%B6%80%ED%84%B0-ZGC%EA%B9%8C%EC%A7%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94-%EA%B0%80%EB%B9%84%EC%A7%80-%EC%BB%AC%EB%A0%89%ED%84%B0GC%EC%9D%98-%EB%B0%9C%EC%A0%84-%EC%8B%9C%EB%A6%AC%EC%96%BC-%EC%BB%AC%EB%A0%89%ED%84%B0%EB%B6%80%ED%84%B0-ZGC%EA%B9%8C%EC%A7%80&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ePNAZ/hyX4xk8b3f/HoaCCSdKeV16ytH3EgOD9K/img.png?width=800&amp;amp;height=452&amp;amp;face=0_0_800_452,https://scrap.kakaocdn.net/dn/bqxWqN/hyX4m4XvlZ/5Du7B3y2KRk4DwHxm5YAy1/img.png?width=800&amp;amp;height=452&amp;amp;face=0_0_800_452,https://scrap.kakaocdn.net/dn/UXIY4/hyX4nv2uYc/yVTpziuSk0vQTkz8EkVMIk/img.png?width=2174&amp;amp;height=1210&amp;amp;face=0_0_2174_1210');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;자바 가비지 컬렉터(GC)의 발전; 시리얼 컬렉터부터 ZGC까지&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요자바를 공부하다보면 가비지 컬렉터(GC)에 대해 자주 접하게 된다.&amp;nbsp;대부분 GC과정이 메모리 관리를 위해 사용된 객체를 해제하고 메모리 관리를 최적화 하기 위해서 여러 세대로 나누어 자&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>jvm 메모리 관리 예제</category>
      <category>인스턴스 변수</category>
      <category>지역 변수</category>
      <category>클래스 변수</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/227</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EA%B2%B0%EA%B5%AD-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-JVM-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EC%88%9C%ED%95%9C%EB%A7%9B#entry227comment</comments>
      <pubDate>Wed, 22 Jan 2025 20:39:51 +0900</pubDate>
    </item>
    <item>
      <title>예제로 배우는 제한자와 자바변수 설계 전략</title>
      <link>https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%A0%9C%ED%95%9C%EC%9E%90%EC%99%80-%EC%9E%90%EB%B0%94%EB%B3%80%EC%88%98-%EC%84%A4%EA%B3%84-%EC%A0%84%EB%9E%B5</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;자바에서 변수는 선언 위치와 제한자에 따라 &lt;b&gt;특성&lt;/b&gt;과 &lt;b&gt;용도&lt;/b&gt;가 달라집니다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;이를 이해하면 코드 설계에서 효율적인 전략을 세울 수 있습니다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;스프링을 이용해 서버를 구현할때 더 효율적인 인스턴스 생성이나 변수 관리를 할수도 있고 통과가 타이트한 알고리즘 문제를 풀때에도 적극적으로 이용할수 있습니다. (무조건 알아둬야 된다는뜻)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;클래스 변수 (Static으로 선언된 변수)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;정의&lt;/b&gt;: static 키워드로 선언된 변수. 클래스 로딩 시 한 번만 생성되고, 모든 객체가 공유.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;위치&lt;/b&gt;: 클래스 내부, 메서드 외부.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클래스에 귀속되고, 객체가 공유하는 변수.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;프로그램 종료 시까지 유지.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;사용 전략&lt;/b&gt;:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 객체가 공통으로 사용할 값(상수, 카운터 등)을 관리.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메모리 절약 및 데이터 일관성 유지&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;public static 의 경우&lt;br /&gt;&lt;/b&gt;: 상수로 사용. 변경 불가능하며, public으로 선언 시 전역 상수처럼 사용 가능.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;프레임워크나 전역적으로 사용되는 공용 util 함수.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737522827717&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class MathUtils {
    public static final double PI = 3.14159;  // 누구나 참조 가능
    public static int add(int a, int b) {
        return a + b;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전역 함수처럼 활용 가능.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트 시 결합도가 높아질 수 있으니 주의(목(Mocks) 대체가 어려움)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;public static final 의 경우&lt;br /&gt;&lt;/b&gt;: 상수로 사용. 변경 불가능하며, public으로 선언 시 전역 상수처럼 사용 가능.&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot; data-text-less=&quot;닫기&quot; data-text-more=&quot;더보기&quot; data-ke-type=&quot;moreLess&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전역적인&amp;nbsp;&lt;b&gt;공유 자원&lt;/b&gt;이나&amp;nbsp;&lt;b&gt;전역 설정 값&lt;/b&gt;을 관리&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;*private static 의 경우 - 싱글턴이나 전역 캐싱&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;: 외부에서 접근 불가. 클래스 내부에서 공통 데이터를 관리하는 데 유용. 추가/삭제 가능한 경우&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;*일부러 Bean이 아닌 로우레벨로 관리할때.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;캐시, 카운터(알고리즘 cnt++), 스레드 풀&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737522670836&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class InternalCache {
    private static Map&amp;lt;String, String&amp;gt; cache = new HashMap&amp;lt;&amp;gt;(); // private static

    public static void put(String key, String value) {
        cache.put(key, value);
    }
    public static String get(String key) {
        return cache.get(key);
    }
}&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;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&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;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;외부에서는 InternalCache.cache 자체에 직접 접근 불가&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메서드 통해서만 조작하게 함으로써 캡슐화를 유지한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 싱글턴에도 적용 가능함&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737522701384&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SingletonService {
    private static SingletonService instance = new SingletonService();

    private SingletonService() {}
    public static SingletonService getInstance() {
        return instance;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;외부에서 생성자를 호출할 수 없고, getInstance()를 통해 하나의 객체만 공유.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;private static final로 선언하면 재할당이 불가능해져 안전성이 높아진다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;*정적 팩토리 메서드를 적용하는 이유&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199; color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;static 키워드와 final 키워드를 결합하면, &lt;b&gt;클래스 전역에서 활용하는 상수&lt;/b&gt;를 한 번만 정의해 효율과 일관성을 동시에 확보&lt;/span&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;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;private static final 의 경우&lt;br /&gt;&lt;/b&gt;: 외부에서 접근 불가. 클래스 내부에서 공통 데이터를 관리하는 데 유용. 의도적으로 해당 클래스 내부에서만 사용하는 변수라는걸 명시가능&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;알고리즘 풀이&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(클래스가 1개로 주어짐, 사실 public 해도 상관없는데, 명시적으로 단일 클래스 내부에서만 사용하면 private 선언하는 습관을 들이자. *왜 이런 선언습관이 좋을까?)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737521482230&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ArrayProcessor {
    // 모든 배열에 적용할 상수 값 (공통된 데이터)
    private static final int ADDITION_CONSTANT = 10;

    public static int[] processArray(int[] inputArray) {
        int[] result = new int[inputArray.length];
        for (int i = 0; i &amp;lt; inputArray.length; i++) {
            result[i] = inputArray[i] + ADDITION_CONSTANT;
        }
        return result;
    }

    public static void main(String[] args) {
        int[] inputArray = {1, 2, 3, 4};
        int[] processedArray = processArray(inputArray);

        for (int value : processedArray) {
            System.out.print(value + &quot; &quot;); // 출력: 11 12 13 14
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ADDITION_CONSTANT는 상수로, 전역적으로 값이 고정되어야 하므로 static final로 선언.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메모리 절약과 데이터 변경 방지를 위해 클래스 레벨에서 정의.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&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;span style=&quot;background-color: #f6e199; color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클래스 변수(static)와 인스턴스 변수를 비교할 때, &lt;b&gt;공통 데이터 공유&lt;/b&gt;와 &lt;b&gt;객체별 상태 관리&lt;/b&gt;라는 두 가지 관점을 함께 고려해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;인스턴스 변수(Static X )&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;정의&lt;/b&gt;: 클래스의 객체가 생성될 때마다 생성되는 변수.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;위치&lt;/b&gt;: 클래스 내부, 메서드 외부.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;특징&lt;/b&gt;:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;각 객체마다 고유의 값을 가짐.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;객체가 제거되면 메모리에서 해제.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;사용 전략&lt;/b&gt;:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;객체의 고유 상태(예: 이름, 나이 등)를 저장.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터 은닉과 불변성 확보로 안전한 객체 설계&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;public 의 경우&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;: 다른 클래스에서 직접 참조와 수정이 가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-&amp;gt; 따라서 잘 이용하지 않는다 왜일까?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;캡슐화가 깨져서 (다른 클래스에서 수정 참조가 가능하다.) 값의 변화를 추적하기 어렵다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;-&amp;gt; 유지보수가 어렵다.&lt;/span&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;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;객체지향에 반하는 사용법이다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;public final의 경우&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;: 다른 클래스에서 읽기는 가능하다. 재할당(수정)은 불가능하다. 인스턴스 생성시에 값이 확정되고 변하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-&amp;gt; 이또한 잘 이용하지 않는다. 왜일까?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;변수에 직접 접근을 허용한다. 객체 내부의 데이터가 외부에 노출이 되는데 객체 지향에 반한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;내부 구현이 외부에 드러날 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;차라리 static 을 붙여서 전역적 상수로 이용해 확실하게 전역적으로 클래스 수준에서 변하지 않는 상수임을 명시하는게 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;private의 경우&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;: 캡슐화 원칙에 따라 변수 보호, 접근자 메서드로만 접근 가능. 클래스 내부에서만 접근 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;*[중요] 스프링에서는 어노테이션이나 도메인 메서드를 이용해 외부와 소통하게 한다. = 메서드&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;필드를 숨기고, 메서드로 조작&quot; REAL 객체지향&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클래스내 선언한 식별자와 속성등 필드를 private 로 두고 이를 조작하는 메서드를 public 으로 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737524974230&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Order {
    private Long orderId; // 외부에 직접 노출되지 않음
    private int quantity;

    public Order(Long orderId, int quantity) {
        this.orderId = orderId;
        this.quantity = quantity;
    }
    
    public Long getOrderId() {
        return orderId;
    }
    
    public int getQuantity() {
        return quantity;
    }
    
    public void changeQuantity(int newQuantity) {
        this.quantity = newQuantity;
    }
}&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;어디서 어떻게 값이 변경되는지 추적이 쉽고, 유지보수성과 안전성 향상.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;*&lt;/b&gt;보일러플레이트 코드(getter/setter)가 늘어날 수 있지만, Lombok 등으로 개선 가능.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;인스턴스 변수를 final로 선언하면,&amp;nbsp;&lt;/span&gt;&lt;b&gt;불변 객체 패턴&lt;/b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;을 쉽게 구현할 수 있으며 이는 동시성 문제를 완화할수 있다.&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;private final 의 경우&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;: 캡슐화 원칙에 따라 변수 보호, 인스턴스 생성 시점에만 필드 값이 설정되고, 재할당 불가능.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;불변 객체&lt;/b&gt;(Immutable Object)를 구성하거나, 특정 필드를 절대 바꾸지 않겠다는 의도를 명확히 표현할수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;*VO 모델을 설계할때도 쓰인다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1737525062415&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Money {
    private final BigDecimal amount;
    private final String currency;

    public Money(BigDecimal amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public String getCurrency() {
        return currency;
    }

    // plus, minus 등 새 객체 반환 메서드
}&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;변경 불가능하므로 멀티스레드 안전, 로직 안정성.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;값이 변해야 하는 시점이 있다면 매번 새 객체를 만들어야 하므로, 성능/메모리 부담 가능성이 있지만 명시를 통해 개발자끼리 소통을 한다거나 안정성 측면을 고려한다면 적용해야한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; &lt;span style=&quot;background-color: #f6e199;&quot;&gt;인스턴스 변수의 스코프가 넓어지면 예기치 않은 부작용이 발생할 수 있으므로, &lt;b&gt;지역 변수로 대체 가능한 부분은 적극 활용&lt;/b&gt;하여 코드 복잡도를 줄입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;지역 변수&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;정의&lt;/b&gt;: 메서드나 블록 내부에서 선언된 변수.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;위치&lt;/b&gt;: 메서드, 생성자, 블록 내부.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;특징&lt;/b&gt;:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메서드 실행 중에만 존재하며, 종료 시 메모리에서 해제.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;반드시 초기화 필요.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;사용 전략&lt;/b&gt;:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메서드 내의 임시 값, 연산 결과를 저장.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메모리 사용을 최소화하며 스코프를 제한.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;final 의 경우&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;: 변수 값을 변경할수 없고 상수처럼 사용.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;매개 변수&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;정의&lt;/b&gt;: 메서드 호출 시 전달되는 값.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;위치&lt;/b&gt;: 메서드 선언부.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;특징&lt;/b&gt;:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메서드 호출 시 전달된 값으로 초기화.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;호출 스택에 저장되며, 메서드 실행이 끝나면 메모리에서 해제.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;사용 전략&lt;/b&gt;:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메서드 간 데이터 전달.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;불필요한 값 변경 방지로 데이터 안정성 강화.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; &lt;b&gt;final 의 경우&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;: 변수 값을 변경할수 없고 상수처럼 사용.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #333333;&quot;&gt;마무리&lt;/span&gt;&lt;/h3&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;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자바에서 변수는 선언 위치와 제한자에 따라 특성과 용도가 크게 달라집니다. &lt;/span&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;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;클래스 변수, 인스턴스 변수, 지역 변수, 매개변수&lt;/b&gt; 각각은 특정 상황에서 적합하게 사용되어야 하며, 변수의 &lt;b&gt;static, final, private&lt;/b&gt; 등의 제한자는 설계 의도를 명확히 드러내는 데 중요한 역할을 합니다.&lt;/span&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;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;클래스 변수(static)&lt;/b&gt;는 &lt;b&gt;공통 데이터 관리&lt;/b&gt;나 &lt;b&gt;전역 상수 선언&lt;/b&gt;에 유용하며, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;메모리 절약과 데이터 일관성을 제공&lt;/span&gt;합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;인스턴스 변수&lt;/b&gt;는 객체마다 고유한 &lt;b&gt;상태를 저장&lt;/b&gt;하며, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;객체 지향 설계의 기본&lt;/span&gt;이 됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;지역 변수&lt;/b&gt;와 &lt;b&gt;매개변수&lt;/b&gt;는 스코프를 제한해 불필요한 &lt;b&gt;메모리 사용을 줄이고&lt;/b&gt;, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;메서드 간 데이터 전달에서 안정성을 강화&lt;/span&gt;합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특성에 따라서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;캡슐화&lt;/b&gt; 원칙을 준수하고 변수의 가시성을 제한&lt;/span&gt;하며, 필요한 경우 final을 활용해&lt;span style=&quot;background-color: #f6e199;&quot;&gt; 불변성을 부여&lt;/span&gt;하면 코드의 &lt;b&gt;안정성&lt;/b&gt;과 &lt;b&gt;유지보수성&lt;/b&gt;이 크게 향상됩니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 설계 원칙은 스프링 기반 서버 구현, 알고리즘 문제 해결 등 다양한 상황에서 유효하기에 숙지해놓는것을 추천합니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Java</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/226</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%A0%9C%ED%95%9C%EC%9E%90%EC%99%80-%EC%9E%90%EB%B0%94%EB%B3%80%EC%88%98-%EC%84%A4%EA%B3%84-%EC%A0%84%EB%9E%B5#entry226comment</comments>
      <pubDate>Wed, 22 Jan 2025 15:02:54 +0900</pubDate>
    </item>
    <item>
      <title>예제로 배우는 자바가 배열을 생성하는 원리 이해하기</title>
      <link>https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94%EA%B0%80-%EB%B0%B0%EC%97%B4%EC%9D%84-%EC%83%9D%EC%84%B1%ED%95%98%EB%8A%94-%EC%9B%90%EB%A6%AC-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
      <description>&lt;h3 id=&quot;overview&quot; style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;이번 글에서는 예제를 통해 자바가 배열을 생성하는 원리를 자세히 알아봅니다. &lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;자바에서 배열은 데이터의 집합을 다루는 데 매우 유용하며, 올바르게 초기화하고 사용하는 방법을 이해하면 코드의 가독성과 안정성을 높일 수 있습니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;또한 알고리즘 풀이에 아주 유용하게 쓰일수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737422799804&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// CASE1
int[] arr;
arr = {1, 21, 312, 3, 123, 1};

// CASE2
int[] arr = new int[6]{1, 21, 312, 3, 123, 1};&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;위의 코드는 오류가 날까요?&amp;nbsp;&lt;/span&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;h3 id=&quot;array-declaration&quot; style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;배열 선언과 초기화&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;자바에서 배열은 일반적으로 아래 두 단계를 통해 생성해서 씁니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;배열 선언: 배열의 데이터 타입과 이름을 지정합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;배열 생성: 메모리를 할당하고 배열 요소를 초기화합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int[] arr; // 배열 선언
arr = new int[5]; // 배열 생성
&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;array-initialization-block&quot; style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;배열 초기화 블록과 배열 생성 구문&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자바 언어 사양(JLS) 10.6에 따르면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열 초기화 블록 { ... }는 배열 변수를 초기화하는 문법으로만 사용되며, 다음 두 경우에만 허용됩니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;선언과 동시에 초기화&lt;/b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;br /&gt;&lt;code&gt;int[] arr = {1, 2, 3};&lt;/code&gt;&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;new 키워드와 함께 배열 초기화&lt;br /&gt;&lt;/b&gt;&lt;code style=&quot;letter-spacing: 0px;&quot;&gt;int[] arr = new int[]{1, 2, 3};&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&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;h3 id=&quot;invalid-initialization&quot; style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;배열 크기와 초기값 동시 명시 불가&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;크기와 초기값을 동시에 명시하면 컴파일 오류 발생:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int[] arr = new int[5]{1, 2, 3, 4, 5}; // 컴파일 오류&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;올바른 방법:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int[] arr = new int[]{1, 2, 3, 4, 5};&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;h3 id=&quot;invalid-initialization&quot; style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;오류가 발생하는 이유&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자바에서 배열 초기화는 &lt;b&gt;컴파일 시점&lt;/b&gt;과 &lt;b&gt;런타임 시점&lt;/b&gt; 모두 관여하는 부분이 있습니다. 이를 유의해서 팔로우를 해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[컴파일 이 끝나야지 런(실행) 타임이 진행된다]&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;컴파일러의 특성을 확인해보면 &lt;b&gt;배열의 크기나 초기값이 명확히 주어졌을 때&lt;/b&gt; 이를 컴파일 시점에 검증하거나 필요한 코드를 생성&lt;/span&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아래의 배열 선언식이 생성되는 흐름을 살펴본다면&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;컴파일 시점&lt;/b&gt;에는&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737423989863&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int[] arr = {1, 2, 3};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위의 코드가&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;컴파일러&lt;/b&gt;에 의해 암묵적으로 아래와 같은 형태로 반환됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737424051223&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int[] arr = new int[]{1, 2, 3};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음으로 런타임 시점에서는 &lt;b&gt;배열의 메모리 할당과 초기화&lt;/b&gt;가 이루어집니다. 자바는 배열을 동적으로 생성하며, 이 과정에서 배열 초기화 표현식(하단에 기술,, )&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하단의 코드의 경우에는&lt;b&gt; 런타임 시점&lt;/b&gt;에 생성됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737424669150&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int n = 5;
int[] arr = new int[n];&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;or&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737424686285&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int[] arr = new int[5];&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이유는 뭘까요??&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;런타임에는 메모리 할당이 이루어지고 변수 n 의 할당 또한 런타임에 이루어집니다.&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;배열 크기가 변수 n에 의해 결정됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;n의 값은 런타임에만 알 수 있으므로, 배열 생성과 초기화는 런타임에 이루어집니다.&lt;/span&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: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;따라서&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737424891901&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int n = 5;
int[] arr = new int[n] {1,2,3,4,5};&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;&lt;span style=&quot;color: #000000;&quot;&gt;자바에서 배열 초기화 시 new int[n] 형태와 {1, 2, 3, 4, 5} 형태를 &lt;b&gt;동시에 사용할 수 없기 때문&lt;/b&gt;이기도 하고, 컴파일, 런타임 시의 할당 이념에도 맞지 않습니다.&lt;/span&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;h3 id=&quot;design-principle&quot; style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;*자바 배열 초기화의 설계 원리&lt;/span&gt;&lt;/h3&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열 생성 표현식(Array Creation Expressions)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;배열 생성 표현식&lt;/b&gt;은 새로운 배열 객체를 생성하는 데 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열은 기본 타입(Primitive Type)이나 클래스/인터페이스 타입(Class or Interface Type)을 요소로 가질 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열 생성 표현식의 문법&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열 생성 표현식은 아래와 같은 형태를 가집니다&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;658&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjZ0i3/btsLUU6yUkh/23gKjVXhTjoagztdljO3T1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjZ0i3/btsLUU6yUkh/23gKjVXhTjoagztdljO3T1/img.png&quot; data-alt=&quot;https://docs.oracle.com/javase/specs/jls/se17/html/jls-15.html#jls-15.10.1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjZ0i3/btsLUU6yUkh/23gKjVXhTjoagztdljO3T1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjZ0i3%2FbtsLUU6yUkh%2F23gKjVXhTjoagztdljO3T1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1474&quot; height=&quot;658&quot; data-origin-width=&quot;1474&quot; data-origin-height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.oracle.com/javase/specs/jls/se17/html/jls-15.html#jls-15.10.1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DimExprs: 배열의 크기를 지정하는 표현식.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Dims: 배열의 차원을 나타내며, 크기를 명시하지 않는 빈 대괄호([ ])로 표현.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ArrayInitializer: 배열 초기화 블록 { ... }.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열 생성의 제약 사항&lt;/span&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;타입 검증&lt;/b&gt;: 클래스나 인터페이스 타입은 &lt;b&gt;구체화 가능한 타입(reifiable type)&lt;/b&gt;이어야 하며, 매개변수화된 타입은 사용할 수 없습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;크기 표현식&lt;/b&gt;: 배열 크기를 지정하는 표현식은 정수 타입으로 변환 가능해야 하며(int 또는 long), 음수일 경우 &lt;b&gt;NegativeArraySizeException&lt;/b&gt;이 발생합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;correct-initialization&quot; style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;올바른 배열 초기화 방법&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int[] arr1 = {1, 2, 3};
int[] arr2 = new int[]{1, 2, 3};
int[] arr3 = new int[3];
arr3[0] = 1;
arr3[1] = 2;
arr3[2] = 3;&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;h3 id=&quot;conclusion&quot; style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;결론 &amp;amp; 참고자료&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자바에서 배열 초기화는 &lt;b&gt;컴파일 시점과 런타임 시점&lt;/b&gt;의 특성을 이해하는 것이 중요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열의 크기와 초기값을 동시에 명시할 수 없다는 점은 설계 원칙에 따라 엄격하게 적용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열 생성 시 초기값을 명시하려면 new int[]{...}와 같이 초기화 블록을 사용하거나, 별도로 배열 크기와 요소 값을 각각 설정하는 방식으로 코드를 작성해야 합니다.&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;Java Docs Chapter 10. Array&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.oracle.com/javase/specs/jls/se17/html/jls-10.html#jls-ArrayInitializer&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/javase/specs/jls/se17/html/jls-10.html#jls-ArrayInitializer&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737425221159&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Chapter&amp;nbsp;10.&amp;nbsp;Arrays&quot; data-og-description=&quot;int[] ai; // array of int short[][] as; // array of array of short short s, // scalar short aas[][]; // array of array of short Object[] ao, // array of Object otherAo; // array of Object Collection [] ca; // array of Collection of unknown type The declara&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/javase/specs/jls/se17/html/jls-10.html#jls-ArrayInitializer&quot; data-og-url=&quot;https://docs.oracle.com/javase/specs/jls/se17/html/jls-10.html#jls-ArrayInitializer&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/specs/jls/se17/html/jls-10.html#jls-ArrayInitializer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/javase/specs/jls/se17/html/jls-10.html#jls-ArrayInitializer&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Chapter&amp;nbsp;10.&amp;nbsp;Arrays&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;int[] ai; // array of int short[][] as; // array of array of short short s, // scalar short aas[][]; // array of array of short Object[] ao, // array of Object otherAo; // array of Object Collection [] ca; // array of Collection of unknown type The declara&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;color: #000000;&quot;&gt;Java SE 17&amp;nbsp; docs&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Arrays.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Arrays.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737425239049&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Arrays (Java SE 17 &amp;amp; JDK 17)&quot; data-og-description=&quot;public class Arrays extends Object This class contains various methods for manipulating arrays (such as sorting and searching). This class also contains a static factory that allows arrays to be viewed as lists. The methods in this class all throw a NullPo&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Arrays.html&quot; data-og-url=&quot;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Arrays.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Arrays.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Arrays.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Arrays (Java SE 17 &amp;amp; JDK 17)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;public class Arrays extends Object This class contains various methods for manipulating arrays (such as sorting and searching). This class also contains a static factory that allows arrays to be viewed as lists. The methods in this class all throw a NullPo&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>알고리즘</category>
      <category>자바배열</category>
      <category>컴파일과런타임</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/225</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94%EA%B0%80-%EB%B0%B0%EC%97%B4%EC%9D%84-%EC%83%9D%EC%84%B1%ED%95%98%EB%8A%94-%EC%9B%90%EB%A6%AC-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0#entry225comment</comments>
      <pubDate>Tue, 21 Jan 2025 11:15:01 +0900</pubDate>
    </item>
    <item>
      <title>Java 조각모음 [3]</title>
      <link>https://nstgic3.tistory.com/entry/Java-%EC%A1%B0%EA%B0%81%EB%AA%A8%EC%9D%8C-3</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&lt;br /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목차&lt;/span&gt;&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;이번 포스팅에서 나오는 주요 키워드&lt;/span&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;JRE, JDK, JVM&lt;/b&gt;: 자바 실행 환경(JRE)과 개발 환경(JDK)의 차이점은 JRE는 실행만 가능하고, JDK는 개발 도구까지 포함. JVM은 자바 바이트 코드를 실행하며, 플랫폼 독립성을 제공.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;저급언어 vs 고급언어&lt;/b&gt;: 저급언어는 하드웨어에 종속적이고 이식성이 낮으며, 고급언어는 사람이 이해하기 쉬워 이식성이 높음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴파일러 vs 인터프리터&lt;/b&gt;: 컴파일러는 소스 코드를 전체 번역 후 실행 파일 생성. 인터프리터는 한 줄씩 번역과 실행을 동시에 수행.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파이썬과 자바의 실행 방식&lt;/b&gt;: 파이썬은 인터프리터 방식으로 즉시 실행, 자바는 컴파일 후 바이트 코드 생성 및 JVM 실행.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;.java 파일 vs .class 파일&lt;/b&gt;: .java는 사람이 작성한 소스 코드 파일, .class는 컴파일된 바이트 코드 파일로 JVM에서 실행 가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;main 메서드&lt;/b&gt;: 자바 프로그램의 시작점으로 JVM이 이를 찾아 실행.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자바의 플랫폼 독립성&lt;/b&gt;: 컴파일된 바이트 코드를 플랫폼별 JVM이 실행하므로 독립성 보장.&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;var 키워드&lt;/b&gt;: Java 10부터 타입 추론 지원. 지역 변수에만 사용 가능하며 초기화 값 필수.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자바 vs 자바스크립트 변수 선언&lt;/b&gt;: 자바는 강타입 언어로 타입을 명시하거나 추론, 자바스크립트는 약타입 언어로 타입 명시 불필요하며 var, let, const 사용.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;boolean 타입 크기&lt;/b&gt;: JVM 구현에 따라 다르며 일반적으로 1바이트.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지역 변수 초기화&lt;/b&gt;: JVM이 초기값을 할당하지 않아 초기화하지 않으면 컴파일 오류 발생.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;long vs float&lt;/b&gt;: long은 64비트 정수형으로 정밀도가 높고 범위가 제한적. float은 32비트지만 부동소수점 방식으로 더 큰 범위 표현 가능.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문자열 비교&lt;/b&gt;: == 연산자는 주소값 비교, equals()는 실제 값 비교. 값 비교 시 equals() 사용 권장.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리터럴&lt;/b&gt;: 프로그램에 고정된 값. 정수형(10), 실수형(3.14), 문자형('A'), 문자열(&quot;Hello&quot;), 논리형(true).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;String 포맷 형식&lt;/b&gt;: %[flags][width][.precision]conversion. flags는 정렬과 부호, width는 최소 폭, precision은 정밀도, conversion은 형식 지정.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;switch 구문&lt;/b&gt;: Java 7부터 String 지원. 해시코드 기반 최적화. long은 처리 비용 때문에 미지원.&lt;/li&gt;
&lt;/ul&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;본문&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q1. JRE, JDK, JVM 개념의 차이점을 설명해주세요&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A1. JRE(Java Runtime Environment)은 자바 프로그램을 실행하기 위한 환경을 제공하는 소프트웨어 패키지이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; JDK(Java Development Kit)는 자바 프로그램을 개발하기 위한 환경을 제공하며, JRE와 개발 도구를 포함한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;JVM(Java Virtual Machine)은 자바 바이트 코드를 실행하는 가상 머신으로, 플랫폼에 종속적이다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1213&quot; data-origin-height=&quot;883&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RKVN7/btsLSzb2jSE/F5kyDxzvdfKVhR83tDPqX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RKVN7/btsLSzb2jSE/F5kyDxzvdfKVhR83tDPqX0/img.png&quot; data-alt=&quot;우리는 JDK 에 대한 설정(지정) 만 한다. 내부 구조에 관해서는 jdk 내부에서 수행된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RKVN7/btsLSzb2jSE/F5kyDxzvdfKVhR83tDPqX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRKVN7%2FbtsLSzb2jSE%2FF5kyDxzvdfKVhR83tDPqX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;531&quot; height=&quot;387&quot; data-origin-width=&quot;1213&quot; data-origin-height=&quot;883&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;우리는 JDK 에 대한 설정(지정) 만 한다. 내부 구조에 관해서는 jdk 내부에서 수행된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q2. 저급언어와 고급언어의 개념과 차이점을 설명해주세요&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A2. 저급언어는 기계어에 가까운 언어로 하드웨어에 최적화된 프로그램을 작성할 수 있으나 이식성이 떨어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;고급언어는 사람이 이해하기 쉬운 언어로, 하드웨어에 독립적이고 이식성이 높아 프로그램을 빠르게 작성할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q3. 컴파일러와 인터프리터의 차이점을 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A3. 컴파일러는 전체 소스 코드를 기계어로 번역하여 실행 파일을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;반면, 인터프리터는 소스 코드를 한 줄씩 번역하고 실행하며, 번역된 코드를 즉시 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;489&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DiL7G/btsLUnucwrP/xRIc9EAcPxi3yfPWQtlqT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DiL7G/btsLUnucwrP/xRIc9EAcPxi3yfPWQtlqT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DiL7G/btsLUnucwrP/xRIc9EAcPxi3yfPWQtlqT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDiL7G%2FbtsLUnucwrP%2FxRIc9EAcPxi3yfPWQtlqT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;489&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;489&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q4. 파이썬과 자바를 컴파일러와 인터프리터의 개념과 함께 차이점을 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A4. 파이썬은 인터프리터 언어로 소스 코드를 실행 시 즉시 번역하고 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자바는 컴파일러 언어로, 전체 소스 코드를 번역해 바이트 코드를 생성한 후 JVM이 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;317&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/62eRo/btsLUkRYQwF/qkqSsgkyNLPURC73qfCs7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/62eRo/btsLUkRYQwF/qkqSsgkyNLPURC73qfCs7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/62eRo/btsLUkRYQwF/qkqSsgkyNLPURC73qfCs7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F62eRo%2FbtsLUkRYQwF%2FqkqSsgkyNLPURC73qfCs7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;613&quot; height=&quot;317&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;317&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q5. 자바의 .java 파일과 .class 파일의 차이점을 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A5. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;.java 파일은 자바 소스 코드 파일로 사람이 읽을 수 있는 텍스트 파일이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; caret-color: auto; letter-spacing: 0px;&quot;&gt;.class 파일은 컴파일된 바이트 코드 파일로, JVM이 실행 가능한 이진 파일이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5OoGB/btsLSrENekh/yAw5r7O5nRmqBfedDamMz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5OoGB/btsLSrENekh/yAw5r7O5nRmqBfedDamMz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5OoGB/btsLSrENekh/yAw5r7O5nRmqBfedDamMz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5OoGB%2FbtsLSrENekh%2FyAw5r7O5nRmqBfedDamMz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;536&quot; height=&quot;152&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;152&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q6. 자바를 실행시킬 때 main이라는 메서드가 필요한 이유를 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A6. main 메서드는 프로그램의 시작점이며, JVM이 이를 찾아 실행한다. main 메서드가 종료되면 프로그램도 종료된다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;*&lt;a href=&quot;https://www.javatpoint.com/java-main-method&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.javatpoint.com/java-main-method&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737355259167&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Java Main Method&quot; data-og-description=&quot;Java main() method with oops, string, exceptions, multithreading, collections, jdbc, rmi, fundamentals, programs, swing, javafx, io streams, networking, sockets, classes, objects etc,&quot; data-og-host=&quot;www.javatpoint.com&quot; data-og-source-url=&quot;https://www.javatpoint.com/java-main-method&quot; data-og-url=&quot;https://www.javatpoint.com/java-main-method&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.javatpoint.com/java-main-method&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.javatpoint.com/java-main-method&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Java Main Method&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Java main() method with oops, string, exceptions, multithreading, collections, jdbc, rmi, fundamentals, programs, swing, javafx, io streams, networking, sockets, classes, objects etc,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.javatpoint.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q7. main 메서드가 없어도 컴파일은 가능하지만 실행이 불가능한 이유를 컴파일러 javac와 JVM의 역할과 함께 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A7. 컴파일러(javac)는 문법 검사를 통해 바이트 코드로 변환하지만, 실행은 JVM이 담당한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;JVM은 프로그램의 시작점을 main 메서드로 인식하기 때문에 main 메서드가 없으면 실행할 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q8. 자바가 플랫폼에 독립적인 이유를 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A8. 자바는 바이트 코드와 JVM 덕분에 플랫폼 독립적이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자바 컴파일러는 바이트 코드를 생성하며, 플랫폼에 종속적인 JVM가 이를 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q9. 변수의 정의와 컴퓨터 내 저장 구조를 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A9. 변수는 값을 저장하는 메모리 공간으로, 메모리 주소와 값을 통해 데이터를 저장하고 읽는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;변수 이름을 통해 해당 메모리 주소를 간접적으로 참조할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q10. 기본형 변수와 참조형 변수의 차이점을 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A10. 기본형 변수는 데이터를 직접 저장하며, 스택 메모리에 저장된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;참조형 변수는 데이터의 주소를 저장하며, 힙 메모리에 동적으로 할당된다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;*&lt;a href=&quot;https://java-programming.mooc.fi/part-5/3-primitive-and-reference-variables&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://java-programming.mooc.fi/part-5/3-primitive-and-reference-variables&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q11. 자바의 변수 명명 규칙을 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A11. 변수 이름은 영문자, 숫자, 언더스코어(_), 달러($)로 구성할 수 있으며, 숫자로 시작할 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대소문자를 구분하며 예약어를 사용할 수 없습니다. 의미 있는 이름과 카멜 표기법을 권장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q12. 자바에서 변수 선언 시 var 키워드를 사용할 수 있는 경우와 사용할 수 없는 경우를 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A12. var 키워드는 Java 10부터 지원되며 지역 변수의 타입을 추론할 때 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;초기화 값이 필요하며, 메서드 매개변수, 클래스 필드 등에는 사용할 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1155&quot; data-origin-height=&quot;799&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm6Rxz/btsLS9RvmHf/KetznyJ3owjabtoTjSkCVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm6Rxz/btsLS9RvmHf/KetznyJ3owjabtoTjSkCVk/img.png&quot; data-alt=&quot;https://docs.oracle.com/javase/10/language/toc.htm&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm6Rxz/btsLS9RvmHf/KetznyJ3owjabtoTjSkCVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm6Rxz%2FbtsLS9RvmHf%2FKetznyJ3owjabtoTjSkCVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1155&quot; height=&quot;799&quot; data-origin-width=&quot;1155&quot; data-origin-height=&quot;799&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.oracle.com/javase/10/language/toc.htm&lt;/figcaption&gt;
&lt;/figure&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;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q13. 자바와 자바스크립트의 변수 선언 방식과 차이점을 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A13. 자바는 Strongly Typed Language로 데이터 타입을 명시해야 하고, var 키워드로 타입을 추론할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자바스크립트는 Weakly Typed Language로 데이터 타입을 명시하지 않아도 되고, var, let, const 키워드를 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q14. boolean 타입의 변수의 크기는 몇 바이트인지 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A14. boolean 타입은 JVM의 구현에 따라 다르지만 일반적으로 1바이트 크기를 가지며, true와 false 값을 저장하는 데 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q15. 지역 변수는 초기화하지 않고 사용할 수 없는 이유에 대해서 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A15. 지역변수의 구조를 확인해보면 컴파일 타임에는 초기화되지 않은 상태로 할당되며, JVM이 기본값을 부여하지 않는다는 특성이 있다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 값이 전역적으로 존재하는 특성을 가진 전역 변수와 달리, 특정 메서드나 함수 내부에서만 사용하는 변수의 관리에 따른 메모리의 효율성과 예측 가능한 동작을 위해 설계된 것이다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;초기화를 하지 않고 해당 변수를 사용하면, 값이 존재하지 않아 예기치 못한 동작이나 오류가 발생할 수 있으므로, 컴파일러가 이러한 상황을 사전에 막기 위해 초기화 여부를 체크힌다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;따라서 자바 컴파일러는 런타임 오류를 줄이고 프로그램의 안정성을 높이기 위해서 지역 변수가 반드시 초기화된 후 사용되도록 강제한다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q16. long과 float 자료형을 비교하자면 메모리 할당 크기는 long이 float보다 크지만, float이 long보다 큰 수를 표현할 수 있는 이유를 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A16. long은 정수형 데이터 타입으로, 8바이트 크기를 가지며, 부호를 포함한 64비트 정수 값을 저장할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;float은 실수형 데이터 타입으로, 4바이트 크기를 가지며, IEEE 754 표준에 따라 32비트 부동 소수점 값을 저장할 수 있습니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;부동 소수점 방식은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;소수점의 위치를 고정하지 않고, 가수와 지수로 나누어 실수를 표현하는 방식&lt;/span&gt;으로, 더 넓은 범위의 수를 표현할 수 있습니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;따라서, float은 long보다 더 큰 수를 표현할 수 있지만, 정밀도가 떨어지기 때문에 정밀한 계산이 필요한 경우에는 double을 사용하는 것이 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q17. 자바에서 문자열을 비교할 때 == 연산자와 equals() 메서드의 차이점을 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A17.자바에서 문자열을 비교할 때 == 연산자는 두 문자열의 주소를 비교하는 연산자이고, equals() 메서드는 두 문자열의 값을 비교하는 메서드입니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 연산자는 두 문자열의 주소를 비교하기 때문에, 두 문자열이 같은 주소를 참조하고 있는 경우에만 true를 반환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; equals() 메서드는 두 문자열의 값을 비교하기 때문에, 두 문자열이 같은 값을 가지고 있는 경우에 true를 반환합니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 따라서, 문자열의 값을 비교할 때는 equals() 메서드를 사용하는 것이 안전하고, 문자열의 주소를 비교할 때는 == 연산자를 사용하는 것이 효율적입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1; text-align: start;&quot; href=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94-String-Pool-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot;&gt;2025.01.20 - [Java] - 예제로 배우는 자바 String Pool 이해하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737358254609&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;예제로 배우는 자바 String Pool 이해하기&quot; data-og-description=&quot;개요 이번 글에서는 예제를 통해 자바의 String Pool과 intern() 메서드 개념을 자세히 알아봅니다.&amp;nbsp;문자열 리터럴과 new 연산자를 통한 객체 생성, 그리고 intern() 메서드 사용 시 String Pool 내의 객체 &quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94-String-Pool-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94-String-Pool-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/v4CTV/hyX4nWtRkp/lIZVpHL3lhqwnXNHB5GiGk/img.png?width=800&amp;amp;height=794&amp;amp;face=0_0_800_794,https://scrap.kakaocdn.net/dn/bGFSJg/hyX4tCmQpa/Hb0KhQAFVwgubXCKm5ZOQ1/img.png?width=800&amp;amp;height=794&amp;amp;face=0_0_800_794,https://scrap.kakaocdn.net/dn/c6Iyi4/hyX4wePD1q/loMIki6KHW9PKvkcxg7Qt1/img.png?width=750&amp;amp;height=744&amp;amp;face=0_0_750_744&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94-String-Pool-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94-String-Pool-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/v4CTV/hyX4nWtRkp/lIZVpHL3lhqwnXNHB5GiGk/img.png?width=800&amp;amp;height=794&amp;amp;face=0_0_800_794,https://scrap.kakaocdn.net/dn/bGFSJg/hyX4tCmQpa/Hb0KhQAFVwgubXCKm5ZOQ1/img.png?width=800&amp;amp;height=794&amp;amp;face=0_0_800_794,https://scrap.kakaocdn.net/dn/c6Iyi4/hyX4wePD1q/loMIki6KHW9PKvkcxg7Qt1/img.png?width=750&amp;amp;height=744&amp;amp;face=0_0_750_744');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;예제로 배우는 자바 String Pool 이해하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요 이번 글에서는 예제를 통해 자바의 String Pool과 intern() 메서드 개념을 자세히 알아봅니다.&amp;nbsp;문자열 리터럴과 new 연산자를 통한 객체 생성, 그리고 intern() 메서드 사용 시 String Pool 내의 객체&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q18. 하지만 ==로도 String 비교가 가능한 경우가 있습니다. 그 이유를 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A18. 문자열 리터럴은 상수 풀(Constant Pool)에 저장되며, 동일한 리터럴은 동일한 주소를 참조합니다. 따라서 == 연산자로 비교해도 true를 반환할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q19. 리터럴이 뭔가요? 리터럴의 종류와 예시를 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A19. 리터럴은 프로그램에서 고정된 값을 의미하며, 정수형(10), 실수형(3.14), 문자형('A'), 문자열(&quot;Hello&quot;), 논리형(true, false) 등이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q20. String의 포맷 문자 형식을 설명해주세요. %[flags][width][.precision]conversion&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A20. &lt;b&gt;%[flags]&lt;/b&gt;는 출력 형식을 지정하는데 사용되며, -는 왼쪽 정렬, +는 부호 표시, 0은 빈 자리를 0으로 채움을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;%[width]&lt;/b&gt;는 출력 폭을 지정하는데 사용되며, 출력 폭은 최소 폭을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;%[.precision]&lt;/b&gt;은 출력 정밀도를 지정하는데 사용되며, 정수의 경우 소수점 이하 자리수를, 문자열의 경우 최대 길이를 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;conversion&lt;/b&gt;은 출력 형식을 지정하는데 사용되며, d는 10진수, o는 8진수, x는 16진수, f는 실수, s는 문자열을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q21. switch 구문은 처음 설계될 당시 문자열을 사용할 수 없었지만, Java 7에서 허용되었습니다. 반면, 여전히 long은 사용할 수 없습니다. 이러한 설계 목적과 이유를 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A21. switch 구문의 설계는 성능 최적화와 특정 데이터 타입의 사용 제한을 염두에 두고 이루어졌습니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사례를 통해 설계 이념(?) 을 확인해보면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737358510713&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;The switch Statement (The Java&amp;trade; Tutorials &amp;gt;        
            Learning the Java Language &amp;gt; Language Basics)&quot; data-og-description=&quot;The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Dev.java for updated tutorials taking advantag&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html&quot; data-og-url=&quot;https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;The switch Statement (The Java&amp;trade; Tutorials &amp;gt; Learning the Java Language &amp;gt; Language Basics)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Dev.java for updated tutorials taking advantag&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. String이 Java 7 이전에 지원되지 않았던 이유&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;초기 Java 설계에서 switch는 간단한 정수 기반 분기를 위해 만들어졌습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이를 통해 컴파일러는 내부적으로 테이블 점프(table jump) 또는 바이너리 검색(binary search) 방식을 사용하여 매우 빠른 실행 속도를 제공할 수 있었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 String은 참조 타입으로, 문자열 비교는 equals() 메서드를 사용해야 하고 해시코드 계산이 필요하기 때문에, 초기에는 switch 설계에서 제외되었습니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;2. Java 7 이후 String이 지원된 이유&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Java 7에서는 String 비교를 위한 최적화가 도입되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;내부적으로 switch는:&amp;nbsp; 각 문자열의 해시코드를 기반으로 case를 구분합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;동일한 해시코드를 가진 문자열에 대해서는 equals() 메서드로 추가 확인을 수행합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이를 통해 문자열 비교를 효율적으로 처리할 수 있게 되어, switch에서 String 사용이 허용되었습니다.&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;3. long이 여전히 지원되지 않는 이유&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;switch는 정수 기반 분기에 초점이 맞춰져 있습니다. long은 64비트 크기를 가지며, 이를 분기로 사용하기 위해서는 더 많은 메모리와 복잡한 처리가 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 대부분의 경우, long을 switch에서 사용하는 사례는 드물며, 복잡한 비교가 필요한 경우 if-else가 더 적합합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;설계의 간소화를 위해&lt;/b&gt; long은 지원하지 않는 것으로 유지되고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;출처 &amp;amp; 추가로 알아보면 좋은것&lt;/span&gt;&lt;/span&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;b&gt;JVM 내부 구조&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Class Loader, Memory Area(Stack, Heap), Execution Engine.&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1; text-align: start;&quot; href=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C&quot;&gt;2024.06.25 - [Java] - JVM스택메모리 구조 이해를 위한 바이트코드 예시&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자바 컴파일 과정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;.java &amp;rarr; .class &amp;rarr; JVM 실행 과정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메모리 관리&lt;/b&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;a style=&quot;background-color: #e6f5ff; color: #0070d1;&quot; href=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94-%EA%B0%80%EB%B9%84%EC%A7%80-%EC%BB%AC%EB%A0%89%ED%84%B0GC%EC%9D%98-%EB%B0%9C%EC%A0%84-%EC%8B%9C%EB%A6%AC%EC%96%BC-%EC%BB%AC%EB%A0%89%ED%84%B0%EB%B6%80%ED%84%B0-ZGC%EA%B9%8C%EC%A7%80&quot;&gt;2024.07.20 - [Java] - 자바 가비지 컬렉터(GC)의 발전; 시리얼 컬렉터부터 ZGC까지&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;멀티스레드 환경에서의 변수&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Thread-safe 변수와 동기화.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자바와 자바스크립트의 주요 차이점&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Java</category>
      <category>면접 대비</category>
      <category>자바 기초</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/224</guid>
      <comments>https://nstgic3.tistory.com/entry/Java-%EC%A1%B0%EA%B0%81%EB%AA%A8%EC%9D%8C-3#entry224comment</comments>
      <pubDate>Mon, 20 Jan 2025 16:39:39 +0900</pubDate>
    </item>
    <item>
      <title>예제로 배우는 자바 String Pool 이해하기</title>
      <link>https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94-String-Pool-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;overview&quot; style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt; 이번 글에서는 예제를 통해 자바의 String Pool과 intern() 메서드 개념을 자세히 알아봅니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;문자열 리터럴과 new 연산자를 통한 객체 생성, 그리고 intern() 메서드 사용 시 String Pool 내의 객체 참조를 어떻게 변경하는지 살펴봅니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 id=&quot;compile-vs-runtime&quot; style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;들어가기 전에&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737352605671&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Case 1
String str1 = &quot;Hello, World!&quot;;
String str2 = &quot;Hello, World!&quot;;
String str3 = new String(&quot;Hello, World!&quot;);
String str4 = new String(&quot;Hello, World!&quot;);

System.out.println(str1 == str2); 
System.out.println(str1 == str3); 
System.out.println(str3 == str4); 

// Case 2
str3 = str3.intern();
str4 = str4.intern();

System.out.println(str1 == str3);
System.out.println(str3 == str4);

// Case 3
String str5 = &quot;Hello, &quot;;
String str6 = &quot;World!&quot;;
String str7 = &quot;Hello, &quot; + &quot;World!&quot;;
String str8 = str5 + str6;

System.out.println(str7 == str8); 
System.out.println(str7.equals(str8));&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;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;어떤 결과가 나올지 한번 예상해보자.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 id=&quot;section1&quot; style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;1. 문자열 리터럴과 String Pool&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333;&quot;&gt; 자바에서 문자열은 보통 두 가지 방식으로 생성됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsezO8/btsLUimlo8a/DmTQ988bfDQfPwHBM1P9sk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsezO8/btsLUimlo8a/DmTQ988bfDQfPwHBM1P9sk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsezO8/btsLUimlo8a/DmTQ988bfDQfPwHBM1P9sk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsezO8%2FbtsLUimlo8a%2FDmTQ988bfDQfPwHBM1P9sk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;348&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot; data-ke-size=&quot;size20&quot;&gt;문자열 리터럴&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 예를 들어, &lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str1 = &quot;Hello, World!&quot;;
String str2 = &quot;Hello, World!&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 위와 같이 리터럴 형태로 문자열을 생성하면, JVM은 &lt;b&gt;String Pool&lt;/b&gt;이라는 메모리 영역에 해당 문자열을 저장합니다. 동일한 리터럴은 한 번만 저장되므로,&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;System.out.println(str1 == str2); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 로 두 변수는 같은 객체를 참조하게 됩니다.&lt;/span&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;h4 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot; data-ke-size=&quot;size20&quot;&gt;new 연산자를 통한 문자열 생성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 예를 들어, &lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str3 = new String(&quot;Hello, World!&quot;);
String str4 = new String(&quot;Hello, World!&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 이 경우, 문자열 리터럴 &quot;Hello, World!&quot;는 String Pool에 존재하더라도, new 연산자를 통해 Heap 영역에 별도의 객체가 생성됩니다. 그래서 &lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;System.out.println(str1 == str3); // false
System.out.println(str3 == str4); // false&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 id=&quot;section2&quot; style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. intern() 메서드로 String Pool 활용하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 자바의 intern() 메서드는 해당 문자열이 이미 String Pool에 존재하면 그 참조를 반환하고, 존재하지 않으면 String Pool에 추가한 후 그 참조를 반환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LUXp8/btsLUpMh9XS/2ICJwPM6sKiya4vOneVSy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LUXp8/btsLUpMh9XS/2ICJwPM6sKiya4vOneVSy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LUXp8/btsLUpMh9XS/2ICJwPM6sKiya4vOneVSy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLUXp8%2FbtsLUpMh9XS%2F2ICJwPM6sKiya4vOneVSy1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;830&quot; height=&quot;240&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 따라서, 아래와 같이 new 연산자로 생성한 문자열에 대해 intern()를 호출하면 String Pool에 저장된 문자열을 참조하게 되어 &lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;ini&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;str3 = str3.intern();
str4 = str4.intern();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 결과적으로, &lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;System.out.println(str1 == str3); // true
System.out.println(str3 == str4); // true&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&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;h3 id=&quot;section3&quot; style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. 컴파일 시점 vs 런타임 시점 문자열 결합&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 문자열 결합은 두 방식으로 처리됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot; data-ke-size=&quot;size20&quot;&gt;컴파일 시점 결합&lt;/h4&gt;
&lt;pre class=&quot;armasm&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str7 = &quot;Hello, &quot; + &quot;World!&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 컴파일러가 상수 리터럴끼리의 결합을 최적화하여 &quot;Hello, World!&quot;로 미리 계산 후 String Pool에 저장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot; data-ke-size=&quot;size20&quot;&gt;런타임 시점 결합&lt;/h4&gt;
&lt;pre class=&quot;armasm&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str5 = &quot;Hello, &quot;;
String str6 = &quot;World!&quot;;
String str8 = str5 + str6;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 변수들을 사용한 결합은 런타임에 수행되어 새로운 문자열 객체가 생성됩니다. 이 객체는 기본적으로 String Pool에 저장되지 않으므로,&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;System.out.println(str7 == str8); // false
System.out.println(str7.equals(str8)); // true&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;equals() 을 사용한다면 역시나 같은 결과가 나오지만 str7은 String Pool에 있는 리터럴 참조이고, str8은 런타임에 만들어진 새로운 객체의 참조이기에 false 가 나온다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;203&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bj1qDg/btsLUH0cpkQ/o9QSlfwg1Bp8hyvfpug5Tk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bj1qDg/btsLUH0cpkQ/o9QSlfwg1Bp8hyvfpug5Tk/img.jpg&quot; data-alt=&quot;https://blog.devgenius.io/beginners-guide-to-compile-time-and-runtime-polymorphism-in-java-72d197862778&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bj1qDg/btsLUH0cpkQ/o9QSlfwg1Bp8hyvfpug5Tk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj1qDg%2FbtsLUH0cpkQ%2Fo9QSlfwg1Bp8hyvfpug5Tk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;754&quot; height=&quot;203&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;203&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://blog.devgenius.io/beginners-guide-to-compile-time-and-runtime-polymorphism-in-java-72d197862778&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 id=&quot;section4&quot; style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;4. UsingConstantPool 예제 코드&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 아래는 주석과 출력 결과 설명 없이 정리한 최종 코드입니다. &lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class UsingConstantPool {
	public static void main(String[] args) {
		// Case 1
		String str1 = &quot;Hello, World!&quot;;
		String str2 = &quot;Hello, World!&quot;;
		String str3 = new String(&quot;Hello, World!&quot;);
		String str4 = new String(&quot;Hello, World!&quot;);
		
		System.out.println(str1 == str2); // true
		// str1은 String Pool의 객체이고, str3은 Heap에 새로 생성된 객체이므로 서로 다른 참조를 가진다. 따라서 false가 출력된다.
		System.out.println(str1 == str3); // false
		// 각각 별도의 new 연산자로 생성된 Heap 객체이므로 서로 다른 참조를 가진다. 따라서 false가 출력된다.
		System.out.println(str3 == str4); // false
		
		// Case 2
		
		// intern() 메서드는 호출한 문자열 객체가 이미 String Pool에 존재하면 그 객체의 참조를 반환하고, 존재하지 않으면 현재 문자열 객체를 String Pool에 추가한 후 그 참조를 반환한다.
		str3 = str3.intern();
		str4 = str4.intern();
		
		System.out.println(str1 == str3); // true
		// str3과 str4 모두 &quot;Hello, World!&quot;라는 String Pool에 저장된 객체의 참조를 가지고 있으므로 true가 출력된다.
		System.out.println(str3 == str4); // true
		
		// Case 3
		String str5 = &quot;Hello, &quot;;
		String str6 = &quot;World!&quot;;
		// &quot;Hello, &quot; + &quot;World!&quot;는 두 리터럴의 연결이 컴파일 시점에 수행되어 &quot;Hello, World!&quot;라는 단일 리터럴로 변환
		String str7 = &quot;Hello, &quot; + &quot;World!&quot;;
		// str5 + str6는 변수들을 사용한 연결이기 때문에 런타임에 문자열 결합이 수행됩니다. 즉, 새로운 문자열 객체가 생성되며, 이 객체는 기본적으로 String Pool에 자동으로 저장되지 않는다.
		String str8 = str5 + str6;
		
		// str7은 String Pool에 있는 리터럴 참조이고, str8은 런타임에 만들어진 새로운 객체의 참조이다.
		System.out.println(str7 == str8); // false
		// 두 문자열의 값(내용)이 동일하기 때문에 equals() 메서드는 true를 반환한다.
		System.out.println(str7.equals(str8)); // true
		
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 id=&quot;section5&quot; style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;5. 정리 및 마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333;&quot;&gt; String Pool은 &lt;b&gt;JVM이 문자열 리터럴을 재사용하기 위해 관리하는 메모리 영역&lt;/b&gt;입니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #333333;&quot;&gt; &lt;code&gt;==&lt;/code&gt; 연산자는&lt;b&gt; 객체의 참조를 비교&lt;/b&gt;하고, &lt;code&gt;equals()&lt;/code&gt; 메서드는 &lt;b&gt;문자열의 내용을 비교&lt;/b&gt;합니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #333333;&quot;&gt; &lt;code&gt;intern()&lt;/code&gt; 메서드를 사용하면 Heap 영역의 문자열 객체를 String Pool에 있는 &lt;b&gt;동일한 값의 객체로 연결&lt;/b&gt;할 수 있습니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #333333;&quot;&gt;또한, &lt;span style=&quot;background-color: #f3c000;&quot;&gt;&lt;b&gt;컴파일 시점에 결합되는 문자열 리터럴&lt;/b&gt;과 &lt;b&gt;런타임에 결합되는 문자열 객체&lt;/b&gt;는 비교 결과가 다를 수 있으므로 주의&lt;/span&gt;해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>intern()</category>
      <category>string pool 원리</category>
      <category>문자열 리터럴 jvm</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/223</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%EC%9E%90%EB%B0%94-String-Pool-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0#entry223comment</comments>
      <pubDate>Mon, 20 Jan 2025 15:20:15 +0900</pubDate>
    </item>
    <item>
      <title>Java 조각모음 [2]</title>
      <link>https://nstgic3.tistory.com/entry/Java-%EC%A1%B0%EA%B0%81%EB%AA%A8%EC%9D%8C-2</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이번 포스팅에서 나오는 주요 키워드&lt;/span&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;빌드 도구:&lt;/b&gt; Maven, Gradle, Groovy, Ant&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파일 구분:&lt;/b&gt; 자바 파일(.java), 클래스 파일(.class)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;패키지와 의존성:&lt;/b&gt; 패키지의 역할, Maven 의존성 관리, Gradle의 동적 버전 관리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예외 처리:&lt;/b&gt; MalformedURLException, IOException&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 통신:&lt;/b&gt; URLConnection, HttpURLConnection&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JSON:&lt;/b&gt; JSONObject, JSONArray, JSON 형식&lt;/li&gt;
&lt;li&gt;&lt;b&gt;입출력:&lt;/b&gt; BufferedWriter, BufferedReader, StringBuilder&lt;/li&gt;
&lt;li&gt;&lt;b&gt;크롤링:&lt;/b&gt; Selenium, ChromeDriver, WebDriver&lt;/li&gt;
&lt;li&gt;&lt;b&gt;경로 탐색:&lt;/b&gt; XPath, CSS Selector&lt;/li&gt;
&lt;li&gt;&lt;b&gt;WebDriver:&lt;/b&gt; 추상화, findElement, WebElement&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;본문&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q1. 자바 프로젝트에서 Maven, Groovy, Gradle, Ant, SBT 등의 빌드 도구를 사용하는 이유는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A1. 빌드 도구를 사용하면 프로젝트의 빌드, 테스트, 배포 작업을 자동화하고 의존성 관리를 효율적으로 수행할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #333333;&quot;&gt;* Maven는 XML 기반의 빌드 도구로 프로젝트 빌드 시에 pom.xml 이 생기게 되는데.. &lt;a href=&quot;https://doosicee.tistory.com/entry/Maven%EC%9D%98-%EC%84%A4%EC%A0%95%ED%8C%8C%EC%9D%BC-Pomxml%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90&quot;&gt;https://doosicee.tistory.com/entry/Maven%EC%9D%98-%EC%84%A4%EC%A0%95%ED%8C%8C%EC%9D%BC-Pomxml%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #333333;&quot;&gt;* Groovy 는 JVM 기반의 동적 언어로, Java와 호환성이 높고 간결한 문법을 가지고 있다. Groovy는 Java와 마찬가지로 JVM에서 실행되며, Java와 Groovy 코드를 혼용하여 사용할 수 있다.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #333333;&quot;&gt;* Gradle 은 Groovy 기반의 빌드 도구로, Maven의 XML 기반 빌드 스크립트 대신 Groovy DSL기반의 빌드 스크립트를 사용하기에 Gradle은 Maven보다 간결하고 유연한 빌드 스크립트를 작성할 수 있으며, Maven과 Ant의 장점을 결합한 빌드 도구이다.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q2. 자바 파일과 자바 클래스 파일의 차이는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A2. 자바 파일(.java)은 소스 코드가 담긴 파일이며 개발자가 작성하는 소스 코드이고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 자바 클래스 파일(.class)은 소스 코드가 컴파일된 바이트 코드 파일이며 JVM에서 바로 실행 가능하다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* 자바의 Write Once, Run Everywhere 이라는 철학은 (아무데에서나 이용가능 ; &lt;b&gt;크로스 플랫포머블&lt;/b&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;JVM 이라는 자바 가상환경을 그 어떤 플랫폼(OS)위에 설치를 한다면 .class 파일을 어디에서든지 실행시킬수 있다는 장점에서 왔다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q3. 자바의 패키지란 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A3. 패키지는 클래스를 구조적으로 관리하고 이름 충돌을 방지하기 위한 단위이다. 명시적인 패키지는 폴더 구조와 매핑된다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q4. Maven 프로젝트에서 의존성 버전을 명시하지 않으면 어떤 문제가 발생할 수 있나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A4. 의존성 버전을 명시하지 않으면 라이브러리 간 충돌이나 예기치 않은 동작이 발생할 수 있다. Gradle은 동적 버전 관리로 최신 버전을 자동으로 사용 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* Gradle 의 장점으로 동적 버전 관리를 지원하는데 Maven 에 비해서 버전을 명시하지 않아도 자동으로 최신 버전을 사용할 수 있다. 또한 의존성 트리 내에서 버전 충돌 또한 자동으로 감지한다.&lt;/span&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2294&quot; data-origin-height=&quot;1092&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wLIDF/btsLQSPQUIr/MiNsSqDd1Z7OxzOxRyGF00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wLIDF/btsLQSPQUIr/MiNsSqDd1Z7OxzOxRyGF00/img.png&quot; data-alt=&quot;gradle 짱짱맨&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wLIDF/btsLQSPQUIr/MiNsSqDd1Z7OxzOxRyGF00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwLIDF%2FbtsLQSPQUIr%2FMiNsSqDd1Z7OxzOxRyGF00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2294&quot; height=&quot;1092&quot; data-origin-width=&quot;2294&quot; data-origin-height=&quot;1092&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;gradle 짱짱맨&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q5. URL 클래스를 생성자를 이용해 main에 선언하였더니 에러가 발생하였습니다. 이유와 해결 방법을 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A5. URL 클래스의 생성자는 예외를 던지므로, 예외 처리를 해주어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; URL 형식이 잘못되었을 때 MalformedURLException이 발생하므로, try-catch 블록으로 예외를 처리하거나 메서드에 throws 절을 추가하여 호출자에게 예외를 전파할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q6. MalformedURLException을 IOException으로 변경하였습니다. 이유가 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A6. MalformedURLException은 IOException의 하위 클래스이므로, IOException으로 변경해도 문제가 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;579&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k9Kf0/btsLQRcpEEX/ag72Uh2YYNGox2lygfKKoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k9Kf0/btsLQRcpEEX/ag72Uh2YYNGox2lygfKKoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k9Kf0/btsLQRcpEEX/ag72Uh2YYNGox2lygfKKoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk9Kf0%2FbtsLQRcpEEX%2Fag72Uh2YYNGox2lygfKKoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;579&quot; height=&quot;292&quot; data-origin-width=&quot;579&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; IOException은 입출력 작업 중 발생하는 예외를 처리하기 위한 상위 클래스입니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 Spring을 활용해 어플리케이션을 만들거나 같은 메서드에서 여러가지 예외가 발생하고, 이를 서로 다르게 핸들링(처리) 해야 되는 경우에는 명확하게 핸들링 해주어야한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q7. (복습) url.openConnection()을 HttpURLConnection으로 형변환하지 않으면 어떤 문제가 발생하나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A7. url.openConnection() 메서드는 URLConnection 타입을 반환합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HttpURLConnection의 메서드를 사용하려면 HttpURLConnection으로 명시적 형변환이 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q8. HttpURLConnection의 setRequestMethod 메서드를 이용하여 GET 방식으로 요청을 보내려고 합니다. 이때 setRequestMethod 메서드의 인자로 POST를 전달하면 어떤 문제가 발생할 수 있나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A8. POST를 전달하면 GET 방식이 아닌 POST 방식으로 요청이 전송됩니다. GET 방식은 URL에 데이터를 포함하며, POST 방식은 요청 본문에 데이터를 담아 전송하기 때문에 서버에서 처리 방식이 달라질 수 있습니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;*GET과 POST 의 차이점은 뭘까요? 멱등성에 대해 알고있나요?&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q9. 왜 API_KEY (인증키) 앞에 Bearer를 붙여서 전송하는지 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A9. Bearer는 HTTP 인증 방식으로, API_KEY와 함께 사용됩니다. Bearer를 사용하면 서버가 API_KEY를 인증 토큰으로 인식하여 인증을 수행할 수 있습니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;RFC6750 에서 명시됨.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc6750&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;* https://datatracker.ietf.org/doc/html/rfc6750&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q10. JSONObject 객체에 .put 메서드를 이용하여 key-value 쌍을 추가하였습니다. 이때 key에 null을 전달하면 어떤 문제가 발생할 수 있나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A10. key에 null을 전달하면 NullPointerException이 발생할 수 있습니다. JSONObject는 null을 key로 허용하지 않으며, 이를 시도하면 예외가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1504&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cG7Lpl/btsLQ3KrkhO/5kBiIzxAeDMDJhGINQ9eok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cG7Lpl/btsLQ3KrkhO/5kBiIzxAeDMDJhGINQ9eok/img.png&quot; data-alt=&quot;https://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cG7Lpl/btsLQ3KrkhO/5kBiIzxAeDMDJhGINQ9eok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcG7Lpl%2FbtsLQ3KrkhO%2F5kBiIzxAeDMDJhGINQ9eok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1504&quot; height=&quot;384&quot; data-origin-width=&quot;1504&quot; data-origin-height=&quot;384&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q11. JSONObject 객체에 .put 메서드를 이용하여 두 개의 인자를 전달하였습니다. 이때 각각의 인자가 어떤 역할을 하는지 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A11. 첫 번째 인자는 key로, 두 번째 인자는 value로 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;JSONObject는 key-value 쌍으로 데이터를 저장하며, 이를 통해 JSON 데이터를 구성할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1584&quot; data-origin-height=&quot;874&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzvyAn/btsLSsbb4mz/oikkoCI3LKa10vb5hWOG5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzvyAn/btsLSsbb4mz/oikkoCI3LKa10vb5hWOG5k/img.png&quot; data-alt=&quot;https://docs.oracle.com/javaee/7/api/javax/json/JsonObject.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzvyAn/btsLSsbb4mz/oikkoCI3LKa10vb5hWOG5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzvyAn%2FbtsLSsbb4mz%2FoikkoCI3LKa10vb5hWOG5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1584&quot; height=&quot;874&quot; data-origin-width=&quot;1584&quot; data-origin-height=&quot;874&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.oracle.com/javaee/7/api/javax/json/JsonObject.html&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보다싶이 슈퍼클래스로 Map&amp;lt;K,V&amp;gt; 를 가지고 있다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q12. JSONArray 객체에 .put 메서드를 이용하여 JSONObject 객체를 추가하였습니다. 이때 JSONArray 객체에 JSONObject 객체를 추가하는 이유는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A12. JSONArray는 여러 개의 JSON 객체를 저장할 수 있는 컨테이너입니다. JSONObject를 JSONArray에 추가하면 배열 형태로 여러 객체를 관리할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1502&quot; data-origin-height=&quot;1038&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4HeMv/btsLQNHTytx/GHlHaozFPusEwIXIfvyXk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4HeMv/btsLQNHTytx/GHlHaozFPusEwIXIfvyXk1/img.png&quot; data-alt=&quot;내부 구조를 보면 JsonValue가 Iterable 한 객체로 감싸져있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4HeMv/btsLQNHTytx/GHlHaozFPusEwIXIfvyXk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4HeMv%2FbtsLQNHTytx%2FGHlHaozFPusEwIXIfvyXk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1502&quot; height=&quot;1038&quot; data-origin-width=&quot;1502&quot; data-origin-height=&quot;1038&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;내부 구조를 보면 JsonValue가 Iterable 한 객체로 감싸져있다.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bt0R4u/btsLQq7uqph/IgzNDiRPqkbo2UbzkFvlH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bt0R4u/btsLQq7uqph/IgzNDiRPqkbo2UbzkFvlH1/img.png&quot; data-alt=&quot;JsonValue 는 JsonObject 를 객체형태로 받고있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bt0R4u/btsLQq7uqph/IgzNDiRPqkbo2UbzkFvlH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbt0R4u%2FbtsLQq7uqph%2FIgzNDiRPqkbo2UbzkFvlH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1160&quot; height=&quot;664&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JsonValue 는 JsonObject 를 객체형태로 받고있다.&lt;/figcaption&gt;
&lt;/figure&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;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q13. BufferedWriter 객체를 생성할 때 new OutputStreamWriter(con.getOutputStream())를 인자로 전달하였습니다. 이때 왜 OutputStreamWriter를 사용하는지 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A13. BufferedWriter 객체를 생성할 때 OutputStreamWriter를 사용하는 이유는, 문자를 바이트로 변환하여 출력 스트림에 쓰기 위함입니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;BufferedWriter는 출력 속도를 높이기 위해 버퍼를 제공하며, OutputStreamWriter는 문자 데이터를 바이트 스트림으로 변환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q14. BufferedWriter 객체의 .write 메서드를 이용하여 data.toString()을 전달하였습니다. 이때 data.toString()이 반환하는 값의 타입은 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A14. data.toString()이 반환하는 값의 타입은 String입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;JSON 객체를 문자열로 변환하여 출력하거나 전송할 수 있게 하기 위함입니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;웹서버-클라 통신은 JSON 을 활용하기 때문에 외부 API등을 이용할때 해당 형식으로 바꿨을것이라고 예상 할수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q15. StringBuilder 객체를 생성할 때 new StringBuilder()를 인자로 전달하였습니다. 이때 왜 StringBuilder를 사용하는지 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A15. StringBuilder는 문자열을 동적으로 변경하기 위해 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;StringBuilder는 불변 객체인 String과 달리, 문자열 조작 시 새로운 객체를 생성하지 않고 내부 버퍼를 이용하여 성능을 향상시킵니다.&lt;/span&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;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p4jVY/btsLSAUykch/P758rdIUPvndj3THRgFvs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p4jVY/btsLSAUykch/P758rdIUPvndj3THRgFvs1/img.png&quot; data-alt=&quot;https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p4jVY/btsLSAUykch/P758rdIUPvndj3THRgFvs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp4jVY%2FbtsLSAUykch%2FP758rdIUPvndj3THRgFvs1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;726&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;span&gt;*동적으로 문자열을 결합할 때 이점이 있다는 특성이 있기에 알고리즘 풀이시에 활용한다.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q16. 외부 API를 사용할 때 BufferedWriter, BufferedReader를 사용하는 이유는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A16. BufferedWriter와 BufferedReader는 입출력 속도를 향상시키기 위해 버퍼를 제공하며, StringBuilder는 문자열 조작 시 새로운 객체를 생성하지 않고 내부 버퍼를 사용해 성능을 최적화합니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* 이를 통해 외부 API와의 데이터 처리 성능이 개선됩니다. 응답 데이터가 불규칙하거나 대량일 경우에 데이터를 부분적으로 읽는 특징이 있기에 메모리의 효율적 사용이 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q17. JSON 형식이란 무엇인가요? JSON 형식의 특징을 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A17. JSON(JavaScript Object Notation)은 데이터를 키-값 쌍으로 표현하는 경량 데이터 형식입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사람이 읽고 쓰기 쉬우며, 기계가 분석하고 생성하기 쉽습니다. 간결하고 다양한 프로그래밍 언어에서 지원됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q18. 크롤링 시 사용하는 Selenium 사용에는 왜 ChromeDriver가 필요한가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A18. Selenium은 웹 애플리케이션을 테스트하기 위한 프레임워크입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ChromeDriver는 Selenium이 Chrome 브라우저를 제어하기 위해 필요한 드라이버로, 브라우저와의 통신을 가능하게 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q19. Driver란 무엇인가요? (운영체제와 하드웨어 사이의 관계)&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A19. Driver는 하드웨어와 운영체제 간의 통신을 가능하게 하는 소프트웨어입니다. 운영체제는 Driver를 통해 하드웨어를 제어하며, 이는 인터페이스 역할을 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;519&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JZU5P/btsLSizS9Qh/YxJPPhy76K6wqahWkxIQ31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JZU5P/btsLSizS9Qh/YxJPPhy76K6wqahWkxIQ31/img.png&quot; data-alt=&quot;https://learn.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/what-is-a-driver-&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JZU5P/btsLSizS9Qh/YxJPPhy76K6wqahWkxIQ31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJZU5P%2FbtsLSizS9Qh%2FYxJPPhy76K6wqahWkxIQ31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;583&quot; height=&quot;466&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;519&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://learn.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/what-is-a-driver-&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q20. 여러 브라우저마다 드라이버가 다르고 매번 이를 선언할 수 없으니 WebDriver를 사용합니다. 이때 WebDriver를 사용하는 이유는 무엇인가요? (객체지향-추상화)&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A20. WebDriver는 여러 브라우저를 동일한 방식으로 제어할 수 있는 인터페이스를 제공하여 개발자가 브라우저마다 개별적으로 드라이버를 다룰 필요 없이 동일한 코드를 사용할 수 있게 합니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; Selenium의 WebDriver API는 이 추상화 개념을 기반으로 설계되었으며, ChromeDriver, GeckoDriver(Firefox), EdgeDriver 등을 동일한 방식으로 제어할 수 있습니다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이를 통해 각 브라우저마다 다른 드라이버를 선언하지 않고도 객체지향 프로그래밍의 추상화를 활용해 일관성 있게 제어할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q21. 웹 컴포넌트의 경로를 가져오는 방법 중에 XPath와 CSS Selector가 있습니다. 이 둘의 차이점을 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A21. XPath는 XML 문서에서 노드를 찾기 위한 경로 표현식으로, HTML 요소의 계층적 구조를 탐색할 때(부모-자식) 관계 유리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;CSS Selector는 HTML 요소를 스타일링하거나 선택하기 위한 간결한 구문으로, 속성과 클래스 기반 선택이 유리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q22. WebDriver 객체의 findElement 메서드를 이용하여 웹 컴포넌트를 가져왔습니다. 이때 findElement 메서드의 반환값은 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A22. findElement 메서드의 반환값은 WebElement 객체입니다. WebElement는 HTML 요소를 나타내며, 해당 요소의 속성이나 동작을 제어할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;출처 &amp;amp; 추가로 알아보면 좋은것&lt;/span&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;빌드 도구 비교&lt;/b&gt;&lt;br /&gt;Maven과 Gradle의 차이 및 장단점.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://gradle.org/&quot;&gt;&lt;span&gt;Gradle&lt;/span&gt;&lt;span&gt; 공식&lt;/span&gt;&lt;span&gt; 문서&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://maven.apache.org/&quot;&gt;&lt;span&gt;Maven&lt;/span&gt;&lt;span&gt; 공식&lt;/span&gt;&lt;span&gt; 문서&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JSON 데이터 처리&lt;/b&gt;&lt;br /&gt;JSON 관련 라이브러리의 사용법과 성능 비교(GSON, Jackson).
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.json.org/&quot;&gt;&lt;span&gt;JSON&lt;/span&gt;&lt;span&gt; 포맷&lt;/span&gt;&lt;span&gt; 설명&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Selenium 활용 사례&lt;/b&gt;&lt;br /&gt;Selenium의 다양한 WebDriver 설정 및 테스트 자동화 예제.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a&gt;&lt;span&gt;Selenium&lt;/span&gt;&lt;span&gt; 공식&lt;/span&gt;&lt;span&gt; 문서&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HTTP 프로토콜 심화&lt;/b&gt;&lt;br /&gt;GET과 POST의 멱등성, HTTP 메서드의 특징과 사용 사례.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a&gt;&lt;span&gt;RFC&lt;/span&gt;&lt;span&gt; 2616&lt;/span&gt;&lt;span&gt; (HTTP&lt;/span&gt;&lt;span&gt; 1.1)&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;XPath와 CSS Selector&lt;/b&gt;&lt;br /&gt;성능 비교와 실제 사례에 따른 사용 가이드.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a&gt;&lt;span&gt;XPath&lt;/span&gt;&lt;span&gt; 튜토리얼&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a&gt;&lt;span&gt;CSS&lt;/span&gt;&lt;span&gt; Selector&lt;/span&gt;&lt;span&gt; 문법&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>Java</category>
      <category>면접 대비</category>
      <category>자바 기초</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/222</guid>
      <comments>https://nstgic3.tistory.com/entry/Java-%EC%A1%B0%EA%B0%81%EB%AA%A8%EC%9D%8C-2#entry222comment</comments>
      <pubDate>Fri, 17 Jan 2025 17:15:37 +0900</pubDate>
    </item>
    <item>
      <title>Java 조각모음 [1]</title>
      <link>https://nstgic3.tistory.com/entry/Java-Basic-1</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;*는 심화적인 내용이므로 처음 접한다면 넘어가도 좋다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이번 포스팅에서 나오는 주요 키워드&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;final 키워드&lt;/li&gt;
&lt;li&gt;static 키워드&lt;/li&gt;
&lt;li&gt;final과 static의 조합&lt;/li&gt;
&lt;li&gt;예약어와 변수명&lt;/li&gt;
&lt;li&gt;snake case&lt;/li&gt;
&lt;li&gt;long 타입&lt;/li&gt;
&lt;li&gt;String 클래스와 불변성&lt;/li&gt;
&lt;li&gt;double 타입과 계산 정확도&lt;/li&gt;
&lt;li&gt;객체 생성 및 메모리 할당&lt;/li&gt;
&lt;li&gt;Object 클래스 주요 메서드&lt;/li&gt;
&lt;li&gt;기본 타입 &amp;amp; 참조 타입&lt;/li&gt;
&lt;li&gt;지역 변수&lt;/li&gt;
&lt;li&gt;new 키워드와 객체 생성&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;본문&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q1. 왜 변수를 선언할 때 final을 쓰는가?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A1. final 키워드는 변수에 최초로 값을 할당한 이후에 다른 값을 할당할 수 없게 만든다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이는 변수의 값이 변하지 않는다는 것을 명시적으로 표현하기 위함이다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q2. 변수를 선언할 때 static을 같이 쓰기도 한다. 왜 그런가?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A2. static 키워드는 클래스 변수를 선언할 때 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 클래스 변수는 클래스가 로딩될 때 생성되어 프로그램이 종료될 때까지 유지된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;따라서 클래스 변수는 프로그램 전체에서 공유되는 변수이다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q3. final과 static을 같이 쓰는 경우의 장점은 무엇인가?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A3. final과 static을 같이 쓰면 프로그램 전체에서 공유되는 상수를 선언할 수 있다. final은 값 변경을 방지하고, static은 메모리를 효율적으로 사용하도록 한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;추후에 안정성이나 재사용성을 늘려준다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;둘이 같이 쓴 변수 = 이 클래스 뿐만 아니라 다른 곳에서도 사용되는구나라고 팀원들이 명시적으로 이해할수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q4. 예약어를 변수명으로 사용 시 오류가 발생하는 이유와 오류 메시지는 무엇인가?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A4. 예약어를 변수명으로 사용하면 컴파일러가 예약어를 변수명으로 사용하는 것을 인식하지 못하고 오류를 발생시킨다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 오류 메세지는 &quot;Syntax error on token '예약어', invalid VariableDeclaratorId&quot;이다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q5. 왜 DB에서는 snake case를 사용하는가?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A5. snake case는 단어 사이에 언더바(_)를 사용하여 변수명을 작성하는 방식이다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DB에서는 snake case를 사용하는 이유는 일반적으로 DBMS에서 대소문자를 구분하지 않기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 이는 성능과 관습적인 이유에서 사용된다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q6. long 형은 너무 범위가 크지 않나요? 실제로 언제 사용하나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A6.&lt;br /&gt;1. 은행/결제 시스템이나 게임 서버에서 큰 수를 다룰 때 사용된다.&lt;br /&gt;*2. 스프링 JPA에서 엔티티의 ID는 일반적으로 DB의 Primary Key와 매핑되며, BIGINT와 호환성을 고려해 long을 사용한다.&lt;br /&gt;3. int로 선언 후 long으로 변경해야 하는 상황을 예방하기 위해 넉넉하게 long으로 선언하는 것이 유리하다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q7. String 내부를 보면 char 배열로 구성되어 있는데 왜 char 배열로 구성되어 있나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0GOAH/btsLPxxXnXZ/BCKsXO1hquh1FjHMSUgBw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0GOAH/btsLPxxXnXZ/BCKsXO1hquh1FjHMSUgBw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0GOAH/btsLPxxXnXZ/BCKsXO1hquh1FjHMSUgBw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0GOAH%2FbtsLPxxXnXZ%2FBCKsXO1hquh1FjHMSUgBw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;724&quot; height=&quot;470&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;br /&gt;&lt;br /&gt;A7. String은 불변(immutable) 클래스이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; char 배열은 불변이 아니므로 String은 안전한 데이터를 제공하기 위해 char 배열을 복사하여 내부적으로 사용한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;String 객체는 toCharArray() 라는&amp;nbsp; 메서드 또한 내장 하고 있다. 추후에 알고리즘 풀이시에도 자주 응용된다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;778&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kDz3C/btsLSz9PdGu/eOFcQpDN5epT83A8CX0B70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kDz3C/btsLSz9PdGu/eOFcQpDN5epT83A8CX0B70/img.png&quot; data-alt=&quot;String.java :4102&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kDz3C/btsLSz9PdGu/eOFcQpDN5epT83A8CX0B70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkDz3C%2FbtsLSz9PdGu%2FeOFcQpDN5epT83A8CX0B70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1670&quot; height=&quot;778&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;778&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;String.java :4102&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q8. String은 왜 불변 클래스로 만들었나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A8.&lt;br /&gt;1. 문자열 풀(String Pool)을 통해 메모리를 절약한다.&lt;br /&gt;2. 멀티스레드 환경에서 안전성을 보장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. 보안성을 제공한다.&lt;br /&gt;&lt;br /&gt;*&lt;a href=&quot;https://deveric.tistory.com/123&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://deveric.tistory.com/123&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q9. double 타입으로 변수를 선언하고 0.1 + 0.2를 출력하면 왜 0.30000000000000004가 나오나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A9. double은 2진수로 표현되기 때문에 10진수로 정확하게 표현할 수 없는 숫자가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이를 &lt;b&gt;이진 부동소수점 연산의 부정확성 문제&lt;/b&gt;라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예를 들어, 0.1은 2진수로 정확히 나타낼 수 없으므로 미세한 오차가 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q10. 그럼 어떻게 해결하나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A10. BigDecimal 클래스를 사용하거나, 계산 중 정수를 사용하여(10진수를 흉내) 오차를 줄일 수 있다. &lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예: &lt;code&gt;double result = (0.1 * 10 + 0.2 * 10) / 10;&lt;/code&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;왜 BigDecimal 은 가능할까?&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;409&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5THOF/btsLO9YzBDR/D5msjotcDQZaJzwkuTaRcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5THOF/btsLO9YzBDR/D5msjotcDQZaJzwkuTaRcK/img.png&quot; data-alt=&quot;BigDecimal.java&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5THOF/btsLO9YzBDR/D5msjotcDQZaJzwkuTaRcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5THOF%2FbtsLO9YzBDR%2FD5msjotcDQZaJzwkuTaRcK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;924&quot; height=&quot;409&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;409&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;BigDecimal.java&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;intVal&lt;/b&gt;: BigInteger 형태로 10진수 숫자를 표현&lt;/li&gt;
&lt;li&gt;&lt;b&gt;scale&lt;/b&gt;: 소수점의 위치를 나타내는 정수로, 10진수 기준으로 사용,&lt;br /&gt;예를 들어, 123.45는 intVal = 12345와 scale = 2로 표현&lt;/li&gt;
&lt;li&gt;&lt;b&gt;precision&lt;/b&gt;: 전체 자릿수를 나타낸다. 성능 최적화를 위해 캐시로 사용(transient 로 Serialize 제외)&lt;/li&gt;
&lt;/ul&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;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;* Q11. new를 통해 객체를 생성하면 어떤 일이 일어나나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A11. new 키워드를 사용하면 Heap 메모리에 객체를 생성하고, 생성자가 호출되어 객체를 초기화한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;생성된 객체의 참조값은 참조 변수에 저장된다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q12. 객체를 printf로 출력하면 나오는 문자열은 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ebdDL6/btsLQH7pCpk/ZCvEYbcMJlZrqnHNP1huuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ebdDL6/btsLQH7pCpk/ZCvEYbcMJlZrqnHNP1huuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ebdDL6/btsLQH7pCpk/ZCvEYbcMJlZrqnHNP1huuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FebdDL6%2FbtsLQH7pCpk%2FZCvEYbcMJlZrqnHNP1huuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;961&quot; height=&quot;476&quot; data-origin-width=&quot;961&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A12. 객체의 &lt;code&gt;toString()&lt;/code&gt; 메서드가 호출된다. 기본적으로 클래스 이름과 해시코드를 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q13. toString() 메서드는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1217&quot; data-origin-height=&quot;314&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBnAF3/btsLPAg93Vl/51996znvtiXnQUUKdL7cp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBnAF3/btsLPAg93Vl/51996znvtiXnQUUKdL7cp1/img.png&quot; data-alt=&quot;https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#toString--&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBnAF3/btsLPAg93Vl/51996znvtiXnQUUKdL7cp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBnAF3%2FbtsLPAg93Vl%2F51996znvtiXnQUUKdL7cp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1217&quot; height=&quot;314&quot; data-origin-width=&quot;1217&quot; data-origin-height=&quot;314&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#toString--&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A13. toString() 메서드는 객체의 문자열 표현을 반환하며, Object 클래스에 정의되어 있다. 오버라이딩을 통해 사용자 정의 문자열을 반환할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q14. toString() 이외에도 Object 클래스에 있는 필수 메서드는 무엇이 있나요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1250&quot; data-origin-height=&quot;652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OwRjA/btsLQqLB9iH/ceBPQ2CQOyt48bMYrlVHfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OwRjA/btsLQqLB9iH/ceBPQ2CQOyt48bMYrlVHfK/img.png&quot; data-alt=&quot;https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OwRjA/btsLQqLB9iH/ceBPQ2CQOyt48bMYrlVHfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOwRjA%2FbtsLQqLB9iH%2FceBPQ2CQOyt48bMYrlVHfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1250&quot; height=&quot;652&quot; data-origin-width=&quot;1250&quot; data-origin-height=&quot;652&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A14. 주요 메서드: &lt;br /&gt;1. equals() - 객체 비교&lt;br /&gt;2. hashCode() - 해시코드 반환&lt;br /&gt;3. clone() - 객체 복제&lt;br /&gt;4. finalize() - 객체 소멸 시 호출&lt;br /&gt;5. notify(), notifyAll(), wait() - 스레드 관리&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q15. 객체를 비교할 때 equals()를 사용하는 이유는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A15. equals()는 객체의 동등성을 비교한다. 오버라이딩하여 원하는 비교 조건을 정의할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q16. hashCode()를 사용하는 이유는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;div class=&quot;moreless-content\&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A16. hashCode()는 객체의 고유 해시코드를 반환하며, 해시 기반 컬렉션 (HashMap, HashSet)에서 객체를 효율적으로 관리하기 위해 사용된다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q17. 기본 타입과 참조 타입에서 변수 변경 시에 결과값이 다르게 나오는 이유는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A17. 기본 타입은 변수에 값을 저장하고 참조 타입은 변수에 객체의 주소를 저장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 기본 타입은 변수에 값을 저장하기 때문에 변수의 값이 변경되어도 다른 변수에 영향을 주지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;참조 타입은 변수에 객체의 주소를 저장하기 때문에 변수의 값이 변경되면 다른 변수에 영향을 줄 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q18. 기본 타입의 변수가 메서드 내에서 변화하면 외부에서도 변화하지 않는 이유는 특성과 함께 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A18. 기본 타입은 변수에 값을 저장하기 때문에 변수의 값이 변경되어도 다른 변수에 영향을 주지 않는다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기본 타입은 스택(stack) 메모리에 저장된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;*스택 메모리는 메서드가 호출될 때 생성되고 메서드가 종료될 때 소멸된다. 따라서 메서드 내에서 변수의 값이 변경되어도 외부에서는 영향을 받지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;**&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q19. 참조 타입의 변수가 메서드 내에서 변화하면 외부에서도 변화하는 이유는 특성과 함께 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A19. 참조 타입은 변수에 객체의 주소를 저장하기 때문에 변수의 값이 변경되면 다른 변수에 영향을 줄 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;참조 타입은 힙(heap) 메모리에 저장된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;*힙 메모리는 객체가 생성될 때 생성되고 객체가 소멸될 때 소멸된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 따라서 메서드 내에서 변수의 값이 변경되면 외부에서도 영향을 받을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q20. 객체를 생성할 때 new 키워드를 사용하는 이유는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1123&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R7WwW/btsLOYW8UVI/e7qzcm0pk8grgav6KFGW0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R7WwW/btsLOYW8UVI/e7qzcm0pk8grgav6KFGW0k/img.png&quot; data-alt=&quot;https://docs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R7WwW/btsLOYW8UVI/e7qzcm0pk8grgav6KFGW0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR7WwW%2FbtsLOYW8UVI%2Fe7qzcm0pk8grgav6KFGW0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1123&quot; height=&quot;309&quot; data-origin-width=&quot;1123&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://docs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html&lt;/figcaption&gt;
&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A20. new 키워드를 사용하여 객체를 생성하면 메모리(heap)에 객체를 생성하고 객체의 주소를 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;객체의 생성자가 호출되어 객체의 초기화를 수행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;생성된 객체의 주소를 참조변수에 저장하여 객체를 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q21. 객체를 생성할 때 클래스를 사용하는 이유는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A21. 클래스는 객체를 생성하기 위한 틀이다. 클래스를 사용하여 객체를 생성하면 객체의 초기화를 수행할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q22. 묵시적 형변환이 가능한 이유가 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A22. 묵시적 형변환은 작은 크기의 데이터 타입에서 큰 크기의 데이터 타입으로 자동으로 형변환하는 것을 말한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;묵시적 형변환은 데이터 손실이 발생하지 않기 때문에 자동으로 형변환할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q23. 명시적 형변환이 가능한 이유가 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A23. 명시적 형변환은 큰 크기의 데이터 타입에서 작은 크기의 데이터 타입으로 형변환하는 것을 말한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;명시적 형변환은 데이터 손실이 발생할 수 있기 때문에 명시적으로 형변환해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q24. Scanner 클래스를 사용할 때 close()를 사용하는 이유는 무엇인가요?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A24. Scanner 클래스는 사용이 끝나면 close() 메서드를 호출하여 리소스를 반환해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;*close() 메서드를 호출하지 않으면 리소스 누수가 발생할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q25. Scanner 클래스가 편리한 이유는 무엇인가요? 예외처리에 관련해서 답변해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A25. Scanner 클래스는 표준 입력 스트림(System.in)에서 데이터를 읽을 수 있는 클래스이다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Scanner 클래스는 다양한 데이터 타입을 읽을 수 있어서 편리하다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 예외처리를 자동으로 처리하기 때문에 사용자가 예외처리를 직접 작성할 필요가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q26. switch-case 문과 if-else 문의 성능상 차이를 특성을 통해 설명해주세요. (조건문을 계산하는 시점을 고려해서)&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A26. switch-case 문은 조건식을 계산한 결과에 따라 case 문을 실행한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;switch-case 문은 조건식을 한 번만 계산하기 때문에 if-else 문보다 성능이 좋다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;if-else 문은 조건식을 계산할 때마다 조건식을 계산하기 때문에 switch-case 문보다 성능이 떨어진다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Q27. for 문의 동작 순서에 대해서 설명해주세요.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A27. for 문의 동작 순서는 다음과 같다: &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 초기화식 실행 &amp;rarr; 2. 조건식 평가 &amp;rarr; 3. 블록 실행 &amp;rarr; 4. 증감식 실행. 조건식이 false가 될 때까지 이 과정을 반복한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;출처 &amp;amp; 추가로 알아보면 좋은 것&lt;/span&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;b&gt;Effective Java&lt;/b&gt; (Joshua Bloch): Java 개발의 모범 사례.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Java Language Specification&lt;/b&gt;: Java 문법 및 동작 원리 공식 문서.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Java Memory Model and Garbage Collection&lt;/b&gt;: 메모리 구조 및 GC 동작 방식.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Java Type Casting Documentation&lt;/b&gt;: 형변환 공식 자료.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Oracle Java Tutorials&lt;/b&gt;: Java 입출력 및 클래스 설계.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Java Performance Tuning&lt;/b&gt;: 조건문과 반복문 최적화.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Head First Java&lt;/b&gt;: Java 객체지향 및 기본 문법 이해.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</description>
      <category>Java</category>
      <category>자바 기초</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/221</guid>
      <comments>https://nstgic3.tistory.com/entry/Java-Basic-1#entry221comment</comments>
      <pubDate>Thu, 16 Jan 2025 13:02:04 +0900</pubDate>
    </item>
    <item>
      <title>인턴 간단후기 + 최근 근황</title>
      <link>https://nstgic3.tistory.com/entry/%EC%9D%B8%ED%84%B4-%EA%B0%84%EB%8B%A8%ED%9B%84%EA%B8%B0-%EC%B5%9C%EA%B7%BC-%EA%B7%BC%ED%99%A9</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-13-12-04-31.jpeg&quot; data-origin-width=&quot;1382&quot; data-origin-height=&quot;1036&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMG5hS/btsLh3QEcIY/4lJc9dPmrxHcPVEKiU8Sfk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMG5hS/btsLh3QEcIY/4lJc9dPmrxHcPVEKiU8Sfk/img.jpg&quot; data-alt=&quot;한달간 ktx 출퇴근을 하며 매일 보던 풍경 , 오송역&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMG5hS/btsLh3QEcIY/4lJc9dPmrxHcPVEKiU8Sfk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMG5hS%2FbtsLh3QEcIY%2F4lJc9dPmrxHcPVEKiU8Sfk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1382&quot; height=&quot;1036&quot; data-filename=&quot;KakaoTalk_Photo_2024-12-13-12-04-31.jpeg&quot; data-origin-width=&quot;1382&quot; data-origin-height=&quot;1036&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;한달간 ktx 출퇴근을 하며 매일 보던 풍경 , 오송역&lt;/figcaption&gt;
&lt;/figure&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;br /&gt;&lt;br /&gt;백엔드 개발자로 지원을 했지만 연말이었고, 예상보다 많은 회사들이 기업에 데모 프로그램을 요청하거나 보안 검사를 실시하는 바람에 여러 분야의 일을 해보기도 하였다. 보안 규정에 따라 허락을 받고 회사명과 디테일한 내용을 제외한 결과를 12월에 천천히 포스팅해보려한다.&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;0. 기존 웹 서버 취약점 분석 및 보안 강화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 웹사이트 리팩토링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- db 구조 최적화, 엔티티 최적화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- deploy 는 하지못함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 박람회 및 학회 등에 사용할 데모 신청 api&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 실시간 데모신청 현황 발송 api (슬랙, 메일)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 웹사이트 i18n 리팩토링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 기존 웹사이트 백/프론트 배포 가이드 제작&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. Nginx 활용한 보안 강화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. Nginx 활용한 웹사이트 정적파일 캐싱&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. DB 서버(mySQL)취약점 분석 및 보안 강화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. Terraform+Ansible 활용하여 웹사이트 배포 완전 자동화&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번까지가 내게 요청해주셨던 일이었고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3~7 번은 주어진 일을 맡아서 하는 과정에서 취약점이나 성능 최적화를 할수 있어 보이는 점이 보여서 진행을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8 번은 끝나갈 무렵 인수인계나 추가 UT 로 인해서 시간적 여유가 생겼었는데 올해 2월쯤인가 CTO 분께서 작업선언은 해두었지만 우선순위가 낮아 미루어 두었던 일을 진행해보았다.&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;&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;최근 근황으로는 ssafy 면접을 보러갔다왔다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 내 지인이거나 블로그에 올라온 또 다른 글을 보신 분들이라면 ssafy에 왜 지원을 했나 궁금하신 분도 계실텐데 최근 아버지가 타지로 발령나는 바람에 어쩌다 혼자 살게되었다ㅋㅋ 아무래도 규칙적인 무언가가 있으면 좋았을것 같고, 금융계열로의 취직도 희망하기에 지원을 해보게 되었다. 위치는 대전으로 버스로 30분만 가면 될듯하다. (밥이 그렇게 맛있다던데,,ㅎㅎ)&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;이외에는 언어도 조금 공부하고 aws 자격증 또한 준비중에 있다. 사실 12월에 신주쿠쪽의 회사 면접도 있는데 어떻게 해야하나 고민이 많다.&lt;/p&gt;</description>
      <category>Intern</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/220</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%9D%B8%ED%84%B4-%EA%B0%84%EB%8B%A8%ED%9B%84%EA%B8%B0-%EC%B5%9C%EA%B7%BC-%EA%B7%BC%ED%99%A9#entry220comment</comments>
      <pubDate>Fri, 13 Dec 2024 12:05:34 +0900</pubDate>
    </item>
    <item>
      <title>스타트업 인턴 지원 및 합격기</title>
      <link>https://nstgic3.tistory.com/entry/%EC%8A%A4%ED%83%80%ED%8A%B8%EC%97%85-%EC%9D%B8%ED%84%B4-%EC%A7%80%EC%9B%90-%EB%B0%8F-%ED%95%A9%EA%B2%A9%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 간단한 채용 프로세스와 1시간 가량의 커피챗을 통해 스타트업의 백엔드 인턴으로 합류하게 되었다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;지원 및 커피챗 후기, 지원한 이유 등&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 합류한 회사는 B2B 서비스를 운영하며 NextJS 기반의 아키텍처를 사용하고 있다.&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;경험상 주로 스프링(Spring)으로 트래픽 처리와 트랜잭션 정합성에 중점을 두고 개발해왔는데, 이번 회사는 일종의 전사 프로그램을 통해 다양한 고객사의 요구사항에 맞춰 솔루션을 조정해나가는 방식으로 서비스를 제공하고 있었 다.(트래픽보다는 고객의 요구에 유연하게 대응하는 구조와 프로세스에 중점을 두는 방향)&lt;br /&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;커피챗에서는 CTO 분이 이러한 특성을 고려해서 DDD를 일부 활용하여 서비스가 확장되거나 고객 요구가 변경에 유연하게 대응  가능하게 구현중에 있다고 하셨는데 이를 먼저 말씀하시기전에 캐치를 해서 그 점이 저를 좋게 봐주시지 않았을까 싶은 생각도 듭니다ㅋㅋ&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;합격 이후 준비 과정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합격 연락을 받은 후, 튜토리얼이나 쿡북등을 활용하여 NextJS 프레임워크에 대한 기초 지식을 쌓고있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블로그에는 새로운 기술 스택에 적응하고 업무 중 느낀 점들을 정리하여, 향후 스타트업 환경에서의 도메인 설계 및 적응 과정을 기록할 계획이다.&lt;/p&gt;</description>
      <category>Intern</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/219</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%8A%A4%ED%83%80%ED%8A%B8%EC%97%85-%EC%9D%B8%ED%84%B4-%EC%A7%80%EC%9B%90-%EB%B0%8F-%ED%95%A9%EA%B2%A9%EA%B8%B0#entry219comment</comments>
      <pubDate>Fri, 1 Nov 2024 11:33:37 +0900</pubDate>
    </item>
    <item>
      <title>Dayner에서 구매 이력을 관리하는 방법 [1] (feat: 개인정보보호법, 원장 데이터)</title>
      <link>https://nstgic3.tistory.com/entry/Dayner%EC%97%90%EC%84%9C-%EA%B5%AC%EB%A7%A4-%EC%9D%B4%EB%A0%A5%EC%9D%84-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-feat-%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4%EB%B3%B4%ED%98%B8%EB%B2%95-%EC%9B%90%EC%9E%A5-%EB%8D%B0%EC%9D%B4%ED%84%B0</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt; Dayner에서는 기프트카드와 쿠폰, 앞으로 추가될 포장 주문과 관련된 결제 데이터를 관리하기 위해 구매 이력 관리 방식을 철저히 설계하고 있다.&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;&lt;b&gt;전자상거래 등에서의 소비자보호에 관한 법률 시행령&amp;nbsp;( 약칭: 전자상거래법 시행령&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;/p&gt;
&lt;figure id=&quot;og_1725076416827&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;국가법령정보센터 | 연계정보&quot; data-og-description=&quot;전자상거래 등에서의 소비자보호에 관한 법률 시행령 [시행 2024. 3. 22.] [대통령령 제34097호, 2024. 1. 2., 일부개정]&quot; data-og-host=&quot;www.law.go.kr&quot; data-og-source-url=&quot;https://www.law.go.kr/LSW//lsLinkCommonInfo.do?lspttninfSeq=63460&amp;amp;chrClsCd=010202&quot; data-og-url=&quot;https://www.law.go.kr/LSW//lsLinkCommonInfo.do?chrClsCd=010202&amp;amp;lspttninfSeq=63460&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.law.go.kr/LSW//lsLinkCommonInfo.do?lspttninfSeq=63460&amp;amp;chrClsCd=010202&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.law.go.kr/LSW//lsLinkCommonInfo.do?lspttninfSeq=63460&amp;amp;chrClsCd=010202&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;국가법령정보센터 | 연계정보&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;전자상거래 등에서의 소비자보호에 관한 법률 시행령 [시행 2024. 3. 22.] [대통령령 제34097호, 2024. 1. 2., 일부개정]&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.law.go.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;이번 포스팅에서는 기능적 요구와 원장/거래 데이터를 따로 관리하는 전략을 왜 선정하게 되었는지 알아보자!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개인정보처리방침 관점의 기능적 설계 분석&lt;/span&gt;&lt;/h3&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1166&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z2WhF/btsJnWZWDkL/LWtKrG7jHsiEkqHyOsWTq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z2WhF/btsJnWZWDkL/LWtKrG7jHsiEkqHyOsWTq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z2WhF/btsJnWZWDkL/LWtKrG7jHsiEkqHyOsWTq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ2WhF%2FbtsJnWZWDkL%2FLWtKrG7jHsiEkqHyOsWTq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1166&quot; height=&quot;464&quot; data-origin-width=&quot;1166&quot; data-origin-height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;/figure&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;클라이언트(Dayner 사업주)의 법률대리인에 의해 요청 받은 기능에 의하면 제 6조에 의거하여 모든 회원이 웹사이트 내에 존재하는 서비스를 통해 거래한 유/무형의 대금 결제에 대해서는 빠짐없이 기록을 해야한다고 한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 열람-보존 방법을 확인해보면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgKSWE/btsJnYKdSB8/pAPktZdecv4PN5XryC2Wjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgKSWE/btsJnYKdSB8/pAPktZdecv4PN5XryC2Wjk/img.png&quot; data-alt=&quot;6조 세부조항 1항&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgKSWE/btsJnYKdSB8/pAPktZdecv4PN5XryC2Wjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgKSWE%2FbtsJnYKdSB8%2FpAPktZdecv4PN5XryC2Wjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1106&quot; height=&quot;160&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;6조 세부조항 1항&lt;/figcaption&gt;
&lt;/figure&gt;
&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;b&gt;&amp;nbsp;1. 결제 내역을 거래발생일과 함께 데이터베이스에 저장/보존 해야한다.&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;앗,, 그리고 당사자(소비자)가 요청하면 데이터를 제공해줘야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;따로 저작물이 없기 때문에 따로 문서화도 할수 있어야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1118&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ekgRqq/btsJmKsHcHE/JIvs1s3r4r3I1S2iVykFmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ekgRqq/btsJmKsHcHE/JIvs1s3r4r3I1S2iVykFmk/img.png&quot; data-alt=&quot;6조 세부조항 2항&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ekgRqq/btsJmKsHcHE/JIvs1s3r4r3I1S2iVykFmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FekgRqq%2FbtsJmKsHcHE%2FJIvs1s3r4r3I1S2iVykFmk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1118&quot; height=&quot;212&quot; data-origin-width=&quot;1118&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;6조 세부조항 2항&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 결제 내역을 회원 별로 조회 할수도 있어야한다.&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;개인정보 이용동의 철회 시에는 별도 보존을 해줘야한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AtjLg/btsJlJO4ggA/WDBOJIdDjcdD3hMIWArJnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AtjLg/btsJlJO4ggA/WDBOJIdDjcdD3hMIWArJnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AtjLg/btsJlJO4ggA/WDBOJIdDjcdD3hMIWArJnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAtjLg%2FbtsJlJO4ggA%2FWDBOJIdDjcdD3hMIWArJnK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1122&quot; height=&quot;154&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;154&quot;/&gt;&lt;/span&gt;&lt;/figure&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;3. 회원의 회원 가입 여부(개인정보 동의 기준) 에 따라서 데이터를 분리하여 관리하여야 한다.&lt;/b&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Dayner의 데이터 관리 전략: 원장 테이블 개념의 적용&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;발생되는 데이터를 관리/저장하는 전략으로 전통적인 금융 원장 테이블의 개념을 차용하였는데 자문에 따르면 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;원장 테이블은 중요한 정보를 신뢰성 있게 보관하고, &lt;b&gt;필요 시 언제든지 참고할 수 있는 기준이 되는 테이블&lt;/b&gt;&lt;/span&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;효율성&lt;/b&gt;&lt;br /&gt;PaymentArchive로 데이터를 이동함으로써, 결제 내역 테이블의 크기를 관리하고 성능을 최적화할 수 있다.&lt;br /&gt;특히 &lt;b&gt;결제수단-결제 내역 형태의 테이블의 경우에는 join이 발생하여 조회시 성능 이슈가 발생&lt;/b&gt; 하는데, join 연산이 어느정도 &lt;b&gt;비정규화로 인해 해소&lt;/b&gt; 되기 때문에 효율적이다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;안정성&lt;/b&gt;&lt;br /&gt;어느정도의 중복을 허용하는 방식으로 인해서 저장비용이 조금 늘게 되겠지만 데이터 보관 은 안정적으로 수행할 수 있다고 한다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;법적 요구사항 준수&lt;/b&gt;&lt;br /&gt;개인정보보호법과 금융상거래법에 따라 필요한 기간 동안 데이터를 보관하며, 데이터의 무결성을 유지하도록 설계되었다.&lt;br /&gt;결제 관련 데이터는 최소 5년간 저장되게 하였다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Dayner의 데이터 관리 방식:&amp;nbsp; 원장 데이터인 PaymentArchive와 결제 내역 테이블&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 위의 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;기능적 요청과 비기능적 특성&lt;/b&gt;에 의해서 결제 이력을 두 개의 테이블로 나누어 관리&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;결제 내역 테이블 (Transaction Table)&lt;/b&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;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결제 데이터 보관 테이블 (PaymentArchive)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일정 기간이 지나거나 발생된 데이터는 결제 내역 테이블에서 PaymentArchive로 이동하여 장기 보관된다(즉시 저장되지 않아도된다. 딜레이가 존재).&lt;/li&gt;
&lt;li&gt;과거 결제 내역을 안전하게 보관하며, 분쟁 발생 시 증거로 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;접근 빈도가 낮은 데이터를 저장하는 효율성을 최적화하는 방식으로 설계되었으며, 중복된 데이터의 일부도 허용하여 보관한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인프라: 보안적 측면&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1632&quot; data-origin-height=&quot;1632&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c89lpP/btsJl3mhz33/rqVOUFjXvRtNRKuw3TyXMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c89lpP/btsJl3mhz33/rqVOUFjXvRtNRKuw3TyXMk/img.png&quot; data-alt=&quot;화살표의 방향을 보면 이해가 쉽다!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c89lpP/btsJl3mhz33/rqVOUFjXvRtNRKuw3TyXMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc89lpP%2FbtsJl3mhz33%2FrqVOUFjXvRtNRKuw3TyXMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1632&quot; height=&quot;1632&quot; data-origin-width=&quot;1632&quot; data-origin-height=&quot;1632&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;화살표의 방향을 보면 이해가 쉽다!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;암호화&lt;/b&gt;&lt;br /&gt;결제 관련 데이터는 접근이 제한된 상황에서만 사용되며, 데이터베이스 서버는 Spring 애플리케이션이 실행되는 서버와 독립적으로 구성되어 있어 직접 조회가 불가능하다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;접근 통제&lt;/b&gt;&lt;br /&gt;PaymentArchive 테이블은 AWS IAM 최상위 권한을 가진 계정만이 접근할 수 있으며, 일반 개발자나 애플리케이션 어드민 계정도 접근이 불가능하도록 설정되어 있다.&lt;br /&gt;최소한의 권한으로만 접근할 수 있는 정책을 통해 데이터 보안을 강화해두었다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 파기&lt;/b&gt;&lt;br /&gt;보관 기간이 지난 결제 데이터는 매월 진행되는 정산 과정에서 삭제하거나 비식별화 처리하여, 개인정보보호법의 요구사항을 충족시키고 있다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;&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;현재의 결제 데이터는 약 5,000건에서 10,000건 정도가 존재하지만, 향후 결제 내역이 증가할 경우 적절한 인덱싱을 통해 추가적인 성능 향상을 기대할 수 있을것 같다.&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;다음 포스팅으로는 그래서 여러 결제 관련 엔티티에서 하나의 원장 데이터(PaymentArchive)로 어떻게 변환해서 저장을 하게 되었는지 코드와 함께 알아보자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Dayner 프로젝트</category>
      <category>개인정보보호법 데이터 저장</category>
      <category>개인정보보호법 데이터 파기</category>
      <category>고객 결제 데이터 관리</category>
      <category>원장 db</category>
      <category>원장 데이터</category>
      <category>웹사이트 운영</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/215</guid>
      <comments>https://nstgic3.tistory.com/entry/Dayner%EC%97%90%EC%84%9C-%EA%B5%AC%EB%A7%A4-%EC%9D%B4%EB%A0%A5%EC%9D%84-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-feat-%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4%EB%B3%B4%ED%98%B8%EB%B2%95-%EC%9B%90%EC%9E%A5-%EB%8D%B0%EC%9D%B4%ED%84%B0#entry215comment</comments>
      <pubDate>Sat, 31 Aug 2024 14:25:20 +0900</pubDate>
    </item>
    <item>
      <title>[책] 켄트백의 Tidy First?</title>
      <link>https://nstgic3.tistory.com/entry/%EC%B1%85-%EC%BC%84%ED%8A%B8%EB%B0%B1%EC%9D%98-Tidy-First</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_Photo_2024-08-30-14-31-18.jpeg&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;1165&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dP3aUm/btsJkUW7gxc/oXEppXGg1bRUYmw0xYC3I1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dP3aUm/btsJkUW7gxc/oXEppXGg1bRUYmw0xYC3I1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dP3aUm/btsJkUW7gxc/oXEppXGg1bRUYmw0xYC3I1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdP3aUm%2FbtsJkUW7gxc%2FoXEppXGg1bRUYmw0xYC3I1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;417&quot; height=&quot;488&quot; data-filename=&quot;edited_KakaoTalk_Photo_2024-08-30-14-31-18.jpeg&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;1165&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&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;&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;&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;/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;크게 3가지의 파트로 나뉘어있는데(나름의 비유를 하자면)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;첫번째 파트는 공구가 어떻게 작동되는지를 알려주고&lt;/li&gt;
&lt;li&gt;두번째는 어떻게 사용할지를 알려준다&lt;/li&gt;
&lt;li&gt;마지막에서는 자신이 얻었던 노하우를 알려주는데&amp;nbsp;&lt;/li&gt;
&lt;/ul&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명 정도를 소개 받아 진행하게 되었는데 잘될지는 모르겠지만 여기서 얻은 나와 코드와의 관계(피드백)를 잘 확인해가면서* 진행을 해보려고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*p69&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을 보면서 인상깊었거나, 나에게 필요하거나, 공감했던 부분과 함께 짧은 포스팅 마무리하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;04&lt;br /&gt;&lt;br /&gt;통로 인터페이스를 이용해보면 아이디어가 생길수 있다&lt;br /&gt;기존 인터페이스를 호출하는 새 인터페이스를 만들고 새 인터페이스를 이용해 구현해보자&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;06&lt;br /&gt;&lt;br /&gt;결합도 제거를 할수 있으면 해라 만약 비용이 크게 느껴진다면 일단 결합도가 있는 코드끼리 가까이 두어보자&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;07&lt;br /&gt;&lt;br /&gt;작은단계로 코드를 변경하고 변수 사용 직전에 초기화해보자&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;08,09&lt;br /&gt;&lt;br /&gt;인자가 긴 표현식의 경우나 하드코딩된 상수라면 적당한 변수 명을 만들어서 선언해놓고 사용하자&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;11&lt;br /&gt;&lt;br /&gt;비슷한 코드끼리 뭉쳐놓자&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;13&lt;br /&gt;&lt;br /&gt;코드가 여러개의 조각으로 이루어져 있다고 느껴질때 하나의 더미를 만들때까지 모아보자&lt;br /&gt;코드를 만들때 가장 큰 비용이 드는건 코드 작성보다는 읽고 이해하는거고 코드 정리를 하면 응집도를 높일수 있다.&lt;br /&gt;실질적으로 한번에 기억해야하는 코드 상세 내용을 줄여준다&lt;br /&gt;&lt;br /&gt;&amp;nbsp;힌트&lt;br /&gt;&amp;nbsp; &amp;nbsp; 길고 반복되는 인자 목록 반복되는 코드, 반복되는 조건문, helper 에 부적절한 이름, 공유가능하고 변경 가능해진 데이터 구조&lt;/blockquote&gt;</description>
      <category>Life</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/214</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%B1%85-%EC%BC%84%ED%8A%B8%EB%B0%B1%EC%9D%98-Tidy-First#entry214comment</comments>
      <pubDate>Fri, 30 Aug 2024 14:33:16 +0900</pubDate>
    </item>
    <item>
      <title>ArrayList/LinkedList 단순 순회시 For, Enhanced For , Iterator, ListIterator, Stream.forEach() 성능비교</title>
      <link>https://nstgic3.tistory.com/entry/DeepDive-For-For-each-Iterator-ListIterator-%EC%84%B1%EB%8A%A5%EB%B9%84%EA%B5%90</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;자바에서 컬렉션을 순회하는 방법은 다양하다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 대표적으로 for 루프, 향상된 for 루프(Enhanced For), Iterator, 그리고 ListIterator가 있다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 각각의 방법은 성능이나 코드의 간결성 측면에서 차이가 있는데 단순히 ~는 객체지향적이기에 사용하면 좋고, ~는 성능이 안좋아서 개선 버전이 있으니 무조건 향상된 for 문을 쓰자 를 넘어서 직접 운영중인 api 의 알고리즘을 대상으로 테스트를 해본다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 이번 글에서는 이러한 순회 방법들이 실제로 얼마나 성능 차이가 나는지, 어떤 상황에서 특정 방법을 사용하는 것이 유리한지에 대해 이야기를 해보려한다.&lt;/span&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;테스트 대상 특성&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;1. 리스트에 삽입/삭제가 이루어지지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;2. 순서대로 순회하면서 이전값,플래그 값과 비교를 통해서 연산을 수행한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 일정들이 특정 규칙에 따라 서로 연결되어 있는지 확인하고, 그에 따라 &quot;START&quot;, &quot;MIDDLE&quot;, &quot;END&quot;, &quot;SINGLE&quot;과 같은 타입을 할당한다.&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;figure id=&quot;og_1724652419571&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;영업시간 디자인 변경에 대응한 리팩토링 일지 [1] (feat: 연결된 일정 구현하기)&quot; data-og-description=&quot;개요Dayner 에는 매달 정기 휴무일을 비롯한 연중 휴일, 급한 일정으로 인한 운영시간 변경등을 등록할수 있는 기능을 가지고 있다.&amp;nbsp;최초의 디자인인 경우에는 대부분 매주 월요일에 있는 정기 &quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/Dayner-%EC%98%81%EC%97%85%EC%8B%9C%EA%B0%84-%EB%94%94%EC%9E%90%EC%9D%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81-%EC%9D%BC%EC%A7%80&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/Dayner-%EC%98%81%EC%97%85%EC%8B%9C%EA%B0%84-%EB%94%94%EC%9E%90%EC%9D%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81-%EC%9D%BC%EC%A7%80&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gFPlo/hyWSocqeIW/szXkpWM2jgagCIpuCUEY5k/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/nNIW8/hyWV5bfavu/UBKB0QLGYkKc8CQTKKSbdK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/K4MMw/hyWSf7EjiN/JTFPB2M31SlHJjigxXRHiK/img.png?width=1444&amp;amp;height=1230&amp;amp;face=0_0_1444_1230&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/Dayner-%EC%98%81%EC%97%85%EC%8B%9C%EA%B0%84-%EB%94%94%EC%9E%90%EC%9D%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81-%EC%9D%BC%EC%A7%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/Dayner-%EC%98%81%EC%97%85%EC%8B%9C%EA%B0%84-%EB%94%94%EC%9E%90%EC%9D%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81-%EC%9D%BC%EC%A7%80&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gFPlo/hyWSocqeIW/szXkpWM2jgagCIpuCUEY5k/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/nNIW8/hyWV5bfavu/UBKB0QLGYkKc8CQTKKSbdK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/K4MMw/hyWSf7EjiN/JTFPB2M31SlHJjigxXRHiK/img.png?width=1444&amp;amp;height=1230&amp;amp;face=0_0_1444_1230');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;영업시간 디자인 변경에 대응한 리팩토링 일지 [1] (feat: 연결된 일정 구현하기)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요Dayner 에는 매달 정기 휴무일을 비롯한 연중 휴일, 급한 일정으로 인한 운영시간 변경등을 등록할수 있는 기능을 가지고 있다.&amp;nbsp;최초의 디자인인 경우에는 대부분 매주 월요일에 있는 정기&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;이러한 작업은 일정의 연속성을 검사하는 논리를 포함하고 있기 때문에, 어떤 순회 방법이 더 효율적인지에 대한 테스트가 필요했다.&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;테스트 Case&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트는 ArrayList와 LinkedList 두 가지 리스트 구조를 사용하여 진행되었으며, 각 구조에 따라서 아래 다섯 가지 순회 방식을 비교했다&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;일반 for 루프&lt;/b&gt;: 인덱스를 사용하여 리스트의 각 요소에 직접 접근&lt;/li&gt;
&lt;li&gt;&lt;b&gt;향상된 for 루프(Enhanced For)&lt;/b&gt;: Iterator를 내부적으로 사용하지만, JIT 컴파일러에 의해 최적화 되어있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Iterator&lt;/b&gt;: 메서드를 통해 리스트를 순차적으로 탐색.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ListIterator&lt;/b&gt;: Iterator의 확장된 버전으로, 양방향 탐색 및 추가적인 메서드들을 제공.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Stream:&amp;nbsp;&lt;/b&gt;Stream.forEach()를 사용하였고, 플래그 값과 비교를 했기에 병렬 처리는 시도하지않았다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &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;작은 데이터셋과 큰 데이터셋 모두에서 이들 방법의 성능을 비교했으며, 리스트 구조에 따라 성능이 어떻게 달라지는지에 대한 실험도 함께 진행했다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터 생성 ;실제 유저의 사용 패턴을 기반&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. &lt;b&gt;날짜의 비연속적 증가&lt;/b&gt;&lt;/h4&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;이를 반영하기 위하여 각 일정의 날짜는 1일 또는 2일씩 랜덤하게 증가시킨다.&lt;br /&gt;유저가 일정 관리 시스템에서 연속되는, 연속되지 않는 일정을 추가하는 일반적인 사용 패턴을 따라했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1724684750797&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int daysToAdd = RANDOM.nextInt(2) + 1; // 1 또는 2일 증가
currentDate = currentDate.plusDays(daysToAdd);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. &lt;b&gt;유사한 유형(Type)과 설명(Description) 유지&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일정 관리 시스템에서  같은 유형의 일정을 연속해서 추가하는 경우 BlockType이 달라진다.&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;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;일정의 유형(Type)과 설명(Description)은 30% 확률로 이전 일정과 동일하게 설정을 하여 유저가 반복적인 일정을 추가하는 패턴을 따라했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724685669470&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (previousType != null &amp;amp;&amp;amp; previousDescription != null &amp;amp;&amp;amp; RANDOM.nextInt(100) &amp;lt; 30) {
    businessSchedules.add(new BusinessSchedule(previousType, previousDescription, currentDate));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. &lt;b&gt;새로운 유형(Type)과 설명(Description) 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 일정을 추가하는 경우도 고려해서 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;나머지 70%의 경우, 새로운 유형(Type)과 설명(Description)이 무작위로 생성하여 패턴을 따라했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724685700279&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;else {
    String newType = &quot;Type&quot; + RANDOM.nextInt(3); // Type0, Type1, Type2
    String newDescription = &quot;Description&quot; + RANDOM.nextInt(5); // Description0 ~ Description4
    businessSchedules.add(new BusinessSchedule(newType, newDescription, currentDate));

    // 새로운 값을 이전 값으로 업데이트
    previousType = newType;
    previousDescription = newDescription;
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uTCIi/btsJfa69UaG/xXlRD1ZgXL1pOetIvNr6K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uTCIi/btsJfa69UaG/xXlRD1ZgXL1pOetIvNr6K1/img.png&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;280&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.5896%; margin-right: 10px;&quot; data-widthpercent=&quot;50.17&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uTCIi/btsJfa69UaG/xXlRD1ZgXL1pOetIvNr6K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuTCIi%2FbtsJfa69UaG%2FxXlRD1ZgXL1pOetIvNr6K1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;770&quot; height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZhLVr/btsJhkGDASy/UmlCjk9Z1uoQuRkh6ChIpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZhLVr/btsJhkGDASy/UmlCjk9Z1uoQuRkh6ChIpK/img.png&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;290&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.2476%;&quot; data-widthpercent=&quot;49.83&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZhLVr/btsJhkGDASy/UmlCjk9Z1uoQuRkh6ChIpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZhLVr%2FbtsJhkGDASy%2FUmlCjk9Z1uoQuRkh6ChIpK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;792&quot; height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;매주 휴일이 있기에 Single 의 개수가 압도적으로 많다. 또한 Start-Mid-End 세트를 고려하면 단일 휴일 vs 연속 휴일의 비율이 약 1:5~ 정도인데&lt;br /&gt;&lt;br /&gt;이는 &lt;b&gt;1.5달에 한번씩 휴일이 있는것으로 적절한 튜닝&lt;/b&gt;이었다고 생각한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;5가지 순회 방식의 구현&lt;/span&gt;&lt;/h3&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;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1724687700409&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;performance_test/src/main/java/com/performance/test/iteratorVsForloop at main &amp;middot; ChoMinGi/performance_test&quot; data-og-description=&quot;성능 테스트 관련 블로그 포스팅에 올릴 코드 저장소. Contribute to ChoMinGi/performance_test development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ChoMinGi/performance_test/tree/main/src/main/java/com/performance/test/iteratorVsForloop&quot; data-og-url=&quot;https://github.com/ChoMinGi/performance_test/tree/main/src/main/java/com/performance/test/iteratorVsForloop&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eXSas/hyWSoKmxje/DMmXG5KtLyJFe9bQZOEVy0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/ChoMinGi/performance_test/tree/main/src/main/java/com/performance/test/iteratorVsForloop&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/ChoMinGi/performance_test/tree/main/src/main/java/com/performance/test/iteratorVsForloop&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eXSas/hyWSoKmxje/DMmXG5KtLyJFe9bQZOEVy0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;performance_test/src/main/java/com/performance/test/iteratorVsForloop at main &amp;middot; ChoMinGi/performance_test&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;성능 테스트 관련 블로그 포스팅에 올릴 코드 저장소. Contribute to ChoMinGi/performance_test development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;b&gt;Iterator를 사용하는 메서드&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;public List&amp;lt;BusinessScheduleWithBlockTypeDTO&amp;gt; createScheduleDTOsUsingIterator(List&amp;lt;BusinessSchedule&amp;gt; businessSchedules) {
    Iterator&amp;lt;BusinessSchedule&amp;gt; iterator = businessSchedules.iterator();

    while (iterator.hasNext()) {
        BusinessSchedule current = iterator.next();
        // 이전 요소와 비교하여 BlockType 결정 및 추가
        // 상태 업데이트
        previous = current;
    }
    // 마지막 요소 처리
    return scheduleDTOs;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Iterator를 사용하여 컬렉션의 요소를 순차적으로 탐색&lt;/li&gt;
&lt;li&gt;각 요소를 탐색하면서 &lt;b&gt;이전 요소와 비교&lt;/b&gt;하여 BlockType을 결정하고, DTO 리스트에 추가&lt;/li&gt;
&lt;/ul&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;h3 data-ke-size=&quot;size23&quot;&gt;2. &lt;b&gt;For 루프를 사용하는 메서드&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;background-color: #212121; color: #eeffff;&quot;&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;public List&amp;lt;BusinessScheduleWithBlockTypeDTO&amp;gt; createScheduleDTOsUsingForLoop(List&amp;lt;BusinessSchedule&amp;gt; businessSchedules) {
    for (int i = 1; i &amp;lt; businessSchedules.size(); i++) {
        BusinessSchedule next = businessSchedules.get(i);
        // 이전 요소와 비교하여 BlockType 결정 및 추가
        // 상태 업데이트
        current = next;
    }
    // 마지막 요소 처리
    return scheduleDTOs;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인덱스를 기반으로 한 일반 for 루프를 사용하여 요소를 탐색&lt;/li&gt;
&lt;li&gt;각 요소에 &lt;b&gt;인덱스를 통해 접근&lt;/b&gt;하며, 이전 요소와 비교하여 BlockType을 결정&lt;/li&gt;
&lt;/ul&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;h3 data-ke-size=&quot;size23&quot;&gt;3. &lt;b&gt;향상된 for 문을 사용하는 메서드&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;background-color: #212121; color: #eeffff;&quot;&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;public List&amp;lt;BusinessScheduleWithBlockTypeDTO&amp;gt; createScheduleDTOsUsingEnhancedForLoop(List&amp;lt;BusinessSchedule&amp;gt; businessSchedules) {
    for (BusinessSchedule current : businessSchedules) {
        // 이전 요소와 비교하여 BlockType 결정 및 추가
        // 상태 업데이트
        previous = current;
    }
    // 마지막 요소 처리
    return scheduleDTOs;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;향상된 for 문(Enhanced for loop)을 사용하여 컬렉션의 각 요소를 순차적으로 탐색&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이전 요소와 현재 요소를 비교&lt;/b&gt;하여 BlockType을 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. &lt;b&gt;ListIterator를 사용하는 메서드&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;background-color: #212121; color: #eeffff;&quot;&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;public List&amp;lt;BusinessScheduleWithBlockTypeDTO&amp;gt; createScheduleDTOsUsingListIterator(List&amp;lt;BusinessSchedule&amp;gt; businessSchedules) {
    ListIterator&amp;lt;BusinessSchedule&amp;gt; iterator = businessSchedules.listIterator();

    while (iterator.hasNext()) {
        BusinessSchedule current = iterator.next();
        // 이전 요소와 비교하여 BlockType 결정 및 추가
        // 상태 업데이트
        previous = current;
    }
    // 마지막 요소 처리
    return scheduleDTOs;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ListIterator를 사용하여 리스트의 요소를 순차적으로 탐색&lt;/li&gt;
&lt;li&gt;&amp;nbsp;순방향 탐색만 사용하고 있고 &lt;b&gt;이전 요소와 비교&lt;/b&gt;하여 BlockType을 결정&lt;/li&gt;
&lt;/ul&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;h3 data-ke-size=&quot;size23&quot;&gt;5. &lt;b&gt;Stream.forEach를 사용하는 메서드&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;background-color: #212121; color: #eeffff;&quot;&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public List&amp;lt;BusinessScheduleWithBlockTypeDTO&amp;gt; createScheduleDTOsUsingStream(List&amp;lt;BusinessSchedule&amp;gt; businessSchedules) {
    AtomicReference&amp;lt;BusinessSchedule&amp;gt; previousRef = new AtomicReference&amp;lt;&amp;gt;(null);
    AtomicReference&amp;lt;Boolean&amp;gt; isPreviousLinkedRef = new AtomicReference&amp;lt;&amp;gt;(false);

    businessSchedules.stream().forEach(current -&amp;gt; {
        BusinessSchedule previous = previousRef.get();
        // 이전 요소와 비교하여 BlockType 결정 및 추가
        // 상태 업데이트
        previousRef.set(current);
    });

    // 마지막 요소 처리
    return scheduleDTOs;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스트림 API의 forEach 메서드를 사용하여 컬렉션의 요소를 순차적으로 처리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상태(previous, isPreviousLinked)를 AtomicReference로 관리&lt;/b&gt;하여, 람다 표현식 내부에서 변경할 수 있도록 한다.&lt;/li&gt;
&lt;li&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;성능 테스트 준비&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Runtime 내의 gc() 메서드를 이용해 각 메서드 별로 사용하고 있는 메모리를 저장하고 StopWatch 를 이용해 각 로직별로 걸린 시간을 측정해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;div style=&quot;background-color: #212121; color: #eeffff;&quot;&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;// 시작 메모리 측정
long beforeMemory = runtime.totalMemory() - runtime.freeMemory();

stopWatch.start(taskName);
task.run();
stopWatch.stop();

// 끝난 후 메모리 측정
long afterMemory = runtime.totalMemory() - runtime.freeMemory();

long memoryUsed = afterMemory - beforeMemory;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;b&gt;시간 측정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;StopWatch 의 prettyPrint()를 이용하여 아주 간단하게 구현했다.&lt;/p&gt;
&lt;div style=&quot;background-color: #212121; color: #eeffff;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public void testPerformance() {
    List&amp;lt;BusinessSchedule&amp;gt; businessScheduleList = createTestData();

    StopWatch stopWatch = new StopWatch(&quot;Performance Testing&quot;);

    // ArrayList 테스트
    measureMemoryAndTime(&quot;ArrayList Iterator&quot;, () -&amp;gt; runTestWithIterator(new ArrayList&amp;lt;&amp;gt;(businessScheduleList)), stopWatch);
    measureMemoryAndTime(&quot;ArrayList For Loop&quot;, () -&amp;gt; runTestWithForLoop(new ArrayList&amp;lt;&amp;gt;(businessScheduleList)), stopWatch);
    measureMemoryAndTime(&quot;ArrayList Enhanced For Loop&quot;, () -&amp;gt; runTestWithEnhancedForLoop(new ArrayList&amp;lt;&amp;gt;(businessScheduleList)), stopWatch);
    measureMemoryAndTime(&quot;ArrayList ListIterator&quot;, () -&amp;gt; runTestWithListIterator(new ArrayList&amp;lt;&amp;gt;(businessScheduleList)), stopWatch);
    measureMemoryAndTime(&quot;ArrayList Stream&quot;, () -&amp;gt; runTestWithStream(new ArrayList&amp;lt;&amp;gt;(businessScheduleList)), stopWatch);

    // LinkedList 테스트
    measureMemoryAndTime(&quot;LinkedList Iterator&quot;, () -&amp;gt; runTestWithIterator(new LinkedList&amp;lt;&amp;gt;(businessScheduleList)), stopWatch);
    measureMemoryAndTime(&quot;LinkedList For Loop&quot;, () -&amp;gt; runTestWithForLoop(new LinkedList&amp;lt;&amp;gt;(businessScheduleList)), stopWatch);
    measureMemoryAndTime(&quot;LinkedList Enhanced For Loop&quot;, () -&amp;gt; runTestWithEnhancedForLoop(new LinkedList&amp;lt;&amp;gt;(businessScheduleList)), stopWatch);
    measureMemoryAndTime(&quot;LinkedList ListIterator&quot;, () -&amp;gt; runTestWithListIterator(new LinkedList&amp;lt;&amp;gt;(businessScheduleList)), stopWatch);
    measureMemoryAndTime(&quot;LinkedList Stream&quot;, () -&amp;gt; runTestWithStream(new LinkedList&amp;lt;&amp;gt;(businessScheduleList)), stopWatch);

    System.out.println(stopWatch.prettyPrint());

    calculateAndPrintBlockTypeDistribution(businessScheduleList);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트 결과&lt;/span&gt;&lt;/h3&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;메모리 영역 (좌측부터 리스트 요소 개수 50000, 10000, 1000, 100)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvSlpe/btsJhDUNqte/XCFywEXTJDeTyW4KZjnDVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvSlpe/btsJhDUNqte/XCFywEXTJDeTyW4KZjnDVk/img.png&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;618&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4952%; margin-right: 10px;&quot; data-widthpercent=&quot;50.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvSlpe/btsJhDUNqte/XCFywEXTJDeTyW4KZjnDVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvSlpe%2FbtsJhDUNqte%2FXCFywEXTJDeTyW4KZjnDVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;838&quot; height=&quot;618&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OyKl0/btsJhMxmVz5/nkFFhoF1OEjFQwgu818j71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OyKl0/btsJhMxmVz5/nkFFhoF1OEjFQwgu818j71/img.png&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;614&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.342%;&quot; data-widthpercent=&quot;49.92&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OyKl0/btsJhMxmVz5/nkFFhoF1OEjFQwgu818j71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOyKl0%2FbtsJhMxmVz5%2FnkFFhoF1OEjFQwgu818j71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;830&quot; height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;50000번 (좌측) / 10000번 (우측)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/otYMv/btsJfRFQFO4/KlO7UKtOErj50RpULR6Dmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/otYMv/btsJfRFQFO4/KlO7UKtOErj50RpULR6Dmk/img.png&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;560&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.3589%; margin-right: 10px;&quot; data-widthpercent=&quot;48.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/otYMv/btsJfRFQFO4/KlO7UKtOErj50RpULR6Dmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FotYMv%2FbtsJfRFQFO4%2FKlO7UKtOErj50RpULR6Dmk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;830&quot; height=&quot;560&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMQeID/btsJg5QGpq9/LWLPgPNwOEOgLtYacLRZv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMQeID/btsJg5QGpq9/LWLPgPNwOEOgLtYacLRZv0/img.png&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;552&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;51.07&quot; style=&quot;width: 50.4783%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMQeID/btsJg5QGpq9/LWLPgPNwOEOgLtYacLRZv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMQeID%2FbtsJg5QGpq9%2FLWLPgPNwOEOgLtYacLRZv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;854&quot; height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;1000번 (좌측) / 100번 (우측)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리의 경우에는 순회 방식과는 차이가 없기에 ArrayList, LinkedList 와의 비교가 될것 같다.&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;&lt;/b&gt;ArrayList의 메모리 사용량은 리스트 요소 개수에 따라 선형적으로 증가하며, 순회 방식에 따라 차이가 거의 없다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;ArrayList가 내부적으로 배열을 사용하여 고정된 크기의 메모리를 할당&lt;/span&gt;하기 때문에 발생하는 현상&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;/b&gt;LinkedList가 ArrayList에 비해서 더 많은 메모리를 사용하는 이유?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LinkedList가 각 노드가 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;양방향 링크를 포함하는 노드를 가지고 있고 추가적인 포인터를 저장하기 위해 더 많은 메모리를 차지&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;nbsp;&lt;b&gt;걸리는 시간&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRmovP/btsJg3l4Phf/c4jENS2poSgx9nkU6GkkFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRmovP/btsJg3l4Phf/c4jENS2poSgx9nkU6GkkFK/img.png&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;738&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.57&quot; style=&quot;width: 48.9932%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRmovP/btsJg3l4Phf/c4jENS2poSgx9nkU6GkkFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRmovP%2FbtsJg3l4Phf%2Fc4jENS2poSgx9nkU6GkkFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;784&quot; height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eNmnMS/btsJgRMTtXA/LYOOUn1yTzgggU4ZikRbg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eNmnMS/btsJgRMTtXA/LYOOUn1yTzgggU4ZikRbg0/img.png&quot; data-origin-width=&quot;776&quot; data-origin-height=&quot;718&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.844%;&quot; data-widthpercent=&quot;50.43&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eNmnMS/btsJgRMTtXA/LYOOUn1yTzgggU4ZikRbg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeNmnMS%2FbtsJgRMTtXA%2FLYOOUn1yTzgggU4ZikRbg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;776&quot; height=&quot;718&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;50000번 (좌측) / 10000번 (우측)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMi5Gc/btsJgE1ij2d/3AFhck18TjleLUUDhrnzI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMi5Gc/btsJgE1ij2d/3AFhck18TjleLUUDhrnzI0/img.png&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;726&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.2498%; margin-right: 10px;&quot; data-widthpercent=&quot;49.83&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMi5Gc/btsJgE1ij2d/3AFhck18TjleLUUDhrnzI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMi5Gc%2FbtsJgE1ij2d%2F3AFhck18TjleLUUDhrnzI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;766&quot; height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uoZhc/btsJhFZoYx4/dkAihR70wwklUachdTndZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uoZhc/btsJhFZoYx4/dkAihR70wwklUachdTndZ0/img.png&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;738&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.5874%;&quot; data-widthpercent=&quot;50.17&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uoZhc/btsJhFZoYx4/dkAihR70wwklUachdTndZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuoZhc%2FbtsJhFZoYx4%2FdkAihR70wwklUachdTndZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;784&quot; height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;1000번 (좌측) / 100번 (우측)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 LinkedList에서 크기가 커질수록 클래식한 For 문의 성능이 급격하게 나빠졌고 병렬순회를 사용하지 못해서 두 리스트 형식에서 모두 안좋은 성능이 나올것이라고 예상하던 Stream이 ArrayList에서는 성능이 안좋았지만 예상외로 큰 규모의 LinkedList 에서 좋은 성능을 보여줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. &lt;b&gt;Iterator&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Iterator는 next() 메서드를 통해 리스트를 순차적으로 순회하는 특성이 있다.&lt;/li&gt;
&lt;li&gt;ArrayList에서는 내부 배열에서 순차적으로 요소를 읽어오므로 효율적으로 나타났다. 하지만 For Loop 에 비해서 추가적인 메서드 구현이 존재하기에 오버헤드는 존재한다.&lt;/li&gt;
&lt;li&gt;LinkedList에서도 Iterator는 요소를 순차적으로 접근하기 때문에 인덱스 기반 접근에 비해 상대적으로 효율적 이다. 하지만 여전히 각 요소를 탐색할 때 다음 노드로 이동하는 추가적인 작업이 필요하기에 작은 크기에서는 무척 안좋은 성능을 가지지만 크기가 커질수록 좋은 성능을 보인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. &lt;b&gt;For Loop&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;For Loop는 인덱스를 이용하여 리스트의 요소에 접근한다.&lt;/li&gt;
&lt;li&gt;ArrayList의 경우 인덱스를 통한 접근이 O(1)의 시간 복잡도를 가지기 때문에, ArrayList에서 For Loop의 성능이 가장 좋다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;LinkedList의 경우, For Loop의 성능이 매우 떨어진다.&lt;/b&gt; 인덱스를 이용해 특정 요소에 접근하려면, 첫 번째 노드부터 차례대로 순회해야 하기에 요소의 개수가 많아질수록 인덱스를 기반으로 한 접근은 O(n)의 시간 복잡도가 요소마다 발생 한다.&lt;br /&gt;이로 인해, 특히 큰 리스트일수록 상당한 오버헤드와 시간지연이 두드러졌다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. &lt;b&gt;Enhanced For Loop&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Enhanced For Loop는 &lt;b&gt;내부적으로 Iterator를 사용&lt;/b&gt;하여 리스트를 순회한다.&lt;/li&gt;
&lt;li&gt;따라서 ArrayList와 LinkedList 모두에서 Iterator와 비슷한 성능을 보인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. &lt;b&gt;ListIterator&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ListIterator는 Iterator의 확장하여 구현한 버전으로, 리스트를 양방향으로 순회할 수 있는 기능을 제공 한다. Iterator와 비슷한 성능을 보이지만 역시나 추가적인 메서드 구현으로 인해서 Iterator 에 비해서 오버헤드가 발생한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;LinkedList의 경우&lt;/b&gt;, ListIterator는 기본적인 Iterator와 유사한 성능을 제공하지만 양방향 순회를 지원하기 때문에 이전 노드에 대한 정보를 좀더 빠르게 가져올수 있어서 빠르지 않았나 추측한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5. &lt;b&gt;Stream&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Stream API를 사용한 순회는 내부적으로 Spliterator를 사용하여 데이터를 순회한다. (분할 가능 반복자)&lt;/li&gt;
&lt;li&gt;ArrayList에서 Stream을 사용하는 것은 내부 구조를 효율적으로 활용하기 때문에 크기가 큰 데이터를 처리할 때 병렬 처리를 사용하지 않더라도 유리하다고 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;LinkedList의 경우,&lt;/b&gt;LinkedList의 요소 접근 방식과 Stream의 순차 처리 방식이 잘 맞지 않기 때문 에 요소가 많아질수록 처리 시간이 길어질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1724773981973&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Spliterator (Java Platform SE 8 )&quot; data-og-description=&quot;Characteristic value signifying that the element source may be safely concurrently modified (allowing additions, replacements, and/or removals) by multiple threads without external synchronization. If so, the Spliterator is expected to have a documented po&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html&quot; data-og-url=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Spliterator (Java Platform SE 8 )&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Characteristic value signifying that the element source may be safely concurrently modified (allowing additions, replacements, and/or removals) by multiple threads without external synchronization. If so, the Spliterator is expected to have a documented po&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>arraylist</category>
      <category>foreach</category>
      <category>Iterator</category>
      <category>LinkedList</category>
      <category>Listiterator</category>
      <category>stream.foreach()</category>
      <category>메모리</category>
      <category>시간 비교</category>
      <category>차이와 성능</category>
      <category>향상된 for 성능</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/213</guid>
      <comments>https://nstgic3.tistory.com/entry/DeepDive-For-For-each-Iterator-ListIterator-%EC%84%B1%EB%8A%A5%EB%B9%84%EA%B5%90#entry213comment</comments>
      <pubDate>Tue, 27 Aug 2024 00:06:55 +0900</pubDate>
    </item>
    <item>
      <title>영업시간 디자인 변경에 대응한 리팩토링 일지 [2] (feat: 버전별 API 캐시 전략)</title>
      <link>https://nstgic3.tistory.com/entry/%EC%98%81%EC%97%85%EC%8B%9C%EA%B0%84-%EB%94%94%EC%9E%90%EC%9D%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EB%8C%80%EC%9D%91%ED%95%9C-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81-%EC%9D%BC%EC%A7%80-2-feat-%EB%B2%84%EC%A0%84%EB%B3%84-API-%EC%BA%90%EC%8B%9C-%EC%A0%84%EB%9E%B5</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목차&lt;/span&gt;&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;이전 포스팅에서도 볼수 있다 싶이&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1724576672100&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;영업시간 디자인 변경에 대응한 리팩토링 일지 [1] (feat: 연결된 일정 구현하기)&quot; data-og-description=&quot;개요Dayner 에는 매달 정기 휴무일을 비롯한 연중 휴일, 급한 일정으로 인한 운영시간 변경등을 등록할수 있는 기능을 가지고 있다.&amp;nbsp;최초의 디자인인 경우에는 대부분 매주 월요일에 있는 정기 &quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/Dayner-%EC%98%81%EC%97%85%EC%8B%9C%EA%B0%84-%EB%94%94%EC%9E%90%EC%9D%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81-%EC%9D%BC%EC%A7%80&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/Dayner-%EC%98%81%EC%97%85%EC%8B%9C%EA%B0%84-%EB%94%94%EC%9E%90%EC%9D%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81-%EC%9D%BC%EC%A7%80&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cCziXk/hyWVYiJzjA/m0EJJPqwJ5ZJstndjR7Ke0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/Xfgnu/hyWSdBTNQM/YCtDHcM06AwB4xNLu6NXe0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bAX4HH/hyWScCXnCP/3CH4GZMpfAPmHgMG46O150/img.png?width=1444&amp;amp;height=1230&amp;amp;face=0_0_1444_1230&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/Dayner-%EC%98%81%EC%97%85%EC%8B%9C%EA%B0%84-%EB%94%94%EC%9E%90%EC%9D%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81-%EC%9D%BC%EC%A7%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/Dayner-%EC%98%81%EC%97%85%EC%8B%9C%EA%B0%84-%EB%94%94%EC%9E%90%EC%9D%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81-%EC%9D%BC%EC%A7%80&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cCziXk/hyWVYiJzjA/m0EJJPqwJ5ZJstndjR7Ke0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/Xfgnu/hyWSdBTNQM/YCtDHcM06AwB4xNLu6NXe0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bAX4HH/hyWScCXnCP/3CH4GZMpfAPmHgMG46O150/img.png?width=1444&amp;amp;height=1230&amp;amp;face=0_0_1444_1230');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;영업시간 디자인 변경에 대응한 리팩토링 일지 [1] (feat: 연결된 일정 구현하기)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요Dayner 에는 매달 정기 휴무일을 비롯한 연중 휴일, 급한 일정으로 인한 운영시간 변경등을 등록할수 있는 기능을 가지고 있다.&amp;nbsp;최초의 디자인인 경우에는 대부분 매주 월요일에 있는 정기&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span&gt;&lt;br /&gt;디자인 변화에 따른 회의를 통한 여러 아이디어들의 비교와 선정을 하였는데 이번 포스팅에서는 이를 적용하고 나름 어떻게 효율적으로 코드를 작성했나(?) 를 중점적으로 포스팅 해보려합니다.&lt;br /&gt;&lt;br /&gt;또한 따로 개발 서버를 두고 있지 않고있기 때문에 api의 버전명시를 통해서 현재 운영 서버에 새로운 프레젠테이션 구조를 가진 api 를 같이 배포를 하고 이에 대한 캐시 전략까지 확인해보기로합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아이디어 4를 적용한 서비스 로직 구현&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 아이디어4의 BusinessSchedule 엔티티에서 연속된 일정을 효율적으로 처리하기 위해 도입된 새로운 로직과 이에 따른 변경 사항을 다루고자 합니다.&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;기존의 로직에서는 일정의 BlockType(Start, Middle, End, Single)을 결정할 때 날짜만을 api 를 통하여 전달했기 때문에, 연속된 일정을 구분하는 작업이 주로 프론트엔드에서 이루어졌습니다.&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;따라서 아이디어4를 구현할때 연속된 일정들을 정확하게 구분하기 위해 날짜뿐만 아니라 ChangeType과 Description도 함께 고려하도록 BlockType 결정 로직을 개선했으며, 인덱스 기반 리스트 순회 방식을 Iterator로 대체하여 코드의 가독성과 유지보수성을 높였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724586728062&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private List&amp;lt;BusinessScheduleWithBlockTypeDTO&amp;gt; createScheduleDTOs(List&amp;lt;BusinessSchedule&amp;gt; businessSchedules) {
    List&amp;lt;BusinessScheduleWithBlockTypeDTO&amp;gt; scheduleDTOs = new ArrayList&amp;lt;&amp;gt;();
    Iterator&amp;lt;BusinessSchedule&amp;gt; iterator = businessSchedules.iterator();

    if (!iterator.hasNext()) {
        return scheduleDTOs; // 빈 리스트 처리
    }

    BusinessSchedule current = iterator.next();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리스트가 비어 있는 경우(hasNext()가 false), 빈 리스트 scheduleDTOs를 반환하게 하여 처리할 일정이 없는 경우를 처리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1470&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdGDAL/btsJfCgFOXo/unN4N96xoIc9fggD82K2rK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdGDAL/btsJfCgFOXo/unN4N96xoIc9fggD82K2rK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdGDAL/btsJfCgFOXo/unN4N96xoIc9fggD82K2rK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdGDAL%2FbtsJfCgFOXo%2FunN4N96xoIc9fggD82K2rK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1470&quot; height=&quot;380&quot; data-origin-width=&quot;1470&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이후에 List 의 iterator()을 호출하여 Iterator 로 만들어주고&lt;/li&gt;
&lt;li&gt;iterator.next()를 호출하여 리스트의 첫 번째 BusinessSchedule 객체를 current 변수에 할당하게 한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724586764864&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    boolean isPreviousLinked = false;

    while (iterator.hasNext()) {
        BusinessSchedule next = iterator.next();

        boolean isNextLinked = current.getDate().plusDays(1).isEqual(next.getDate()) &amp;amp;&amp;amp;
                current.getChangeType().equals(next.getChangeType()) &amp;amp;&amp;amp;
                current.getDescription().equals(next.getDescription());

        BlockType blockType = getBlockType(isPreviousLinked, isNextLinked);

        scheduleDTOs.add(BusinessScheduleWithBlockTypeDTO.from(current, blockType));
        isPreviousLinked = isNextLinked;
        current = next;
    }&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;isPreviousLinked는 이전 일정이 연속된 일정인지 여부를 나타내는 플래그로, 처음 값은 이전 값이 없기 때문에 false로 설정한다.&lt;/li&gt;
&lt;li&gt;while (iterator.hasNext()) 루프는 리스트의 모든 요소를 순회할 때까지 반복한다.&lt;/li&gt;
&lt;li&gt;루프 내부에서 iterator.next()를 호출하여 다음 일정(next)을 가져오게한다.(Iterator을 쓴 이유 중 하나. 표현이 직관적이다.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;isNextLinked 변수는 현재 일정(current)과 다음 일정(next)이 연속되는지 판단한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 일정의 날짜가 연속(즉, current.getDate().plusDays(1)이 next.getDate()와 동일)&lt;/li&gt;
&lt;li&gt;ChangeType과 Description이 동일&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;getBlockType(isPreviousLinked, isNextLinked) 메서드는 현재 일정의 BlockType을 결정한다.&lt;/li&gt;
&lt;li&gt;scheduleDTOs.add(BusinessScheduleWithBlockTypeDTO.from(current, blockType))를 호출하여 current 일정에 대한 BusinessScheduleWithBlockTypeDTO를 생성하고 리스트에 추가한다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;isPreviousLinked 플래그를 현재의 isNextLinked 값으로 업데이트해서 다음 루프에서 현재 일정이 이전 일정과 연속되는지 판단하는 데 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724586869091&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // 마지막 일정 처리
    BlockType lastBlockType = isPreviousLinked ? BlockType.END : BlockType.SINGLE;
    scheduleDTOs.add(BusinessScheduleWithBlockTypeDTO.from(current, lastBlockType));

    return scheduleDTOs;
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;루프가 끝나면 마지막 일정이 처리되지 않았기 때문에, 마지막 일정에 대한 BlockType을 결정하고 리스트에 추가한다.&lt;/li&gt;
&lt;li&gt;isPreviousLinked가 true라면 마지막 일정은 연속된 일정의 끝(END)으로 간주되며, 그렇지 않으면 독립적인 일정(SINGLE)으로 지정한다.&lt;/li&gt;
&lt;/ul&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;마지막으로 객체 생성 시에는 DTO 내부에 정적 팩토리 메서드(from)를 도입하였는데&lt;/p&gt;
&lt;pre id=&quot;code_1724588244076&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static class MonthlyScheduleDTO {
        private final List&amp;lt;BusinessScheduleWithBlockTypeDTO&amp;gt; businessScheduleDTOList;

        public MonthlyScheduleDTO(List&amp;lt;BusinessSchedule&amp;gt; businessScheduleList) {
            this.businessScheduleDTOList = createScheduleDTOs(businessScheduleList);
        }

        private enum BlockType {
            START, MIDDLE, END, SINGLE
        }

        private record BusinessScheduleWithBlockTypeDTO(int day, String changeType, String description, BlockType blockType) {
            public static BusinessScheduleWithBlockTypeDTO from(BusinessSchedule businessSchedule, BlockType blockType) {
                return new BusinessScheduleWithBlockTypeDTO(
                        businessSchedule.getDate().getDayOfMonth(),
                        businessSchedule.getChangeType().getTitle(),
                        businessSchedule.getDescription(),
                        blockType
                );
            }
        }

        private List&amp;lt;BusinessScheduleWithBlockTypeDTO&amp;gt; createScheduleDTOs(List&amp;lt;BusinessSchedule&amp;gt; businessSchedules) {
            List&amp;lt;BusinessScheduleWithBlockTypeDTO&amp;gt; scheduleDTOs = new ArrayList&amp;lt;&amp;gt;();
            Iterator&amp;lt;BusinessSchedule&amp;gt; iterator = businessSchedules.iterator();

            if (!iterator.hasNext()) {
                return scheduleDTOs; // 빈 리스트 처리
            }

            BusinessSchedule current = iterator.next();
            boolean isPreviousLinked = false;

            while (iterator.hasNext()) {
                BusinessSchedule next = iterator.next();

                boolean isNextLinked = current.getDate().plusDays(1).isEqual(next.getDate()) &amp;amp;&amp;amp;
                        current.getChangeType().equals(next.getChangeType()) &amp;amp;&amp;amp;
                        current.getDescription().equals(next.getDescription());

                BlockType blockType = getBlockType(isPreviousLinked, isNextLinked);

                scheduleDTOs.add(BusinessScheduleWithBlockTypeDTO.from(current, blockType));
                isPreviousLinked = isNextLinked;
                current = next;
            }

            // 마지막 일정 처리
            BlockType lastBlockType = isPreviousLinked ? BlockType.END : BlockType.SINGLE;
            scheduleDTOs.add(BusinessScheduleWithBlockTypeDTO.from(current, lastBlockType));

            return scheduleDTOs;
        }

        private static BlockType getBlockType(boolean isPreviousLinked, boolean isNextLinked) {
            BlockType blockType;
            if (isPreviousLinked &amp;amp;&amp;amp; isNextLinked) {
                blockType = BlockType.MIDDLE;
            } else if (isPreviousLinked) {
                blockType = BlockType.END;
            } else if (isNextLinked) {
                blockType = BlockType.START;
            } else {
                blockType = BlockType.SINGLE;
            }
            return blockType;
        }

    }&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;b&gt;DTO 내부에 변환 로직을 구현한 이유&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;BlockType은 프론트엔드에서 UI 표현을 위해 사용하는 정보로, 비즈니스 로직이나 데이터 저장하지 않는다. 또한 다른 도메인의 서비스단과 상호작용이 없고 프레젠테이션 단에서만 사용되기 때문에 DTO 클래스 내에 메서드 형태로 도입하여 책임을 분리했다.&lt;/li&gt;
&lt;li&gt;개념 객체를 통해 명시 해줄수도 있었다. 하지만 이후에 서버나 또다른 api에서 BlockType을 재사용할 일이 없다고 판단하여 안에 숨겨놓는 캡슐화를 진행했다.&lt;/li&gt;
&lt;/ol&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;해당 기능을 구현하는 상황에서는 생성자보다 더 명확하고 관리하기 쉬운 객체 생성 방식이라고 판단하였다.&lt;/li&gt;
&lt;li&gt;또한 생성자로 각 속성을 나열하는 것보다 객체 + DTO 내부에서만 선언되어있는 enum 타입 의 조합으로 해당 메서드가 동작한다는 것을 표현하고 싶었다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;캐시 전략에 대한 고민과 선택&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영 중인 애플리케이션을 안정적으로 유지하면서 새로운 기능을 개발하고 테스트하기 위해서 기존의 api와 캐시를 삭제하지 않고 그대로 두었고, 같은 DB에 접근하는 API를 엔드포인트의 버저닝부분을 /v2 로 변경하여 추가 구현을 해주었다.&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;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;v1과 v2 API를 동시에 운영하는 상황에서 적절한 캐시 전략이 필요하다고 생각이 들었습니다. 사실 많이 복잡하지는 않았지만 실제 운영 서버에 테스트를 위한 api 와 운영중인 api를 캐싱 기능을 포함하여 모두 올려보는게 처음이라서 글을 써본다.&lt;br /&gt;&lt;br /&gt;&lt;/span&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;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;최고의 선택은 테스트를 위한 서버를 따로 두거나 현재 채택되지 않은 api의 경우엔 캐시기능을 굳이 안넣는게 좋을것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div data-message-id=&quot;4600e1b8-c1a8-480f-a336-41d518d7df80&quot; data-message-author-role=&quot;assistant&quot;&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;&lt;b&gt;첫째&lt;/b&gt;, v1과 v2의 DTO 구조가 서로 다르다는 점.&lt;br /&gt;이로 인해 동일한 데이터를 캐시하더라도 두 버전이 서로 다른 형식으로 데이터를 사용하기 때문에, 캐시를 분리하여 관리하는 것이 불가피했다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;둘째&lt;/b&gt;, 각 버전의 캐시를 어떻게 무효화할지에 대한 고민이 있었다.&lt;br /&gt;특정 데이터가 수정, 추가, 삭제될 때, v1과 v2 모두에서 해당 데이터의 캐시가 무효화되어야 했기 때문이다.&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;/p&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2212&quot; data-origin-height=&quot;946&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/behfCO/btsJfQZ2Hfo/AdtvMNXUeea59kf0eWhkE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/behfCO/btsJfQZ2Hfo/AdtvMNXUeea59kf0eWhkE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/behfCO/btsJfQZ2Hfo/AdtvMNXUeea59kf0eWhkE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbehfCO%2FbtsJfQZ2Hfo%2FAdtvMNXUeea59kf0eWhkE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2212&quot; height=&quot;946&quot; data-origin-width=&quot;2212&quot; data-origin-height=&quot;946&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;버전별 독립 캐시 사용&lt;/b&gt;: v1과 v2의 DTO 구조 차이를 반영하여, 각 버전에서 별도의 캐시를 운영.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동일한 무효화 타이밍 적용&lt;/b&gt;: 데이터의 추가, 수정, 삭제 시점에 v1과 v2의 캐시를 동시에 무효화하도록 설정.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재는 운영중인 페이지와 새로운 디자인으로 개발되고 있는 개발 서버에서도 같은 서버 url을 통해서 각각의 api 가 확실하게 작동되고 있다.&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;캐시전략은 항상 꼼꼼히,,&lt;/p&gt;</description>
      <category>Dayner 프로젝트</category>
      <category>api 버저닝</category>
      <category>iterator 활용</category>
      <category>캐시 전략</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/212</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%98%81%EC%97%85%EC%8B%9C%EA%B0%84-%EB%94%94%EC%9E%90%EC%9D%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EB%8C%80%EC%9D%91%ED%95%9C-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81-%EC%9D%BC%EC%A7%80-2-feat-%EB%B2%84%EC%A0%84%EB%B3%84-API-%EC%BA%90%EC%8B%9C-%EC%A0%84%EB%9E%B5#entry212comment</comments>
      <pubDate>Sun, 25 Aug 2024 21:30:44 +0900</pubDate>
    </item>
    <item>
      <title>영업시간 디자인 변경에 대응한 리팩토링 일지 [1] (feat: 연결된 일정 구현하기)</title>
      <link>https://nstgic3.tistory.com/entry/Dayner-%EC%98%81%EC%97%85%EC%8B%9C%EA%B0%84-%EB%94%94%EC%9E%90%EC%9D%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81-%EC%9D%BC%EC%A7%80</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dayner 에는 매달 정기 휴무일을 비롯한 연중 휴일, 급한 일정으로 인한 운영시간 변경등을 등록할수 있는 기능을 가지고 있다.&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;최초의 디자인인 경우에는 대부분 매주 월요일에 있는 정기 휴무만 표시를 하고 있었기에 영업시간변경/휴일 을 표시하는 type, date, description 이 존재하고 있었다.&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;이를 ~/yyyyMM 형식으로 표현된 엔드포인트를 이용해 api 요청을 하면 영업일정(id,type, date, description) 로 된 db에 between 첫일~ 말일 쿼리를 이용해 제공을 해주고 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJPp00/btsI931pfdI/bbe7CcQfgM0ka7kXPkiYaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJPp00/btsI931pfdI/bbe7CcQfgM0ka7kXPkiYaK/img.png&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;1266&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.3789%; margin-right: 10px;&quot; data-widthpercent=&quot;50.97&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJPp00/btsI931pfdI/bbe7CcQfgM0ka7kXPkiYaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJPp00%2FbtsI931pfdI%2Fbbe7CcQfgM0ka7kXPkiYaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;884&quot; height=&quot;1266&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc1akO/btsJahE7Zn6/BrPkKbKlkKIL5ZDYk4j4x1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc1akO/btsJahE7Zn6/BrPkKbKlkKIL5ZDYk4j4x1/img.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1072&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.4583%;&quot; data-widthpercent=&quot;49.03&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc1akO/btsJahE7Zn6/BrPkKbKlkKIL5ZDYk4j4x1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc1akO%2FbtsJahE7Zn6%2FBrPkKbKlkKIL5ZDYk4j4x1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;1072&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;좌 : 기존 디자인 / 우 : 새로 바뀌는 디자인&lt;/figcaption&gt;
&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;문제는 디자인이 바뀌면서 프론트 단에서 우측 사진의 24~25일에 그려져있는 연속된 일정의 컴포넌트를 만들기 위해 프론트에서 과도한 자원 사용이 이루어지는 것 같다는 의견이 제시되면서 시작되었다.&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;span style=&quot;background-color: #f6e199;&quot;&gt;변화가 적고, get 요청이 대부분 이라는 도메인 특성을 생각해보면 서버에서 프론트가 표현하기 가장 쉬운 형태로 데이터를 조작해서 캐싱을 통해 구현을 하는게 가장 효율적이라고 판단&lt;/span&gt;을 하여 여러 방안을 생각해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;1230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lHg5R/btsJd9UnNnc/cNsLuzkDGXRO20HQYhq9w1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lHg5R/btsJd9UnNnc/cNsLuzkDGXRO20HQYhq9w1/img.png&quot; data-alt=&quot;대강 이번 리팩터링의 개념도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lHg5R/btsJd9UnNnc/cNsLuzkDGXRO20HQYhq9w1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlHg5R%2FbtsJd9UnNnc%2FcNsLuzkDGXRO20HQYhq9w1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1444&quot; height=&quot;1230&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;1230&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대강 이번 리팩터링의 개념도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아이디어 1&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt; 현재 기능을 유지하되, 같은 description 의 경우에는 date에 리스트 형식으로 표현한다.&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;해당 기능을 담당했던 개발자 분이 연속된 디자인을 구현해내기 위해서 description의 비교를 통해서 리스트를 만들었는데 이를 서버에서 만들면 어떨까 하는 아이디어를 내셨다.&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;h4 data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB 마이그레이션이 필요하지 않다.&lt;/li&gt;
&lt;li&gt;주어진 api 에 충실한 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리스트를 만드는 과정에서 연속되어있는지, description이 같은지를 검증 해보아야하기에 자원이 많이 낭비된다.&lt;/li&gt;
&lt;li&gt;또한 만들어진 리스트도 sort 를 통해 head 와 tail 을 인식하는 과정에 맨 앞과 맨 뒤의 index 를 가져오는 접근또한 자원이 소모된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;서버 측 - O(N)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;N개의 일정을 순회하면서 같은 description을 가진 일정을 그룹화하고, 연속된 날짜를 찾아 리스트를 만든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;프론트 측 - O(N)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프론트에서는 서버에서 받은 리스트를 다시 순회하면서 각 일정의 head, tail을 인식하는 작업을 수행해야 한다. 따라서 프론트에서도 O(N) 복잡도가 발생한다.&lt;/li&gt;
&lt;/ul&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;&amp;rarr; description 검증과 연속 여부를 검증하는 것보다 차라리 등록시에 리스트 형식으로 출력하기 쉽도록 등록하는건 어떨까?&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아이디어 2&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt; db 마이그레이션을 통해 startDate, endDate 속성을 추가한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직관적인 data&lt;/li&gt;
&lt;li&gt;서버단에서 추가적인 작업을 할 필요가 없다.&lt;/li&gt;
&lt;li&gt;head, tail 이 주어지기 때문에 프론트단의 자원소모가 적다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB 마이그레이션이 이루어져야한다!&lt;/li&gt;
&lt;li&gt;또한 쿼리를 발생시키는 과정에서도 전월의 말일 ~ 금월의초반 을 가지고 있는 일정의 경우에는 Between 쿼리를 이용하지 못해서 full scan 이 이루어진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;서버 측 - O(N)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;startDate와 endDate가 포함된 일정 데이터를 조회하는 과정에서, 특정 범위에 해당하는 일정들을 가져오는 작업은 여전히 O(N) 복잡도를 가진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;프론트 측 - O(1)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일정이 이미 startDate와 endDate로 구분되어 있으므로, 프론트에서 별도로 head와 tail을 인식할 필요가 없다.&lt;/li&gt;
&lt;/ul&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;&amp;rarr; DB마이그레이션이 이루어지지 않고 효율적인 구현이 어려울까?&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아이디어 3&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hasNext Boolean 옵션을 추가하여 연결 디자인에 대응한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB 마이그레이션이 필요하지 않다.&lt;/li&gt;
&lt;li&gt;단일 일정에 대해서 hasNext 검증을 통해 쉽게 구현 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;head, tail 에 대한 구분을 하기 위한 로직이 필요하다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;head: (prev.hasNext == False and now.hasNext == True)&lt;/li&gt;
&lt;li&gt;tail: (now.hasNext == True and next not null and next.hasNext == False)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;서버 측 - O(N)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버에서 일정에 hasNext 값을 추가하거나 기존 값을 업데이트할 때, 연속된 일정을 확인하는 작업이 O(N) 복잡도를 가진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;프론트 측 - O(N)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프론트에서는 hasNext 값을 바탕으로 head와 tail을 인식하기 위해 다시 O(N) 복잡도를 가진다.&lt;/li&gt;
&lt;/ul&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;&amp;rarr; 아예 head, tail 구분을 백엔드에서 제공해주는게 어떨까?&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아이디어 4&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;결국 우리가 필요한건?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입을 나누어서 생각해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1332&quot; data-origin-height=&quot;232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9RNTo/btsJaMkmo98/1SsIpOEkkcmKJQyRE3yMc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9RNTo/btsJaMkmo98/1SsIpOEkkcmKJQyRE3yMc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9RNTo/btsJaMkmo98/1SsIpOEkkcmKJQyRE3yMc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9RNTo%2FbtsJaMkmo98%2F1SsIpOEkkcmKJQyRE3yMc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1332&quot; height=&quot;232&quot; data-origin-width=&quot;1332&quot; data-origin-height=&quot;232&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연속된 일정을 위한 head와 tail 그리고 mid 가 있겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 일정을 위한 single 타입이 있고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든게 영업시간 변경/휴일 인지로 크게 나뉘어진다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;필수 구현 알고리즘?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB 마이그레이션을 진행할것이 아니라면(안하는 편이 DB 조회 측면에서도 효율적이다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 범위 내의 N개의 일정에 대해서&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;연속되는 일정인지 검증&lt;/li&gt;
&lt;li&gt;같은 type인지 검증&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;해당 과정이 필수적인데 O(N)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;이를 하는 과정에서 어떤 타입인지 서버에서 제공을 해준다면?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;아이디어 결론&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;blockType 이라는 새로운 속성을 만들어서 각 일정에 대해 특정 날짜가 어떤 블록 타입인지(start, middle, end, single) 판단한 후 클라이언트로 이 정보를 포함한 date만 나열된 데이터를 보내는 방식으로 진행해보자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB 마이그레이션이 필요하지 않다.&lt;/li&gt;
&lt;li&gt;단일 일정에 대해서 blockType 을 통해 쉽게 판별 가능하다.&lt;/li&gt;
&lt;li&gt;head, tail 구분을 위한 로직이 프론트에 구현되지 않아도 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 사이드에서의 자원소모가 불가피 하지만 DB 쿼리의 효율과 필수적으로 구현해야되는 로직이기 때문에 불가피한 소모라고 생각한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;서버 측 - O(N)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버에서 각 일정에 대해 blockType을 판단(start, middle, end, single)하고 이를 설정하는 과정이 O(N) 복잡도를 가진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;프론트 측 - O(1)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버에서 이미 blockType을 제공하므로, 프론트에서 추가적인 연산을 할 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아이디어 5&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;애초에 저장할때 blockType 도 같이 저장을 할까? (DB에 속성 추가)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 만약 일정에 변화가 생기게 된다면 변화된 일정 앞뒤로의 blockType 수정이 불가피하다.&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;1. 변화가 없다면 요청마다 계산을 하지 않아도 되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 캐싱 전략의 경우에는 GET 요청에 yyyyMM 파라미터를 이용해 저장해두고 yyyyMM 에 생성/업데이트/삭제가 수행될 경우에는 캐시 evict을 수행하는 방식으로 구현해보자&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이번 글에서는 Dayner의 일정 관리 기능의 새로운 디자인 요구사항 추가에 대응하여&amp;nbsp;다양한 아이디어를 탐색하고, 그 장단점을 비교해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div data-message-id=&quot;52b09fe8-3b19-4d87-8daf-ddb1ffe32f54&quot; data-message-author-role=&quot;assistant&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 아이디어를 고려한 결과로 api의 효율에는 &lt;b&gt;서버와 프론트 간의 역할 분담&lt;/b&gt;이 중요하다는 것을 깨닫게 되었는데 서론에서도 말했듯이, 시스템(도메인)의 특성과 요구 사항에 따라 어디의 자원을 이용할지 어떤 전략을 사용할지가 정해지는지를 배운것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 예로 들면, 아이디어 2의 경우에는 프론트 사이드에서 제시한 이슈를 해결하기 위해서 쉽고 귀찮지 않은(?) 방안으로 DB 마이그레이션을 통해 데이터를 구조적으로 변경하는 것이 빠를수도 있었지만, 프론트 사이드의 자원 사용을 같이 고려하여 적절하게 DB의 데이터를 후처리해서 제공을 해주는게 api의 효율을 높이는데 도움이 되었다는것을 알수 있었습니다.&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;간단하지만 나름의 View를 얻은게 있다하면 &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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;여담으로 아이디어의 DB구조로 처음 DB설계를 진행하려했는데 오히려 &lt;b&gt;최소한의 정보만을 담고 있었기에 리팩토링 시에 더 많은 가용성을 가지고 문제 해결에 접근할 수 있었던 것 같다&lt;/b&gt;는 생각을 하게 되어서 앞으로의 설계 철학에 이번 경험이 영향을 미칠것 같다는 생각이 들었습니다. ㅎㅎ&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Dayner 프로젝트</category>
      <category>dayner</category>
      <category>리팩토링</category>
      <category>연결된 일정 구현</category>
      <category>일지</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/211</guid>
      <comments>https://nstgic3.tistory.com/entry/Dayner-%EC%98%81%EC%97%85%EC%8B%9C%EA%B0%84-%EB%94%94%EC%9E%90%EC%9D%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81-%EC%9D%BC%EC%A7%80#entry211comment</comments>
      <pubDate>Thu, 22 Aug 2024 02:02:58 +0900</pubDate>
    </item>
    <item>
      <title>CORS 에러 발생 시나리오 정리</title>
      <link>https://nstgic3.tistory.com/entry/CORS-%EC%97%90%EB%9F%AC-%EB%B0%9C%EC%83%9D-%EC%8B%9C%EB%82%98%EB%A6%AC%EC%98%A4-%EC%A0%95%EB%A6%AC</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;면접 스터디 진행중 cors 에러 발생 시나리오에 대해 간단히 정리해둔것을 가져와봤다.&lt;/span&gt;&lt;/span&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;CORS의 개념&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Same-Origin Policy&lt;/b&gt;를 기반으로한 브라우저의 보안정책이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저는 같은 출처에서만 API 요청을 허용하기에 따라서, 다른 도메인, 프로토콜 또는 포트를 가진 서버로부터 자원을 요청할 경우 CORS 에러가 발생할 수 있다.&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;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[프론트] api 요청 프록시 설정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백엔드 서버가 EC2나 다른 클라우드 환경에 있고 해당 서버로 요청을 보낼 때, localhost에서 3000번 포트를 사용하여 서비스하는 경우 출처가 다르므로 CORS 오류가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 등 대부분의 프레임워크에서 패키징 관련 설정을 통해 proxy설정이 가능하니 api 서버로 url을 설정해주자.&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[서버] 특정/모든 출처에 대한 요청 허용&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;로컬에서 개발을 할 프론트를 위해 Access-Control-Allow-Origin 헤더에 특정 출처(http://localhost:3000 등) 또는 모든 출처(*)에서 오는 요청을 허용해야 해당 출처와 CORS에러 없이 통신이 가능하다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;[서버] Credentials 관련 헤더 설정, [프론트] withCredential 옵션&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt; 토큰이나 세션id 를 이용해 프로젝트를 구현해두고 withCredentials 옵션과 CORS 헤더 설정을 해놓지 않아 Preflight Request 과정에서 CORS 오류가 발생할수 있다. 혹은 에러 핸들링을 명확하게 하지 않았을때 자격증명 없음이 CORS 에러라고 명시될수도 있다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버의 CORS 설정에 Access-Control-Allow-Credentials: true를 추가하여 자격 증명을 포함한 요청을 허용하게 되면 내부의 자격증명을 검증해보고 검증 결과에 따라서 요청을 받아들이게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트에서는 서버가 자격 증명을 처리할 수 있도록 명시적으로 요청 withCredentials = true를 추가하여 요청에 쿠키와 인증 정보를 포함시켜 보내준다.&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[인프라/서버] 포트,프로토콜 이슈&lt;/span&gt;&lt;/h3&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 Oauth2 같은 HTTPS 를 사용해야만 하는 서비스를 이용할때 HTTP 를 이용한다거나, ALB 설정에 있어서 프록시 설정을 제대로 하지 않았거나, HTTP to HTTPS 와 같은 설정을 해주지 않아서 CORS 오류가 많이 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[인프라] Oauth2 리다이렉션 URI 미설정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt; OAuth2는 클라이언트 애플리케이션이 사용자를 대신해 리소스 서버에 접근할 수 있도록 권한을 부여하는 프로토콜로, 사용자 인증과 권한 부여가 아래와 같은 흐름으로 이루어진다.&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;Authorization Request&lt;/b&gt; 클라이언트 애플리케이션이 사용자에게 로그인 페이지를 보여주기 위해 인증 서버(Authorization Server)로 리다이렉트한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;User Authentication&lt;/b&gt; 사용자는 인증 서버에서 로그인하고, 인증 서버는 사용자를 리다이렉션 URL(redirect_uri)로 다시 보낸다. 이 URL에는 인증 코드(code)가 포함되어 있으며, 클라이언트는 이 코드를 사용하여 토큰 교환을 진행한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Token Exchange&lt;/b&gt; 클라이언트 애플리케이션은 받은 인증 코드를 사용해 인증 서버로부터 액세스 토큰(Access Token)을 요청하고 받는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;API 요청&lt;/b&gt;: 클라이언트 애플리케이션은 이 액세스 토큰을 포함하여 리소스 서버(Resource Server)로 API 요청을 보낸다.&lt;/li&gt;
&lt;/ol&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번의 인증코드를 포함해 리다이렉션을 보낼때 잘못된 uri 를 설정했다면 클라이언트 애플리케이션의 출처와 다르면 브라우저는 이를 크로스-오리진 요청으로 간주해서 오류가 발생할 수 있다.&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS</category>
      <category>cors 오류해결</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/210</guid>
      <comments>https://nstgic3.tistory.com/entry/CORS-%EC%97%90%EB%9F%AC-%EB%B0%9C%EC%83%9D-%EC%8B%9C%EB%82%98%EB%A6%AC%EC%98%A4-%EC%A0%95%EB%A6%AC#entry210comment</comments>
      <pubDate>Wed, 21 Aug 2024 13:22:01 +0900</pubDate>
    </item>
    <item>
      <title>Module not found: Error: Can't resolve '../{위치}' in '/home/runner/work/{위치}' 해결과 절대 경로 설정</title>
      <link>https://nstgic3.tistory.com/entry/Module-not-found-Error-Cant-resolve-%EC%9C%84%EC%B9%98-in-homerunnerwork%EC%9C%84%EC%B9%98-%ED%95%B4%EA%B2%B0%EA%B3%BC-%EC%A0%88%EB%8C%80-%EA%B2%BD%EB%A1%9C-%EC%84%A4%EC%A0%95</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;리액트로 작성된 프론트 코드의 CI/CD 를 하다가 오류가 발생했고 디버깅을 하다가 원인을 알아내서 간단히 작성해보려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;656&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqSqQP/btsI03sdQ3h/nJtV9Q3batc9rK49zBsYX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqSqQP/btsI03sdQ3h/nJtV9Q3batc9rK49zBsYX0/img.png&quot; data-alt=&quot;Github CI/CD 에러로그&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqSqQP/btsI03sdQ3h/nJtV9Q3batc9rK49zBsYX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqSqQP%2FbtsI03sdQ3h%2FnJtV9Q3batc9rK49zBsYX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1416&quot; height=&quot;656&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;656&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Github CI/CD 에러로그&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;원인 분석; 왜 Vite 나 Webpack 에서 발생하는가?&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt; 웹팩(Webpack)이나 Vite 는 모듈 번들러로 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;자바스크립트 파일들을 하나로 묶어 애플리케이션에서 사용할 수 있게&lt;span&gt; &lt;/span&gt;&lt;/span&gt;모듈이나 파일 경로를 해석하는데 이때 올바르지 않은 경로가 참조되면 Module not found 오류가 발생한다.&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;보통 상대 경로(../../components/Button)가 잘못 작성되었거나, 프로젝트 구조 변경 시 경로 수정이 누락된 경우에 발생한다. 또한, 웹팩이나 Vite가 특정 확장자를 찾지 못했을 때도 이 오류가 발생할 수 있다.&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해결책; 우회하기&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;1. 처음부터 작성을 잘 해둔다. 뒤에 파일 형식을 잘 지켜서&lt;/b&gt;&lt;br /&gt;&amp;nbsp;경로를 명확히 하고, 프로젝트 구조를 체계적으로 관리하여 오류를 방지한다.&lt;br /&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;2. resolve 옵션에 extentions 필드로 확장자를 자동으로 처리할 수 있게 구성한다.&lt;/b&gt;&lt;br /&gt;&amp;nbsp;웹번들러의 resolve 옵션의 extensions 필드를 설정하여 특정 확장자를 자동으로 처리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;nbsp;파일을 import할 때 확장자를 생략할 수 있고, 자동으로 해당 확장자를 가진 파일을 찾아준다.&lt;br /&gt;&lt;/span&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;pre id=&quot;code_1723336091683&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module.exports = {
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src/components'),
    },
    extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'], // TypeScript 파일 확장자도 추가
  },
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723336179094&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Resolve | 웹팩&quot; data-og-description=&quot;웹팩은 모듈 번들러입니다. 주요 목적은 브라우저에서 사용할 수 있도록 JavaScript 파일을 번들로 묶는 것이지만, 리소스나 애셋을 변환하고 번들링 또는 패키징할 수도 있습니다.&quot; data-og-host=&quot;webpack.kr&quot; data-og-source-url=&quot;https://webpack.kr/configuration/resolve/#resolveextensions&quot; data-og-url=&quot;https://webpack.kr/configuration/resolve/#resolveextensions&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/SSbdo/hyWKCaNafB/NfItZYwJIVQYyU9wId4akK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://webpack.kr/configuration/resolve/#resolveextensions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://webpack.kr/configuration/resolve/#resolveextensions&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/SSbdo/hyWKCaNafB/NfItZYwJIVQYyU9wId4akK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Resolve | 웹팩&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;웹팩은 모듈 번들러입니다. 주요 목적은 브라우저에서 사용할 수 있도록 JavaScript 파일을 번들로 묶는 것이지만, 리소스나 애셋을 변환하고 번들링 또는 패키징할 수도 있습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;webpack.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Alias 이용하여 절대경로 이용&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;alias 옵션의 경우에는 프로젝트 내 특정 디렉토리를 나타내는 단축 경로를 나타내서 ../../assets/* 또는 ../../../components/*와 같은 &lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;복잡한 경로 를 작성하기 쉽게 해주고 다수의 import 문을 수정할 필요가 없어진다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;리팩터링 시에 유지보수도 간편해지는것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723336297969&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Button from &quot;../../../components/Button&quot;;

// 아래와같이 표현이 가능하다!
import Button from &quot;@/components/Button&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1723336383282&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Resolve | 웹팩&quot; data-og-description=&quot;웹팩은 모듈 번들러입니다. 주요 목적은 브라우저에서 사용할 수 있도록 JavaScript 파일을 번들로 묶는 것이지만, 리소스나 애셋을 변환하고 번들링 또는 패키징할 수도 있습니다.&quot; data-og-host=&quot;webpack.kr&quot; data-og-source-url=&quot;https://webpack.kr/configuration/resolve/#resolvealias&quot; data-og-url=&quot;https://webpack.kr/configuration/resolve/#resolvealias&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b1GFSr/hyWOlLZJBx/OPOvCT837690o3n8d2C4r0/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://webpack.kr/configuration/resolve/#resolvealias&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://webpack.kr/configuration/resolve/#resolvealias&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b1GFSr/hyWOlLZJBx/OPOvCT837690o3n8d2C4r0/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Resolve | 웹팩&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;웹팩은 모듈 번들러입니다. 주요 목적은 브라우저에서 사용할 수 있도록 JavaScript 파일을 번들로 묶는 것이지만, 리소스나 애셋을 변환하고 번들링 또는 패키징할 수도 있습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;webpack.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;만약 TypeScript 를 이용하게 된다면 컴파일러 옵션을 이용하여 확장자, 절대 경로 모두를 이용할수 있게되는데 moduleResolution옵션과 ts 의 import 경로 설정을 해주면 쉽게 구현가능하다.&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;일단 이용하는 스택은 Vite, TS 이다.&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;먼저 TS 컴파일러와 IDE가 참고하는 설정파일 tsconfig.json 코드를 확인해보면&lt;/p&gt;
&lt;pre id=&quot;code_1723389383440&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    &quot;baseUrl&quot;: &quot;.&quot;,  // 프로젝트의 루트 디렉토리
    &quot;paths&quot;: {
      &quot;@/*&quot;: [&quot;src/*&quot;]  // '@'를 'src' 폴더로 매핑
    },
    &quot;jsx&quot;: &quot;react-jsx&quot;, // React 프로젝트의 JSX 설정
    &quot;target&quot;: &quot;ES2020&quot;,
    &quot;module&quot;: &quot;ESNext&quot;,
    &quot;moduleResolution&quot;: &quot;bundler&quot;,  // app에서도 bundler를 사용하므로 상위로 이동
    &quot;strict&quot;: true,
    &quot;esModuleInterop&quot;: true,
    &quot;skipLibCheck&quot;: true,
    &quot;forceConsistentCasingInFileNames&quot;: true,
    &quot;lib&quot;: [&quot;ES2020&quot;, &quot;DOM&quot;, &quot;DOM.Iterable&quot;],  // app과 상위 둘 다 사용하므로 상위로 이동
    &quot;resolveJsonModule&quot;: true
  },
  &quot;include&quot;: [&quot;src/**/*&quot;],
  &quot;exclude&quot;: [&quot;node_modules&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;baseUrl과 paths 옵션을 통해 TypeScript가 모듈 경로를 해석하는 방법을 설정&lt;/b&gt;하는데 이때 paths 설정을 통해 프로젝트 내에서 alias를 사용할수 있게 된다.&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;위 코드에서 작성한 @/*를 src/*로 매핑하면, @/components/Button과 같이 짧은 경로로 파일을 import할수 있게 되고 해당 설정은 &lt;b&gt;TS 컴파일러 동작시에 작동&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;span style=&quot;background-color: #f6e199;&quot;&gt;vite.config.ts 에 잘 작성했는데 실제 사용하려고 @/~ 을 이용해 import 를 했을때 참조오류가 발생하는것&lt;/span&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;config.app.json는 하위의 설정(동작 어플리케이션) 으로 상위의 설정을 상속받아 작동하는데 모듈화가 되어있고 큰 프로젝트라면 적절하게 작성해주도록하자.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vite는 번들러로서 모듈을 해석할 때 TypeScript 설정을 자동으로 인식하지 않는다.(아쉽게도)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 Vite는 독립적으로 설정된 alias를 사용하여 파일 경로를 알아야하기 때문에 vite.config.ts 파일에 명시적으로 alias를 설정해주도록 하자&lt;/p&gt;
&lt;pre id=&quot;code_1723389917537&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
});&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;이후에는 간단히 src 내부 컴포넌트를 하나 만들어보고 이를 app.tsx에서 작동 테스트를 해보았다.&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;&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;혹시 이렇게 해도 오류가 발생하거나 확장자 매핑 문제가 발생하면&amp;nbsp;&lt;b&gt;&lt;span&gt;&quot;compilerOptions&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;{&lt;/span&gt; &lt;span&gt;&quot;allowImportingTsExtensions }&lt;/span&gt;&lt;/b&gt;&lt;span&gt; 옵션이 true 인지 확인해보자&lt;/span&gt;&lt;/p&gt;</description>
      <category>React</category>
      <category>Alias</category>
      <category>extentions</category>
      <category>module not found: error: can't resolve</category>
      <category>react</category>
      <category>절대 경로</category>
      <category>타입스크립트 alias 문제</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/209</guid>
      <comments>https://nstgic3.tistory.com/entry/Module-not-found-Error-Cant-resolve-%EC%9C%84%EC%B9%98-in-homerunnerwork%EC%9C%84%EC%B9%98-%ED%95%B4%EA%B2%B0%EA%B3%BC-%EC%A0%88%EB%8C%80-%EA%B2%BD%EB%A1%9C-%EC%84%A4%EC%A0%95#entry209comment</comments>
      <pubDate>Sun, 11 Aug 2024 09:33:45 +0900</pubDate>
    </item>
    <item>
      <title>반년 간의 EC2 Spring 배포 Thread Stravation 장애 해결기</title>
      <link>https://nstgic3.tistory.com/entry/%EB%B0%98%EB%85%84-%EA%B0%84%EC%9D%98-EC2-Spring-%EB%B0%B0%ED%8F%AC-%EC%9E%A5%EC%95%A0-%ED%95%B4%EA%B2%B0%EA%B8%B0</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요 및 프로젝트 특징(조건)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;작년 이맘때에 샀던 도메인의 만료로 인해 갱신도 했으니 가운영 반년, 실제 운영 1년이 넘어가는 시점이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1240&quot; data-origin-height=&quot;744&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dW6qKh/btsI1fMtHDK/PuA9VVkm9XPhWTHhQ83to1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dW6qKh/btsI1fMtHDK/PuA9VVkm9XPhWTHhQ83to1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dW6qKh/btsI1fMtHDK/PuA9VVkm9XPhWTHhQ83to1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdW6qKh%2FbtsI1fMtHDK%2FPuA9VVkm9XPhWTHhQ83to1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1240&quot; height=&quot;744&quot; data-origin-width=&quot;1240&quot; data-origin-height=&quot;744&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;약 22회의 기능 추가/수정 으로 인한 Deploy, 와 30번 이상의 hotfix, 그리고 두번의 대규모 리팩터링을 거친 나름 내가 진행해본 프로젝트 중에서 가장 공을 많이 들이고 여러 기술도 적용시켜보며 지속적으로 신경쓴 프로젝트라고 할수 있을것같다. 특징으로는&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. 최소 비용이 목표라 aws 의 프리티어 ec2를 사용중&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 특성상 카페 이용 시간대만 사용자가 몰리고, 트래픽이 증가되는 시간대가 정해져있다. 따라서 AutoScale 을 도입.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 테스트 상으로 5명의 유저가 분당 150 내외의 GET 요청까지는 무리없이 커버한다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;10개월~ 정도는 규모도 작고 이용자도 적어서 잘 이용하고 있었는데 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;사람이 몰리지 않는 새벽 시간대나 아침 시간대에도 인스턴스 교체(오토 스케일링으로 인한 인스턴스 복제 후에 오래된 인스턴스가 삭제 되는 현상)가 일어나는 문제점이 발생&lt;/span&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;/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. 중요 트랜잭션이 실행되고 있는걸 캐치해서 상태를 보여주는 엔드포인트를 만들어 이를 헬스체크에 사용하고 인프라 구조를 블루/그린 방식으로 변경하거나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 최소 인스턴스 개수를 2개로 띄우거나(돈이 2배로!)&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;여러 방법이 있었는데 ASG 에 보면 왜 스케일-아웃이 일어났는지 모니터링/로깅을 해둔 부분이 있어 확인해보니&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Healty check의 기준이 너무 타이트했다!&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;나는,, ec2 프리티어를 사용하고 있는데 healty check 는 전혀 이를 고려하지 않은 세팅이었던 것이다.&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 인스턴스가 최초 시작후에 apt 업데이트 등을 거치고 spring 코드를 가져오고(CI/CD) 하는 과정에서 적절한 wait()가 이루어지지 않아 cpu 에 부하가 걸렸고, 이로 인해서 ec2 내의 스프링 프로젝트의 시작 시간이 5분 넘게 걸리는 경우도 있었다.&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이 있었고 스케일 업을 통해 새로 만들어진 인스턴스 2가 프로젝트 시작도 채 해보지 않고 healty check 에 걸려서 또다시 중지 처리가 되고 새로운 인스턴스 3가 만들어지는 경우도 존재했다.&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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;AutoScailing Group 스케일-아웃 조건 러프하게 만들기&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;를 통해서 스케일-아웃 당시에 인스턴스가 3개,, 4개 발생되는것을 막을수 있었다.&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&amp;gt;대상그룹&amp;gt;ALB&amp;gt;대상검사 경로로 들어가면 설정이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1616&quot; data-origin-height=&quot;1400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfikQQ/btsIFHvXRYG/4v40jEDkIpANp8lFSGVzl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfikQQ/btsIFHvXRYG/4v40jEDkIpANp8lFSGVzl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfikQQ/btsIFHvXRYG/4v40jEDkIpANp8lFSGVzl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfikQQ%2FbtsIFHvXRYG%2F4v40jEDkIpANp8lFSGVzl1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1616&quot; height=&quot;1400&quot; data-origin-width=&quot;1616&quot; data-origin-height=&quot;1400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;그렇게 한달 정도는 별탈 없이 사용했던것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;그리고 당시에 prometheus 를 다른 vpc의 ec2위에 올려서 이 서버를 모니터링 하게 하였고 메모리 또한 준수하게 작동되었었다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Thread starvation 의 발생&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1402&quot; data-origin-height=&quot;208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpPzRQ/btsI0UIS6Oe/12D2Ug9zqYs7ZOQPYMAr31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpPzRQ/btsI0UIS6Oe/12D2Ug9zqYs7ZOQPYMAr31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpPzRQ/btsI0UIS6Oe/12D2Ug9zqYs7ZOQPYMAr31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpPzRQ%2FbtsI0UIS6Oe%2F12D2Ug9zqYs7ZOQPYMAr31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1402&quot; height=&quot;208&quot; data-origin-width=&quot;1402&quot; data-origin-height=&quot;208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. EC2의 시스템 로그 확인하기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1462&quot; data-origin-height=&quot;838&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zzSVu/btsI0uRxLIF/PuPqApaHRQL9OM6qlzHG3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zzSVu/btsI0uRxLIF/PuPqApaHRQL9OM6qlzHG3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zzSVu/btsI0uRxLIF/PuPqApaHRQL9OM6qlzHG3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzzSVu%2FbtsI0uRxLIF%2FPuPqApaHRQL9OM6qlzHG3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1462&quot; height=&quot;838&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1462&quot; data-origin-height=&quot;838&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1464&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doi28H/btsIZQtXKqB/qJPA2aaVLL5mBajQ1Q1tzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doi28H/btsIZQtXKqB/qJPA2aaVLL5mBajQ1Q1tzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doi28H/btsIZQtXKqB/qJPA2aaVLL5mBajQ1Q1tzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdoi28H%2FbtsIZQtXKqB%2FqJPA2aaVLL5mBajQ1Q1tzK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1464&quot; height=&quot;456&quot; data-origin-width=&quot;1464&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2 인스턴스에는 문제가 없이 실행중이었다. 단지 Spring 프로젝트가 셧다운 되서 healty check 가 되지않아 교체되고 있었다.&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. CPU, 메모리 사용량 확인하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2와 로드밸런서의 모니터링 서비스를 활용하여 혹시 트래픽이 증가해서 발생했는지 확인해보았다.&lt;br /&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;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;이때 인프라에는 아무 문제가 없다고 판단하고 시선을 제작한 스프링서버로 돌렸다.. ( 시야가 좁아져버린,,)&lt;/span&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;3. 스프링 프로젝트의 모니터링 확인&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bif6s6/btsI0x1LBBU/vaR6KSFpdrmLpzLjYlcGM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bif6s6/btsI0x1LBBU/vaR6KSFpdrmLpzLjYlcGM0/img.png&quot; data-origin-width=&quot;2090&quot; data-origin-height=&quot;1788&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.6245%; margin-right: 10px;&quot; data-widthpercent=&quot;50.21&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bif6s6/btsI0x1LBBU/vaR6KSFpdrmLpzLjYlcGM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbif6s6%2FbtsI0x1LBBU%2FvaR6KSFpdrmLpzLjYlcGM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2090&quot; height=&quot;1788&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwa9La/btsI0slSgzw/XtY6IG777nRMkp2xKjdhWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwa9La/btsI0slSgzw/XtY6IG777nRMkp2xKjdhWK/img.png&quot; data-origin-width=&quot;1398&quot; data-origin-height=&quot;1206&quot; data-is-animation=&quot;false&quot; width=&quot;608&quot; height=&quot;524&quot; style=&quot;width: 49.2127%;&quot; data-widthpercent=&quot;49.79&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwa9La/btsI0slSgzw/XtY6IG777nRMkp2xKjdhWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdwa9La%2FbtsI0slSgzw%2FXtY6IG777nRMkp2xKjdhWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1398&quot; height=&quot;1206&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;Heap 영역도 안정적으로 이루어지고 GC 또한 균등한 매그니튜드로 실행되고 있음을 확인했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;설계 문제로 인해서 메모리 누수가 일어나고 있음이 아닌것이 확인&lt;/span&gt; 되었다.&lt;br /&gt;&lt;br /&gt;점점 해결의 실마리가 보이지 않고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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. 스레드 덤프 분석&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mkvuh/btsI02zYvCF/So1LiKo8rfRwgihdd22p60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mkvuh/btsI02zYvCF/So1LiKo8rfRwgihdd22p60/img.png&quot; data-origin-width=&quot;1484&quot; data-origin-height=&quot;548&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;82.02&quot; style=&quot;width: 81.0666%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mkvuh/btsI02zYvCF/So1LiKo8rfRwgihdd22p60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmkvuh%2FbtsI02zYvCF%2FSo1LiKo8rfRwgihdd22p60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1484&quot; height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CCJCi/btsI1wgh0Wo/HEMJk1BwDSRc12iiZYO3o0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CCJCi/btsI1wgh0Wo/HEMJk1BwDSRc12iiZYO3o0/img.png&quot; data-origin-width=&quot;2086&quot; data-origin-height=&quot;3514&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;17.98&quot; style=&quot;width: 17.7706%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CCJCi/btsI1wgh0Wo/HEMJk1BwDSRc12iiZYO3o0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCCJCi%2FbtsI1wgh0Wo%2FHEMJk1BwDSRc12iiZYO3o0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2086&quot; height=&quot;3514&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;CPU 의 사용량이 70퍼센트를 넘거나 요청이 5건 이상 들어오는 경우를 cloudwatch 로 catch 해서 이벤트 발생 후 10분간 30초 간격으로 자동으로 스레드 덤프를 가져오는 jstack을 활용해 덤프 생성하여 MAT을 통해 확인을 해보았다.&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;상당한 노가다였지만 발생 당시에 TIMED_WAITING 또는 WAITING 상태에 적은 CPU점유를 가지고 있었고 따로 BLOCKED 상태로 길게 유지 되는 경우가 없었다.&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;따라서 스레드 덤프에는 문제가 없었고, 여기서 스레드 덤프의 생성이 높은 CPU사용량이나 스레드의 BLOCKED 상태가 장기화 되기 이전에 멈췄다는 것을 발견했다.&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;span style=&quot;background-color: #f6e199;&quot;&gt;어플리케이션 외부에 문제가 있다고 판단 하게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;starvation 을 해결하기 위한 다양한 시도&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;1. HikariCP 풀사이즈 변경&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;기본 값으로 10이 설정 되어있었지만 EC2의 프리티어는 코어수 2개에 코어당 스레드수 2개 총 4개의 스레드에 메모리도 8기가 이기에,&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; 시스템 리소스가 과부화 될수 있을것 같다고 판단했다.&lt;/span&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;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;그래서 조정을 하려보니 개수 공식이 존재했고, 또한 여러가지 고려할 상황도 존재했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1723269955101&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;blog&quot; data-og-title=&quot;Testing MySQL Applications With Java and Testcontainers&quot; data-og-description=&quot;Writing comprehensive tests for code that interacts with a database can be a challenge. In this post, we talk about how we can use Testcontainers and JUnit to make it is easier to write tests for Java applications that interct with a MySQL database.&quot; data-og-host=&quot;blogs.oracle.com&quot; data-og-source-url=&quot;https://blogs.oracle.com/mysql/post/testing-mysql-applications-with-java-and-testcontainers&quot; data-og-url=&quot;https://orasites-prodapp.cec.ocp.oraclecloud.com/site/mysql/post/testing-mysql-applications-with-java-and-testcontainers&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/IOpYx/hyWKJ8HXnd/EIjWJhJMGFUGI2UMKug2xk/img.jpg?width=1024&amp;amp;height=585&amp;amp;face=0_0_1024_585,https://scrap.kakaocdn.net/dn/wloJM/hyWOk0wJ8y/lGYOxZbBQ1B5Qx6idzlcA1/img.jpg?width=1024&amp;amp;height=585&amp;amp;face=0_0_1024_585,https://scrap.kakaocdn.net/dn/sMEu7/hyWKzE38i1/wplPJakvkB6iYoVILYqvI0/img.jpg?width=702&amp;amp;height=463&amp;amp;face=0_0_702_463&quot;&gt;&lt;a href=&quot;https://blogs.oracle.com/mysql/post/testing-mysql-applications-with-java-and-testcontainers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blogs.oracle.com/mysql/post/testing-mysql-applications-with-java-and-testcontainers&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/IOpYx/hyWKJ8HXnd/EIjWJhJMGFUGI2UMKug2xk/img.jpg?width=1024&amp;amp;height=585&amp;amp;face=0_0_1024_585,https://scrap.kakaocdn.net/dn/wloJM/hyWOk0wJ8y/lGYOxZbBQ1B5Qx6idzlcA1/img.jpg?width=1024&amp;amp;height=585&amp;amp;face=0_0_1024_585,https://scrap.kakaocdn.net/dn/sMEu7/hyWKzE38i1/wplPJakvkB6iYoVILYqvI0/img.jpg?width=702&amp;amp;height=463&amp;amp;face=0_0_702_463');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Testing MySQL Applications With Java and Testcontainers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Writing comprehensive tests for code that interacts with a database can be a challenge. In this post, we talk about how we can use Testcontainers and JUnit to make it is easier to write tests for Java applications that interct with a MySQL database.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blogs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1723269459803&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;HikariCP Dead lock에서 벗어나기 (실전편) | 우아한형제들 기술블로그&quot; data-og-description=&quot;1부 HikariCP Dead lock에서 벗어나기 (이론편)은 잘 보셨나요? 2부 HikariCP Dead lock에서 벗어나기 (실전편)에서는 실제 장애 사례를 기반으로 장애 원인을 설명하고 해결 사례를 공유하고자 합니다. 그&quot; data-og-host=&quot;techblog.woowahan.com&quot; data-og-source-url=&quot;https://techblog.woowahan.com/2663/&quot; data-og-url=&quot;https://techblog.woowahan.com/2663/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qZpXd/hyWOnJH5Vq/SmCijkilbApPgZEk5XmR41/img.jpg?width=1640&amp;amp;height=856&amp;amp;face=0_0_1640_856,https://scrap.kakaocdn.net/dn/4NSUU/hyWOd1otIR/9KeOOZfatKITZWG59y0kX1/img.jpg?width=1640&amp;amp;height=856&amp;amp;face=0_0_1640_856,https://scrap.kakaocdn.net/dn/cCZc6y/hyWKDOa3tG/X0eGGexmY6kkP0AlP5MMmk/img.png?width=1876&amp;amp;height=1846&amp;amp;face=0_0_1876_1846&quot;&gt;&lt;a href=&quot;https://techblog.woowahan.com/2663/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techblog.woowahan.com/2663/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qZpXd/hyWOnJH5Vq/SmCijkilbApPgZEk5XmR41/img.jpg?width=1640&amp;amp;height=856&amp;amp;face=0_0_1640_856,https://scrap.kakaocdn.net/dn/4NSUU/hyWOd1otIR/9KeOOZfatKITZWG59y0kX1/img.jpg?width=1640&amp;amp;height=856&amp;amp;face=0_0_1640_856,https://scrap.kakaocdn.net/dn/cCZc6y/hyWKDOa3tG/X0eGGexmY6kkP0AlP5MMmk/img.png?width=1876&amp;amp;height=1846&amp;amp;face=0_0_1876_1846');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;HikariCP Dead lock에서 벗어나기 (실전편) | 우아한형제들 기술블로그&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1부 HikariCP Dead lock에서 벗어나기 (이론편)은 잘 보셨나요? 2부 HikariCP Dead lock에서 벗어나기 (실전편)에서는 실제 장애 사례를 기반으로 장애 원인을 설명하고 해결 사례를 공유하고자 합니다. 그&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techblog.woowahan.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;다행히도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;id AUTO 전략을 사용한적은 없었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1회의 요청에 2개 이상의 커넥션을 만드는 Lazy 로딩으로 설정된 OneToMany나 ManyToMany 전략을 사용하지 않았고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;db 요청에 관한 쿼리는 JPQL 로 fetch join 을 사용하여 1회만에 수행가능하게 만들어놓았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WbKEa/btsIZYewYX9/xWDFl6TZZScZ4V5uUMxRP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WbKEa/btsIZYewYX9/xWDFl6TZZScZ4V5uUMxRP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WbKEa/btsIZYewYX9/xWDFl6TZZScZ4V5uUMxRP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWbKEa%2FbtsIZYewYX9%2FxWDFl6TZZScZ4V5uUMxRP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;908&quot; height=&quot;112&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 마진을 두어 Cm을 2로 잡았고 Tn 은 현재 Ec2 의 스펙을 따라서&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bE8qPA/btsI1vuUv5W/bqZdkYPiy9nob1QrvtKhKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bE8qPA/btsI1vuUv5W/bqZdkYPiy9nob1QrvtKhKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bE8qPA/btsI1vuUv5W/bqZdkYPiy9nob1QrvtKhKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbE8qPA%2FbtsI1vuUv5W%2FbqZdkYPiy9nob1QrvtKhKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1116&quot; height=&quot;592&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;4로 설정하여 최소 풀의 크기는 5, 여기에 1의 추가 마진을 주어 6으로 변경 해보기도 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2714&quot; data-origin-height=&quot;760&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA8XZv/btsIZL7vVEl/YUiCXRjiEMsAahYdjxsT41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA8XZv/btsIZL7vVEl/YUiCXRjiEMsAahYdjxsT41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA8XZv/btsIZL7vVEl/YUiCXRjiEMsAahYdjxsT41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA8XZv%2FbtsIZL7vVEl%2FYUiCXRjiEMsAahYdjxsT41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2714&quot; height=&quot;760&quot; data-origin-width=&quot;2714&quot; data-origin-height=&quot;760&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;b&gt;&amp;nbsp;2. EC2 의 스왑 메모리 적용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 사용하고 있는 ec2 의 메모리는 총 1GB로 Spring 에서 사용할수 있는 메모리의 수가 부족한것 같다는 판단이 들었다.&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 인스턴스로 교체를 해보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; &lt;b&gt;최소한의 유지비용을 위해&lt;/b&gt;서 프리티어를 쓰기 때문에 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;더 높은 인스턴스로의 교체는 최후의 수단&lt;/span&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VTPzV/btsJnrt0Spl/LIfpzQaMYdIC8lZ6GkFRk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VTPzV/btsJnrt0Spl/LIfpzQaMYdIC8lZ6GkFRk0/img.png&quot; data-alt=&quot;사실 시도를 안해보지는 않았다. (8월은 도메인 구입비용때문에 20달러가 추가지출 된것이다)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VTPzV/btsJnrt0Spl/LIfpzQaMYdIC8lZ6GkFRk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVTPzV%2FbtsJnrt0Spl%2FLIfpzQaMYdIC8lZ6GkFRk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1220&quot; height=&quot;470&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사실 시도를 안해보지는 않았다. (8월은 도메인 구입비용때문에 20달러가 추가지출 된것이다)&lt;/figcaption&gt;
&lt;/figure&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;클라이언트로 하여금 가끔 끊기는 현상을 방지하기 위해 운영비를 2배로 늘렸습니다. 는 정말 최후의 수단인거다.&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;span style=&quot;background-color: #f6e199;&quot;&gt; EC2는 PC의 가상 메모리처럼 디스크용량을 메모리로 스왑하여 사용이 가능&lt;/span&gt;하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1723275202488&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;스왑 파일을 사용하여 Amazon EC2 인스턴스에서 메모리를 스왑 스페이스로 할당합니다.&quot; data-og-description=&quot;Amazon Elastic Compute Cloud(Amazon EC2) 인스턴스에서 스왑 파일로 사용할 메모리를 할당하고 싶습니다. 어떻게 해야 하나요?&quot; data-og-host=&quot;repost.aws&quot; data-og-source-url=&quot;https://repost.aws/ko/knowledge-center/ec2-memory-swap-file&quot; data-og-url=&quot;https://repost.aws/ko/knowledge-center/ec2-memory-swap-file&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bACkGV/hyWKFkYcrX/fOxQR4lAyiu2gyT2NkcW20/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://repost.aws/ko/knowledge-center/ec2-memory-swap-file&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://repost.aws/ko/knowledge-center/ec2-memory-swap-file&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bACkGV/hyWKFkYcrX/fOxQR4lAyiu2gyT2NkcW20/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;스왑 파일을 사용하여 Amazon EC2 인스턴스에서 메모리를 스왑 스페이스로 할당합니다.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Amazon Elastic Compute Cloud(Amazon EC2) 인스턴스에서 스왑 파일로 사용할 메모리를 할당하고 싶습니다. 어떻게 해야 하나요?&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;repost.aws&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8OOOj/btsI0t6bBnM/0avreeU91jBkJINaFd4rg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8OOOj/btsI0t6bBnM/0avreeU91jBkJINaFd4rg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8OOOj/btsI0t6bBnM/0avreeU91jBkJINaFd4rg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8OOOj%2FbtsI0t6bBnM%2F0avreeU91jBkJINaFd4rg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1392&quot; height=&quot;248&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4mtGV/btsIZPol55B/KFHikzwrmpo2UglO8k3gRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4mtGV/btsIZPol55B/KFHikzwrmpo2UglO8k3gRK/img.png&quot; data-alt=&quot;기존 1기가였던 메모리 + 스왑메모리 3기가를 추가해 총 4기가의 메모리를 가지게 되었다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4mtGV/btsIZPol55B/KFHikzwrmpo2UglO8k3gRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4mtGV%2FbtsIZPol55B%2FKFHikzwrmpo2UglO8k3gRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1380&quot; height=&quot;408&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;기존 1기가였던 메모리 + 스왑메모리 3기가를 추가해 총 4기가의 메모리를 가지게 되었다.&lt;/figcaption&gt;
&lt;/figure&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;그렇다면 해결이 되었을까?&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;span style=&quot;background-color: #f6e199;&quot;&gt;스왑 메모리의 도입으로 Stravation으로 인한 셧다운 문제는 해결&lt;/span&gt;되었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1532&quot; data-origin-height=&quot;942&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXL33F/btsJpJM2Bcs/KShpZ890cKSUoOWgDk3cQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXL33F/btsJpJM2Bcs/KShpZ890cKSUoOWgDk3cQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXL33F/btsJpJM2Bcs/KShpZ890cKSUoOWgDk3cQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXL33F%2FbtsJpJM2Bcs%2FKShpZ890cKSUoOWgDk3cQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1532&quot; height=&quot;942&quot; data-origin-width=&quot;1532&quot; data-origin-height=&quot;942&quot;/&gt;&lt;/span&gt;&lt;/figure&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;OOM 의 발생&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 얼마 지나지 않아 OOM(Out Of Memory)가 발생하게 되었는데..&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;스왑 메모리 할당으로 인한 디스크 공간 부족&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OOM, 즉 메모리가 부족하다는거다.&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;디스크 공간은 충분할까? 싶어서 인스턴스 status 를 확인해보았더니&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MXpCO/btsI0rUOwFI/BWW5Ukx6RulfWoWVFApWV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MXpCO/btsI0rUOwFI/BWW5Ukx6RulfWoWVFApWV0/img.png&quot; data-alt=&quot;Wa! 99%!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MXpCO/btsI0rUOwFI/BWW5Ukx6RulfWoWVFApWV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMXpCO%2FbtsI0rUOwFI%2FBWW5Ukx6RulfWoWVFApWV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1116&quot; height=&quot;208&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;208&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Wa! 99%!&lt;/figcaption&gt;
&lt;/figure&gt;
&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;왜 사전에 확인을 못했을까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하고 있는 프리티어의 EC2 인스턴스 기본 설정 디스크 공간 크기는 8기가인데,&amp;nbsp;초창기에 단순히 java 파일과 jdk 설치+aws 클라이언트 설치만을 했을때 &lt;b&gt;많아도 4기가가 넘지 않아&lt;/b&gt; 30기가까지의 디스크 공간 추가가 가능하지만 설정을 따로 변경하지는 않았었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1824&quot; data-origin-height=&quot;258&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcA2Qv/btsI00Wtaa6/BOkzKQTBAWiHx1KZZU2Vzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcA2Qv/btsI00Wtaa6/BOkzKQTBAWiHx1KZZU2Vzk/img.png&quot; data-alt=&quot;30기가 까지는 무료로 제공된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcA2Qv/btsI00Wtaa6/BOkzKQTBAWiHx1KZZU2Vzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcA2Qv%2FbtsI00Wtaa6%2FBOkzKQTBAWiHx1KZZU2Vzk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1824&quot; height=&quot;258&quot; data-origin-width=&quot;1824&quot; data-origin-height=&quot;258&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;30기가 까지는 무료로 제공된다.&lt;/figcaption&gt;
&lt;/figure&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;br /&gt;여분의 4기가는 추후 CI/CD 를 구축하면서 1. code Deploy관련된 파일과 설치가 이루어지고, 2. 운영하면서 발생하는 여러 로그 파일들과 3. 스왑메모리로 3기가를 할당했기에 디스크 공간이 부족해진것이었다.&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;&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;바로 EC2 내리고 볼륨 관리자 EBS에서 시원하게 12기가를 추가해서 20기가를 맞춰주었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qngoJ/btsI0wu3HY9/WWT500vdBonjqXXlKz7oq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qngoJ/btsI0wu3HY9/WWT500vdBonjqXXlKz7oq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qngoJ/btsI0wu3HY9/WWT500vdBonjqXXlKz7oq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqngoJ%2FbtsI0wu3HY9%2FWWT500vdBonjqXXlKz7oq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;954&quot; height=&quot;306&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;306&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1652&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bztr7R/btsJovvIei3/lxPV1qKFAq7I1AKKQWmYu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bztr7R/btsJovvIei3/lxPV1qKFAq7I1AKKQWmYu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bztr7R/btsJovvIei3/lxPV1qKFAq7I1AKKQWmYu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbztr7R%2FbtsJovvIei3%2FlxPV1qKFAq7I1AKKQWmYu0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1652&quot; height=&quot;1024&quot; data-origin-width=&quot;1652&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(0902추가)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 거의 한달 정도가 지났는데 해당 Starving 문제는 해결되었다.&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;&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;오래 운영해오기도 했고 최근 돈을 들여서 새로운 디자이너분을 통해 새 디자인도 나온 만큼 내가 맡고있는 서버의 안정적인 운영이 뒷받침 되어줘야 한다고 생각하던 찰나에 여러번의 서버 이슈가 발생했고 매번 다른 오류를 뱉어내서 마음고생도 했지만&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;해결 과정을 통해서 JVM 의 구조나 여러 OOM을 직접 경험해보기도 하고 스레드 덤프를 확인해보기도 하면서 경험치가 쌓인것 같다.&lt;/p&gt;</description>
      <category>Dayner 프로젝트</category>
      <category>Ebs</category>
      <category>ec2 메모리 스왑</category>
      <category>ec2 모니터링</category>
      <category>hikaricp풀 사이즈 변경</category>
      <category>jvm 메모리 영역</category>
      <category>oom</category>
      <category>prometheus</category>
      <category>스레드 덤프</category>
      <category>오토스케일 조건 변경</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/208</guid>
      <comments>https://nstgic3.tistory.com/entry/%EB%B0%98%EB%85%84-%EA%B0%84%EC%9D%98-EC2-Spring-%EB%B0%B0%ED%8F%AC-%EC%9E%A5%EC%95%A0-%ED%95%B4%EA%B2%B0%EA%B8%B0#entry208comment</comments>
      <pubDate>Sat, 10 Aug 2024 16:51:15 +0900</pubDate>
    </item>
    <item>
      <title>자바 가비지 컬렉터(GC)의 발전; 시리얼 컬렉터부터 ZGC까지</title>
      <link>https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94-%EA%B0%80%EB%B9%84%EC%A7%80-%EC%BB%AC%EB%A0%89%ED%84%B0GC%EC%9D%98-%EB%B0%9C%EC%A0%84-%EC%8B%9C%EB%A6%AC%EC%96%BC-%EC%BB%AC%EB%A0%89%ED%84%B0%EB%B6%80%ED%84%B0-ZGC%EA%B9%8C%EC%A7%80</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바를 공부하다보면 가비지 컬렉터(GC)에 대해 자주 접하게 된다.&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;대부분 GC과정이 메모리 관리를 위해 사용된 객체를 해제하고 메모리 관리를 최적화 하기 위해서 여러 세대로 나누어 자주 접근하거나 다른 객체들에 의해 참조되는 객체들은 오래된 세대로 이동하여, 신세대에 비해 해제 빈도를 낮추는 전략을 사용한다. 정도로만 이해하고 있을 수 있는데,&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;JVM 밑바닥까지 파헤치기' 라는 책을 읽으며&lt;/span&gt; GC의 작동 원리는 이보다 훨씬 더 복잡하고 여러 과정을 거쳐서 발전해왔음을 확인할 수 있었다.&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;&amp;nbsp;따라서 이번 포스팅에서는 용어와 알고리즘을 정리한후에 클래식 가비지 컬렉터의 특성과 종류를 시작으로 ZGC나 쉐넌 도어같은 최신 가비지 컬렉션 기술까지 특성 위주로 설명을 해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;용어 - Stop the world(STW)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어에서 알수 있다싶이 가비지 컬렉션을 수행하기 위해 JVM이 애플리케이션의 모든 스레드를 일시 중지시키는 현상&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;&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;가비지 컬렉션 중에는 모든 객체의 접근성을 파악하고 메모리를 재배치 또는 해제해야 하기 때문에 애플리케이션 스레드가 동시에 실행되면 메모리 일관성 및 정확성 문제가 발생할 수 있기 때문에 정지를 하게 된다.&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;가비지 컬렉터의 종류, 힙의 크기 및 복잡성, 시스템의 하드웨어 성능에 따라 달라진다.&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;최신의 가비지 컬렉터들은 STW의 영향을 줄이기 위해 점진적 컬렉션을 통해 STW를 짧게 유지하는 경우(G1), ZGC와 셰넌도어의 경우에는 애플리케이션 스레드가 실행 중인 동시에 수행해서 STW를 극단적으로 줄인다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마크-컴팩트(Mark Compact) 알고리즘&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;마크-컴팩트&lt;/b&gt; 알고리즘은 메모리 내의 객체들을 '마킹' 단계와 '컴팩션' 단계를 거쳐 관리한다.&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;마킹 단계&lt;br /&gt;&lt;/b&gt;루트 객체에서 시작하여 접근 가능한 모든 객체를 마킹하여 활성 객체(사용 중인 객체)를 식별한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴팩션 단계&lt;br /&gt;&lt;/b&gt;마킹된 객체들을 메모리에 연속된 할당하여 메모리 내의 파편화를 줄인다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용된 GC: &lt;/b&gt;&lt;b&gt;Serial GC, &lt;/b&gt;&lt;b&gt;Parallel Compacting GC&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마크-스윕(Mark Sweep) 알고리즘&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;마크-스윕&lt;/b&gt; 알고리즘은 메모리를 회수하려는 알고리즘이다.&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;마킹 단계&lt;br /&gt;&lt;/b&gt;마크-컴팩트와 마찬가지로 활성 객체를 식별하기 위해 루트 객체에서 시작하여 접근 가능한 모든 객체를 마킹한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스윕 단계&lt;br /&gt;&lt;/b&gt;마킹되지 않은 객체들(가비지)을 메모리에서 제거하고, 그 공간을 자유 공간 목록에 추가한다.&lt;br /&gt;마크- 컴패트와는 다르게 파편화가 발생할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용된 GC&lt;/b&gt;: &lt;b&gt;Concurrent Mark-Sweep (CMS) GC, &lt;/b&gt;&lt;b&gt;Parallel Scavenge GC&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클래식 가비지 컬렉터&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;자바 초기 버전에서 사용&lt;/b&gt;되던 가비지 컬렉션 방식을 지칭하며 단순하고 직관적인 알고리즘을 이용하여 메모리의 할당을 해제한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2146&quot; data-origin-height=&quot;1214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHgLvo/btsIHUooj4s/XkqLCIQQr5qBFwuLhMlxF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHgLvo/btsIHUooj4s/XkqLCIQQr5qBFwuLhMlxF1/img.png&quot; data-alt=&quot;위 그림과 함께 보면 이해가 쉽다. 책 내용 발췌(근데 열심히 그린)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHgLvo/btsIHUooj4s/XkqLCIQQr5qBFwuLhMlxF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHgLvo%2FbtsIHUooj4s%2FXkqLCIQQr5qBFwuLhMlxF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2146&quot; height=&quot;1214&quot; data-origin-width=&quot;2146&quot; data-origin-height=&quot;1214&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;위 그림과 함께 보면 이해가 쉽다. 책 내용 발췌(근데 열심히 그린)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 시리얼 가비지 컬렉터 (Serial GC) - JDK 1.0&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;단일 스레드&lt;/span&gt;를 사용하여 수행하고 힙의 Young Generation에서 객체를 대상으로 &lt;b&gt;마크-컴팩트(Mark-Compact) 방식&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;특징&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;작은 힙 사이즈 또는 단일 처리 코어에서 효과적&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;단점&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;'Stop-the-World'가 발생하여 모든 애플리케이션 스레드가 가비지 컬렉션 동안 중단됨&lt;/li&gt;
&lt;li&gt;큰 힙 또는 멀티 코어 환경에서 성능 저하가 발생할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 병렬 가비지 컬렉터 (Parallel GC) - JDK 1.4&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;여러 스레드&lt;/span&gt;를 사용하여 Young Generation의 가비지 컬렉션을 병렬로 수행하고 멀티 프로세서 시스템에서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;처리량을 최적화하는 데 유리&lt;/span&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;특징&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;처리량(throughput) 최적화에 초점을 맞춤&lt;/li&gt;
&lt;li&gt;'Stop-the-World' 이벤트 발생&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 data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&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;여러 스레드를 사용하므로 CPU 자원 사용량이 높음&lt;/li&gt;
&lt;li&gt;리얼타임 애플리케이션에서는 예측 불가능한 중단 시간으로 인해 문제가 발생할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Concurrent Mark-Sweep (CMS) 가비지 컬렉터&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응답 시간을 적게 가져가기 때문에 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;응답시간을 중시하는 애플리케이션에 적합&lt;/span&gt;하고 Old Generation의 메모리를 대상으로 &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;span style=&quot;background-color: #f6e199;&quot;&gt;객체를 마킹하고 삭제하는 작업을 애플리케이션 스레드가 실행 중일 때 동시에 수행&lt;/span&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;특징&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;Old Generation에서 동시성을 지원하여 애플리케이션의 중단 시간을 줄임&lt;/li&gt;
&lt;li&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 data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&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;클래식 GC 방식들은 각각의 애플리케이션 유형과 환경에 따라 선택적으로 사용되는데 예를 들어, 처리량을 중시하는 배치 처리 시스템에서는 병렬 가비지 컬렉터가, 응답 시간이 중요한 인터랙티브 애플리케이션에서는 CMS가 더 적합할 수 있다.&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모던 가비지 컬렉터&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;멀티스레딩과 더 나은 동시성 지원을 통해 성능 저하를 최소화&lt;/b&gt;하는데에 초점이 맞춰져있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2174&quot; data-origin-height=&quot;1210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/InmVW/btsJaKMIYdW/k32El5u5d8P7yJ4ZPDSwU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/InmVW/btsJaKMIYdW/k32El5u5d8P7yJ4ZPDSwU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/InmVW/btsJaKMIYdW/k32El5u5d8P7yJ4ZPDSwU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FInmVW%2FbtsJaKMIYdW%2Fk32El5u5d8P7yJ4ZPDSwU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2174&quot; height=&quot;1210&quot; data-origin-width=&quot;2174&quot; data-origin-height=&quot;1210&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;G1 Garbage Collector&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;G1(Garbage-First) 컬렉터&lt;/b&gt;는 JDK 7 에서 소개되었고, JDK 9부터는 기본 가비지 컬렉터로 설정되었다.&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;힙을 여러 영역(Region)으로 나누어서&lt;/b&gt; 메모리 관리를 더욱 효율적으로 만들어주며, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;가비지 컬렉션 시간을 예측 가능&lt;/span&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;특징&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;기억 집합(Remembered Set)과 쓰기 장벽(Write Barrier)을 사용하여 애플리케이션과 GC의 상호작용 최소화.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&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;컬렉션 시간을 줄여 성능 저하 최소화.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점:&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;.&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;Z Garbage Collector (ZGC)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ZGC는 JDK 11에서 실험적 기능으로 도입되었다가, 무척 최근인 JDK 15에서 프로덕션이 준비가 되었다.&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;span style=&quot;background-color: #f6e199;&quot;&gt;매우 큰 힙 크기를 효과적으로 처리&lt;/span&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;특징&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;컬러 포인터와 로드 배리어 기술 사용하여 'Stop-the-World' 지연을 극단적으로 줄임&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&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;&lt;b&gt;고성능 실시간 시스템&lt;/b&gt;에 적합.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; Shenandoah&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Shenandoah는 JDK 12에서 실험적기능으로 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;도입되었다가,&lt;/span&gt; JDK 14에서 적용이 되었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;응답 시간을 최소화하는 것에 초점이 맞춰져있어서 G1과 유사한&lt;b&gt; 여러 영역으로 나뉜 메모리 관리 방식&lt;/b&gt;을 사용하지만, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;가비지 컬렉션과 애플리케이션 작업을 더욱 동시에 수행할 수 있도록 설계&lt;/span&gt;되었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;중단 없는 가비지 컬렉션을 목표로 하며, 이 과정에서 '복사 정리'(Brooks Pointers) 기술을 사용하여&lt;span style=&quot;background-color: #f6e199;&quot;&gt; 가비지 컬렉션 중에도 메모리 접근을 관리&lt;/span&gt;한다.&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징&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;G1과 유사한 지역화된 메모리 관리 방식.&lt;/li&gt;
&lt;li&gt;동시성을 극대화하는 설계.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&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;Brooks Pointers 기술을 사용하여 GC 중에도 메모리 접근 관리.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&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;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;사실 이 책을 읽고 이 글을 정리하는 과정에 있어서 각 가비지컬렉터에 대한 내용이 추상적이고 복잡한 느낌이 들어서 오랜 시간이 걸렸지만 위에 하이라이트로 작성해놓은 각 가비지 컬렉션들의 목적을 중심으로 이해하려 노력해보니 기술이나 상황에 따라서 필요한 부분으로 점차 진화가 되어갔음을 느낄수 있었다.&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;또한 G1, ZGC, Shenandoah 같은 최신 기술들이 어떻게 Stop-the-World 현상을 최소화하는지, 그리고 왜 그러한 기술적 진화가 필요했는지에 대한 이유를 최근 프로젝트에서 진행하고 있는 멀티 모듈화나 대용량 실시간 데이터 전송 기법 등의 기술적 요구사항에 의해서 발생되었구나~ 라는 것도 이해할수 있었다.&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;의문사하는 서버 해결기&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724216069352&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;반년 간의 EC2 Spring 배포 Thread Stravation 장애 해결기&quot; data-og-description=&quot;목차&amp;nbsp;개요 및 프로젝트 특징(조건)작년 이맘때에 샀던 도메인의 만료로 인해 갱신도 했으니 가운영 반년, 실제 운영 1년이 넘어가는 시점이다.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;약 22회의 기능 추가/수정 으로 인한 Deploy, 와&quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/%EB%B0%98%EB%85%84-%EA%B0%84%EC%9D%98-EC2-Spring-%EB%B0%B0%ED%8F%AC-%EC%9E%A5%EC%95%A0-%ED%95%B4%EA%B2%B0%EA%B8%B0&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/%EB%B0%98%EB%85%84-%EA%B0%84%EC%9D%98-EC2-Spring-%EB%B0%B0%ED%8F%AC-%EC%9E%A5%EC%95%A0-%ED%95%B4%EA%B2%B0%EA%B8%B0&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/1VZQ4/hyWSiPLPly/aIhjV4kKN2SOK3cVFrhURK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/brz0IW/hyWSeGBSCE/b83lzV9zs7FlT0AgauKbzK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bfbXIW/hyWSjA7erm/47cGAVAyVCBLsKtE8qojnk/img.png?width=1398&amp;amp;height=1206&amp;amp;face=0_0_1398_1206&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EB%B0%98%EB%85%84-%EA%B0%84%EC%9D%98-EC2-Spring-%EB%B0%B0%ED%8F%AC-%EC%9E%A5%EC%95%A0-%ED%95%B4%EA%B2%B0%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/%EB%B0%98%EB%85%84-%EA%B0%84%EC%9D%98-EC2-Spring-%EB%B0%B0%ED%8F%AC-%EC%9E%A5%EC%95%A0-%ED%95%B4%EA%B2%B0%EA%B8%B0&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/1VZQ4/hyWSiPLPly/aIhjV4kKN2SOK3cVFrhURK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/brz0IW/hyWSeGBSCE/b83lzV9zs7FlT0AgauKbzK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bfbXIW/hyWSjA7erm/47cGAVAyVCBLsKtE8qojnk/img.png?width=1398&amp;amp;height=1206&amp;amp;face=0_0_1398_1206');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;반년 간의 EC2 Spring 배포 Thread Stravation 장애 해결기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;목차&amp;nbsp;개요 및 프로젝트 특징(조건)작년 이맘때에 샀던 도메인의 만료로 인해 갱신도 했으니 가운영 반년, 실제 운영 1년이 넘어가는 시점이다.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;약 22회의 기능 추가/수정 으로 인한 Deploy, 와&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>G1</category>
      <category>zgc</category>
      <category>가비지 컬렉션</category>
      <category>셰넌도어</category>
      <category>클래식 모던 가비지컬렉터</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/207</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94-%EA%B0%80%EB%B9%84%EC%A7%80-%EC%BB%AC%EB%A0%89%ED%84%B0GC%EC%9D%98-%EB%B0%9C%EC%A0%84-%EC%8B%9C%EB%A6%AC%EC%96%BC-%EC%BB%AC%EB%A0%89%ED%84%B0%EB%B6%80%ED%84%B0-ZGC%EA%B9%8C%EC%A7%80#entry207comment</comments>
      <pubDate>Sat, 20 Jul 2024 01:45:29 +0900</pubDate>
    </item>
    <item>
      <title>자바가상머신의 메모리 구조: JVM Runtime Data Area</title>
      <link>https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0-JVM-Runtime-Data-Area</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자바가 제공하는 메모리 관리는 할당과 해제를 하여 관리해야하는 다른 언어들과는 달리 개발자의 편의성 측면에서 많은 이점을 가져온다. 하지만 그 이면으로 내가 직접 관리를 하지 않기 때문에 GC 과정에 이상이 생길시에 원인을 분석하여 해결해야된다는 점이 있는데 이는 자바가상머신의 메모리에 대해서 알아보면 원인 분석 및 이해가 빨라질수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 이를 구조를 설명하고 구조별로 일어날만한 오류들을 정리를 해보려한다.&lt;s&gt;(고봉밥으로다가)&lt;/s&gt;&lt;/span&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;span&gt;들어가기에 앞서서 JVM 을 크게 나눠보자면 위에도 언급했던 힙 메모리를 관리하는 가비지 컬렉터, 자바 클래스를 메모리 영역(어디인지는 아래에 나올것이다.) 에 로드해주는 클래스 로더 시스템, JVM의 바이트 코드를 실행하는 실행 엔진으로 기능적 요소가 존재하고 이번에 설명할 메모리 영역이 나머지를 채워주고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biuLJo/btsIbPAZ8BC/v4KmNymgXFgkgKHy32w4dK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biuLJo/btsIbPAZ8BC/v4KmNymgXFgkgKHy32w4dK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biuLJo/btsIbPAZ8BC/v4KmNymgXFgkgKHy32w4dK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiuLJo%2FbtsIbPAZ8BC%2Fv4KmNymgXFgkgKHy32w4dK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;665&quot; height=&quot;499&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;한빛 미디어의 '이것이 자바다' 와 프로그래밍 인사이트의 'jvm 밑바닥까지 파헤치기' 를 읽고 정리하는 글이다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사전 지식&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1719242148300&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;JVM에서 자바 메서드와 네이티브 메서드 실행의 차이점&quot; data-og-description=&quot;목차&amp;nbsp;개요JVM의 메모리 구조 이해를 위한 글로 두 메서드의 실행 차이점을 알아본다.Java 9 이전보다 최근들어서는 자바로 쓰인 라이브러리의 종류도 많아져 잘 사용하지 않기에 사용이 적다. 이&quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/JVM%EC%97%90%EC%84%9C-%EC%9E%90%EB%B0%94-%EB%A9%94%EC%84%9C%EB%93%9C%EC%99%80-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%8B%A4%ED%96%89%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/JVM%EC%97%90%EC%84%9C-%EC%9E%90%EB%B0%94-%EB%A9%94%EC%84%9C%EB%93%9C%EC%99%80-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%8B%A4%ED%96%89%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bpi7hg/hyWoICsBP0/hqkk4nDSmly65NZ45kU2x1/img.png?width=800&amp;amp;height=797&amp;amp;face=0_0_800_797,https://scrap.kakaocdn.net/dn/bGGtPD/hyWrTbgfWS/TBGDE2H9u0amBtQmO3NBT0/img.png?width=800&amp;amp;height=797&amp;amp;face=0_0_800_797,https://scrap.kakaocdn.net/dn/coSjnS/hyWoIoVH40/BwEYgZ22TAnzkeEK4Rz52K/img.png?width=750&amp;amp;height=747&amp;amp;face=0_0_750_747&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/JVM%EC%97%90%EC%84%9C-%EC%9E%90%EB%B0%94-%EB%A9%94%EC%84%9C%EB%93%9C%EC%99%80-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%8B%A4%ED%96%89%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/JVM%EC%97%90%EC%84%9C-%EC%9E%90%EB%B0%94-%EB%A9%94%EC%84%9C%EB%93%9C%EC%99%80-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%8B%A4%ED%96%89%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bpi7hg/hyWoICsBP0/hqkk4nDSmly65NZ45kU2x1/img.png?width=800&amp;amp;height=797&amp;amp;face=0_0_800_797,https://scrap.kakaocdn.net/dn/bGGtPD/hyWrTbgfWS/TBGDE2H9u0amBtQmO3NBT0/img.png?width=800&amp;amp;height=797&amp;amp;face=0_0_800_797,https://scrap.kakaocdn.net/dn/coSjnS/hyWoIoVH40/BwEYgZ22TAnzkeEK4Rz52K/img.png?width=750&amp;amp;height=747&amp;amp;face=0_0_750_747');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;JVM에서 자바 메서드와 네이티브 메서드 실행의 차이점&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;목차&amp;nbsp;개요JVM의 메모리 구조 이해를 위한 글로 두 메서드의 실행 차이점을 알아본다.Java 9 이전보다 최근들어서는 자바로 쓰인 라이브러리의 종류도 많아져 잘 사용하지 않기에 사용이 적다. 이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;-&amp;nbsp; 자바는 다중 스레드를 지원하므로 스레드 마다 별도의 메모리를 가지는 경우(PC, 자바 메서드 스택, 네이티브 메서드 스택)도 있고 전체에 통용되는 메모리 공간(힙 메모리, 메서드 메모리)도 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;- 사람들이 흔히 말하는 자바는 힙과 스택으로 메모리가 구성되어있다~ 라는 말은 자바+네이티브 스택을 스택으로 자바힙과 네이티브힙을 힙으로 칭한다고 이해하면 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;프로그램 카운터 (PC)&lt;/span&gt;&lt;/h3&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;CPU 에서의 pc와 무척 유사하게도 하이퍼 스레딩을 지원하는 CPU에서 각 스레드 마다 독립적인 프로그램 카운터가 존재하는 것 처럼 JVM 에서도 스레드 마다 각 스레드의 현재 실행하고 있는 코드 위치를 저장하고 있다.&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;다만 차이점이라고 하면 CPU의 경우에는 실행중인 명령어의 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;물리적인 메모리 주소&lt;/span&gt;를 표기하고 JVM의 경우에는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;자바 바이트코드의 인덱스를 표기&lt;/span&gt;하고 있다는 차이점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;JVM의 인터프리터는 pc 값을 수정하여 다음 실행할 자바 바이트 코드를 명시하고 JIT 컴파일러는 해당 pc 를 활용해서 실행을 한다.&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;- 스레드가 네이티브 메서드를 실행시킬때는 undefined 값을 지니게 된다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;단일값이며, 위치를 표기하고 있기에 OOM 에러의 조건이 명시되어있지 않다.&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자바 가상머신 스택&lt;/span&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;b&gt;정의&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PC 와 마찬가지로 스레드 프라이빗 하며 메서드 호출에 관련된 정보를 프레임에 담아 추가하는 방식으로 저장한다.&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;로컬 변수 배열 (Local Variables Array)&lt;/b&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;일반적으로 슬롯 하나의 크기는 32비트로 double,long 타입처럼 길이가 64비트인것은 슬롯 2칸을 차지한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오퍼랜드 스택 (Operand Stack)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JVM 명령어가 연산을 수행할 때 사용하는 스택&lt;/li&gt;
&lt;li&gt;피연산자를 일시적으로 저장하고, 연산 결과를 저장합니다.&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택의 크기 또한 메서드가 컴파일될 때 결정됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메서드 호출과 복귀 주소 (Return Address)&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;실행 시 상수 풀 레퍼런스 (Reference to Runtime Constant Pool)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 클래스의 런타임 상수 풀에 대한 참조를 포함하고 런타임시에 JVM 이 참조한다.&lt;/li&gt;
&lt;li&gt;상수 풀에는 클래스 파일에 포함된 리터럴 상수와 메서드, 필드, 클래스 참조 등이 저장된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;간단한 바이트 코드를 보면서 이해해보자(오퍼랜드)&lt;br /&gt;&lt;/b&gt;이외에도 로컬변수도 저장하고 상수풀도 이용하는 예제를 보려면 아래를 읽어보자&lt;/p&gt;
&lt;figure id=&quot;og_1719651447298&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;자바가상머신 스택 이해를 위한 바이트코드 예시&quot; data-og-description=&quot;개요JVM의 메모리 영역 구성 요소중 하나인 자바가상머신 스택에 대한 이해를 위해 예제를 통해 각 구역에 데이터가 할당되고 해제되는것을 javap 명령어를 통해 알아본다.&amp;nbsp;&amp;nbsp;*해당 포스팅에서 나&quot; data-og-host=&quot;nstgic3.tistory.com&quot; data-og-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C&quot; data-og-url=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cwSAaY/hyWrUCiI6q/xzXImHlt0AY4Ht8wJr8T4k/img.png?width=800&amp;amp;height=803&amp;amp;face=0_0_800_803,https://scrap.kakaocdn.net/dn/cj1Ve5/hyWrTwEQ2O/fwCxx0GUnJ4HT4Kqka31M1/img.png?width=800&amp;amp;height=803&amp;amp;face=0_0_800_803,https://scrap.kakaocdn.net/dn/ytUAN/hyWrVur41x/vyeLK9eklLIXm4rxN0NKEk/img.png?width=1694&amp;amp;height=486&amp;amp;face=0_0_1694_486&quot;&gt;&lt;a href=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cwSAaY/hyWrUCiI6q/xzXImHlt0AY4Ht8wJr8T4k/img.png?width=800&amp;amp;height=803&amp;amp;face=0_0_800_803,https://scrap.kakaocdn.net/dn/cj1Ve5/hyWrTwEQ2O/fwCxx0GUnJ4HT4Kqka31M1/img.png?width=800&amp;amp;height=803&amp;amp;face=0_0_800_803,https://scrap.kakaocdn.net/dn/ytUAN/hyWrVur41x/vyeLK9eklLIXm4rxN0NKEk/img.png?width=1694&amp;amp;height=486&amp;amp;face=0_0_1694_486');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;자바가상머신 스택 이해를 위한 바이트코드 예시&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요JVM의 메모리 영역 구성 요소중 하나인 자바가상머신 스택에 대한 이해를 위해 예제를 통해 각 구역에 데이터가 할당되고 해제되는것을 javap 명령어를 통해 알아본다.&amp;nbsp;&amp;nbsp;*해당 포스팅에서 나&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nstgic3.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719302503467&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Example {
    public static void main(String[] args) {
        System.out.println(&quot;Hello, World!&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;658&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dAApc0/btsIbpp9bto/15XsXUmepZT76UonUL4Kyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dAApc0/btsIbpp9bto/15XsXUmepZT76UonUL4Kyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dAApc0/btsIbpp9bto/15XsXUmepZT76UonUL4Kyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdAApc0%2FbtsIbpp9bto%2F15XsXUmepZT76UonUL4Kyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1750&quot; height=&quot;658&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;b&gt;getstatic #7&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;System.out 정적 필드를 가져와 오퍼랜드 스택에 푸시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오퍼랜드 스택: [System.out]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ldc #13&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;상수 풀에서 문자열 &quot;Hello, World!&quot;를 가져와 오퍼랜드 스택에 푸시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오퍼랜드 스택: [System.out, &quot;Hello, World!&quot;]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;invokevirtual #19&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;println 메서드를 호출&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;invokevirtual은 System.out 객체의 println 메서드를 호출하고 해당 오퍼랜드 스택에서 objectref와 인수(&quot;Hello, World!&quot;)를 꺼내고 새로운 프레임을 생성하여 메서드를 실행한다.&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;return&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;b&gt;변경 후&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;스택 형태를 띄고 있기 때문에 스레드에서 요청한 값이 가상머신 허용 공간보다 큰 경우에는 StackOverFlow 오류를, 스택 용량을 동적으로 할당 가능한 가상 머신(클래식 VM)에서는 여유 메모리가 충분하지 않다면 OutOfMemory 오류를 발생시킨다.&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;네이티브 메서드 스택 영역&lt;/span&gt;&lt;/h3&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;pc, jvm 스택 영역과 더불어 스레드마다 할당이 되어있는 메모리 영역이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바가상머신이 자바가 아닌 다른 언어로 작성된 네이티브 메서드들을 실행하기 위해 사용하는 메모리 영역으로 주로 C나 C++로 작성되며 JVM에 의해 직접 관리되고 JNI(Java Native Interface)를 통해 자바 코드와 상호작용한다.&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;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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;발생할수 있는 오류&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바 가상머신 스택과 동일하게 스택 형태를 띄고 있기 때문에 스레드에서 요청한 값이 가상머신 허용 공간보다 큰 경우에는 StackOverFlow 오류를, 스택 용량을 동적으로 할당 가능한 가상 머신(클래식 VM)에서는 여유 메모리가 충분하지 않다면 OutOfMemory 오류를 발생시킨다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메서드 영역&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;위에 설명했던 영역과는 다르게 모든 스레드가 공유하는 메모리 공간으로 클래스와 관련된 메타데이터 들이 포함된다.&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;저 메타데이터들이 자바 8을 기준으로 영구영역에서 메타스페이스로 변경되었다는 것이 자주 설명이 되고는 한다. 간단히 설명하면 자바가 주력으로 하던 핫스팟에서는 문자열이나 정적변수를 저장하는 메서드 영역을 영구세대에 할당했기에 메모리의 한계가 존재했는데 JRockit에는 메모리 최댓값의 한계가 없었고 이는 가상 머신에 따라서 성능 차이와 메모리 관리의 번거로움을 주었었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;따라서 이를 해결하기 위해서 따로 메타스페이스라는 영역을 만들고 메모리 제약을 없애주었다. 라고 간단히 알고있고 이에 대해서 JSR 을 읽던 패치 노트를 이용하여 나중에 포스팅 해보겠다.&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;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;JIT 컴파일된 코드:&lt;/b&gt; Just-In-Time(JIT) 컴파일러가 생성한 네이티브 코드를 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;발생할수 있는 오류&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;메서드 영역이 꽉 차면 OOME 가 발생할수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;런타임 상수 풀&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정의&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;각 클래스 또는 인터페이스의 메타데이터 내에 포함된 상수 풀&lt;/b&gt;로, 클래스 파일이 JVM에 의해 생성자로 인해 생성되고 가상머신 위로 로드될 때 저장된다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;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; 클래스 파일의 상수 풀(Constant Pool)에서 가져온 것을 클래스별로 관리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동적 상수 풀:&lt;/b&gt; 실행 중에 새로운 상수가 추가될 수 있으며, String.intern() 메서드를 통해 새로운 문자열 상수를 추가 가능&lt;/li&gt;
&lt;/ul&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;이는 메서드 영역에 포함되어있기 때문에 메서드 영역을 넘어가는 메모리를 할당하려하면 OOME가 발생한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다이렉트 메모리&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;네이티브 메서드 스택 영역하고 함께 네이티브 메모리를 구성하고 있다는 공통점이 있어 바로 아래에 설명을 해본다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;정의&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&amp;nbsp;java.nio 패키지의 다이렉트 버퍼를 통해 사용되는 메모리 영역으로 JVM 힙이 아닌 네이티브 메모리에 할당된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;*다이렉트 버퍼는 네이티브 메모리에 직접 접근하여 데이터를 읽고 쓰므로, 일반적인 힙 메모리보다 빠른 I/O 처리가 가능하다.&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;다이렉트 버퍼를 이용해 네이티브 메모리를 사용하여 I/O 성능 변화를 모니터링하는 포스팅&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1719657507997&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;blog&quot; data-og-title=&quot;Java Native Memory Tracking&quot; data-og-description=&quot;Java Native Memory TrackingDMA자바에서도 DirectBuffer를 이용해서 JVM Heap이 아닌 Native 메모리를 사용하고 DMA(Direct Memory Access)의 장점을 활용할 수 있다. 구체적인 사용법 등 자세한 내용은 Java NIO Direct Buffe&quot; data-og-host=&quot;homoefficio.github.io&quot; data-og-source-url=&quot;https://homoefficio.github.io/2020/04/09/Java-Native-Memory-Tracking/&quot; data-og-url=&quot;http://homoefficio.github.io/2020/04/09/Java-Native-Memory-Tracking/index.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/banOvI/hyWrY5OzA6/7Kp7woAJ4WKZc5TFFRfiqK/img.png?width=876&amp;amp;height=877&amp;amp;face=0_0_876_877,https://scrap.kakaocdn.net/dn/7Sr6u/hyWrSkdd4o/gmkDmRnvmB8kShKV8ETIP1/img.png?width=859&amp;amp;height=825&amp;amp;face=0_0_859_825,https://scrap.kakaocdn.net/dn/cVYg2T/hyWrUvzJO7/k4c9tjgMQZs7tsTIGAEu81/img.png?width=581&amp;amp;height=290&amp;amp;face=0_0_581_290,https://scrap.kakaocdn.net/dn/IyNcU/hyWrYSiU72/jPPS3kKB1nS6mchvKEarWK/img.png?width=876&amp;amp;height=877&amp;amp;face=0_0_876_877&quot;&gt;&lt;a href=&quot;https://homoefficio.github.io/2020/04/09/Java-Native-Memory-Tracking/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://homoefficio.github.io/2020/04/09/Java-Native-Memory-Tracking/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/banOvI/hyWrY5OzA6/7Kp7woAJ4WKZc5TFFRfiqK/img.png?width=876&amp;amp;height=877&amp;amp;face=0_0_876_877,https://scrap.kakaocdn.net/dn/7Sr6u/hyWrSkdd4o/gmkDmRnvmB8kShKV8ETIP1/img.png?width=859&amp;amp;height=825&amp;amp;face=0_0_859_825,https://scrap.kakaocdn.net/dn/cVYg2T/hyWrUvzJO7/k4c9tjgMQZs7tsTIGAEu81/img.png?width=581&amp;amp;height=290&amp;amp;face=0_0_581_290,https://scrap.kakaocdn.net/dn/IyNcU/hyWrYSiU72/jPPS3kKB1nS6mchvKEarWK/img.png?width=876&amp;amp;height=877&amp;amp;face=0_0_876_877');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Java Native Memory Tracking&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Java Native Memory TrackingDMA자바에서도 DirectBuffer를 이용해서 JVM Heap이 아닌 Native 메모리를 사용하고 DMA(Direct Memory Access)의 장점을 활용할 수 있다. 구체적인 사용법 등 자세한 내용은 Java NIO Direct Buffe&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;homoefficio.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;발생할수 있는 오류&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사용되는 메모리의 영역합이 물리 메모리의 한계를 넘는다면 이또한 OutOfMemory(OOME) 가 발생한다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;추가&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가상머신 런타임에도 들어가지 않고 NIO의 다이렉트 버퍼를 쓰지 않으면 고려안해도 될 사항인가? 라고 의문을 가졌지만 삼성sds 기술블로그에서 java환경에서 메모리 부족이 자주 일어나는 상황을 설명한 케이스를 잘 읽다가 내 생각이 틀렸음을 깨달았다. 실제환경에서는 모니터링시의 기준책정 시에도 들어가는 중요한 요소 였다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1770&quot; data-origin-height=&quot;584&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5iBUH/btsIinLn2gz/0BZKnUpQlyfT0DSDmKsk0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5iBUH/btsIinLn2gz/0BZKnUpQlyfT0DSDmKsk0k/img.png&quot; data-alt=&quot;https://m.post.naver.com/viewer/postView.nhn?volumeNo=23726161&amp;amp;amp;memberNo=36733075&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5iBUH/btsIinLn2gz/0BZKnUpQlyfT0DSDmKsk0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5iBUH%2FbtsIinLn2gz%2F0BZKnUpQlyfT0DSDmKsk0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1770&quot; height=&quot;584&quot; data-origin-width=&quot;1770&quot; data-origin-height=&quot;584&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://m.post.naver.com/viewer/postView.nhn?volumeNo=23726161&amp;amp;memberNo=36733075&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자바 힙&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바 어플리케이션이 사용 가능한 가장 큰 메모리 영역이기도 하면서 이 또한 모든 스레드가 공유하며 가상 머신이 구동시에 만들어진다는 특징을 가지고 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바 코드에 짜여져 있는 모든 객체의 인스턴스가 이 곳에 저장이 되고 가비지 컬렉터가 관리 하는 메모리 영역이라는 특징이 있다. 이 공통 부분은 여러 스레드에서 나누어 쓴다는 것 때문에 객체 할당 효율을 높이려고 일종의 버퍼를 구현해두는데 이는 힙의 영역을 잘게 나누어서 다발적으로 들어오는 메모리 할당과 해제 속도를 증가 시켰다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;GC 가비지 컬렉터와 TLAB 스레도 로컬 할당 버퍼에 대해서는 다룰 내용이 많아서 따로 포스팅을 통하려고 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;발생할수 있는 오류&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바 힙의 경우에도 크기를 사용자가 지정하거나 동적으로 확장 가능하게 구현할 수도 있는데 역시나 최대 할당 공간이 늘어나면 OutOfMemory(OOME) 가 발생한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바 애플리케이션 동작에 있어서 OOME 가 가장 많이 발생하는 영역이라고도 한다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;추후에 힙 덤프 스냅샷을 통해서 오버플로우를 의도적으로 만들어보고 의도적으로 만들어진 객체(메모리 누수가 발생한)로 부터 GC의 루트까지의 참조를 살펴보면서 추적하는 과정에 대해서도 따로 포스팅을 해볼 예정이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바의 가상머신을 구성하고 있는 메모리들에 대해서 알아보고 간단하게 특징에 대해서 전체적으로 확인해보는 시간을 가졌다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사실 이번 포스팅을 작성하면서 거의 2주 가까이 걸렸던것 같은데 이내용 저내용 담다보니 글의 방향도 규모도 좀 커진 감이 있었다. 붙여놓았던 내용(가비지 컬렉팅이나 구체적인 오류 발생상황들)을 다 덜어내고 작은 포스팅 덩어리로 모듈화(?)를 해서 마무리를 할 생각이다.&lt;/p&gt;</description>
      <category>Java</category>
      <category>jvm 스택 메모리</category>
      <category>네이티브 메서드 스택 메모리</category>
      <category>메서드 영역</category>
      <category>자바 가상머신 메모리 구조</category>
      <category>프로그램 카운터</category>
      <category>힙 메모리</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/203</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0-JVM-Runtime-Data-Area#entry203comment</comments>
      <pubDate>Thu, 4 Jul 2024 23:28:22 +0900</pubDate>
    </item>
    <item>
      <title>DNS, TCP, TLS 통신에 대한 WireShark를 이용한 패킷 분석</title>
      <link>https://nstgic3.tistory.com/entry/DNS-TCP-TLS-%ED%86%B5%EC%8B%A0%EC%97%90-%EB%8C%80%ED%95%9C-WireShark%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%ED%8C%A8%ED%82%B7-%EB%B6%84%EC%84%9D</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 블로그 포스트에서는 Wireshark를 사용하여 pc 에서 &lt;a href=&quot;http://www.naver.com&quot;&gt;www.naver.com&lt;/a&gt;으로의&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;네트워크 트래픽 캡처&lt;/span&gt;를 통해 TCP와 TLS 통신 시퀀스를 상세히 분석해보겠습니다.&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;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;DNS 쿼리와 응답&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TCP 3way handshake (open)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TLS client hello &amp;amp; handshake&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TCP 4way handshake (close)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DNS 쿼리&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1195&quot; data-origin-height=&quot;73&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qFfEa/btsIhKUZyJh/Xwi2RH4nC11unUUKd0SkRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qFfEa/btsIhKUZyJh/Xwi2RH4nC11unUUKd0SkRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qFfEa/btsIhKUZyJh/Xwi2RH4nC11unUUKd0SkRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqFfEa%2FbtsIhKUZyJh%2FXwi2RH4nC11unUUKd0SkRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1195&quot; height=&quot;73&quot; data-origin-width=&quot;1195&quot; data-origin-height=&quot;73&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프레임 541&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 A가 DNS 서버 B에 &lt;a href=&quot;http://www.naver.com의&quot;&gt;www.naver.com의&lt;/a&gt; A 레코드를 요청&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.naver.com에&quot;&gt;www.naver.com에&lt;/a&gt; 대한 &lt;b&gt;IPv4 주소&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;프레임 542&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 A가 DNS 서버 B에 &lt;a href=&quot;http://www.naver.com의&quot;&gt;www.naver.com의&lt;/a&gt; HTTPS 레코드를 요청&lt;br /&gt;도메인 이름에 대한 HTTPS 서비스 정보를 얻기 위함&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;프레임 543&lt;br /&gt;&lt;/b&gt;DNS 서버 B가 HTTPS 레코드 요청에 대해 응답&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응답에는 &lt;a href=&quot;http://www.naver.com이&quot;&gt;www.naver.com이&lt;/a&gt; &lt;a href=&quot;http://www.naver.com.nheos.com의&quot;&gt;www.naver.com.nheos.com의&lt;/a&gt; CNAME임을 알려주고, SOA 레코드도 포함되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;CNAME 레코드란?&lt;br /&gt;요청된 도메인이 다른 도메인으로 매핑될 때 사용되며, DNS 서버가 이를 통해 정확한 IP 주소를 찾도록 도와준다.&lt;/li&gt;
&lt;/ul&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;프레임 544&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DNS 서버 B가 A 레코드 요청에 대해 응답&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.naver.com의&quot;&gt;www.naver.com의&lt;/a&gt; 여러 A 레코드가 포함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;A 레코드란?&lt;br /&gt;도메인 이름을 실제로 접근할 수 있는 IP 주소로 변환하는 역할, 모두 도메인으로의 접속이 가능하기 때문에 하나의 경로가 다운되더라도 다른 경로를 통해 접근이 가능하다.&lt;/li&gt;
&lt;/ul&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 해당 dns로의 접속 목적지는 현재 내가 사용하고 있는 인터넷제공자인 LG 사의 &lt;b&gt;네임서버&lt;/b&gt;였고 출발지는 내 pc의 ip 가 아닌 홈라우터(wifi 공유기)의 ip 가 할당되어있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-06-30 오후 4.16.59.png&quot; data-origin-width=&quot;2154&quot; data-origin-height=&quot;606&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VwH1L/btsIhdDn3Tx/QQbryeLe7J7Ru74DSP1R40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VwH1L/btsIhdDn3Tx/QQbryeLe7J7Ru74DSP1R40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VwH1L/btsIhdDn3Tx/QQbryeLe7J7Ru74DSP1R40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVwH1L%2FbtsIhdDn3Tx%2FQQbryeLe7J7Ru74DSP1R40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2154&quot; height=&quot;606&quot; data-filename=&quot;스크린샷 2024-06-30 오후 4.16.59.png&quot; data-origin-width=&quot;2154&quot; data-origin-height=&quot;606&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TCP 3 - way handshake (open)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2612&quot; data-origin-height=&quot;114&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QP4j0/btsIixm3VUY/DDoFiOdbKhUX1uri1e4ESk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QP4j0/btsIixm3VUY/DDoFiOdbKhUX1uri1e4ESk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QP4j0/btsIixm3VUY/DDoFiOdbKhUX1uri1e4ESk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQP4j0%2FbtsIixm3VUY%2FDDoFiOdbKhUX1uri1e4ESk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2612&quot; height=&quot;114&quot; data-origin-width=&quot;2612&quot; data-origin-height=&quot;114&quot;/&gt;&lt;/span&gt;&lt;/figure&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;프레임 545&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 A가 서버 B에 TCP SYN 패킷을 보냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP 연결을 시작하기 위함 (3-way 핸드셰이크의 첫 단계)&lt;b&gt;&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;b&gt;목적지 포트&lt;/b&gt;: 443 (HTTPS)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;플래그&lt;/b&gt;: SYN&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순서 번호&lt;/b&gt;: 0&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MSS&lt;/b&gt;: 1460 (Maximum Segment Size)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 연결에서 각 세그먼트가 가질 수 있는 최대 바이트 수를 정의하는 MSS 를 보내주어 패킷 손실 가능성을 줄인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로 인해서 해당 포스트에 IP 단편화도 넣고 싶었지만 일어나는걸 모니터링 하지는 못했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.ietf.org/rfc/rfc793.txt&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.ietf.org/rfc/rfc793.txt&lt;/a&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;프레임 546&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 B가 클라이언트 A에 TCP SYN-ACK 패킷을 보냄&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;출발지 포트&lt;/b&gt;: 443 (HTTPS)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;목적지 포트&lt;/b&gt;: 50409&lt;/li&gt;
&lt;li&gt;&lt;b&gt;플래그&lt;/b&gt;: SYN, ACK&lt;/li&gt;
&lt;/ul&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;프레임 547&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 A가 서버 B에 TCP ACK 패킷을 보냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버의 SYN-ACK 패킷에 응답하여 3-way 핸드셰이크를 완료하기 위함&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;출발지 포트&lt;/b&gt;: 50409&lt;/li&gt;
&lt;li&gt;&lt;b&gt;목적지 포트&lt;/b&gt;: 443 (HTTPS)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;플래그&lt;/b&gt;: ACK&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TLS handshake (open)&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1652&quot; data-origin-height=&quot;143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QYhLK/btsIizkVplo/eK2OsdsmPpivkKDLP1D1g0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QYhLK/btsIizkVplo/eK2OsdsmPpivkKDLP1D1g0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QYhLK/btsIizkVplo/eK2OsdsmPpivkKDLP1D1g0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQYhLK%2FbtsIizkVplo%2FeK2OsdsmPpivkKDLP1D1g0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1652&quot; height=&quot;143&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1652&quot; data-origin-height=&quot;143&quot;/&gt;&lt;/span&gt;&lt;/figure&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;731&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9pA0n/btsIg31Tnmb/Tp4oKk7TQ5nOkw6TOOXBU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9pA0n/btsIg31Tnmb/Tp4oKk7TQ5nOkw6TOOXBU0/img.png&quot; data-alt=&quot;상위의 tcp 3 way handshake 와 함께 진행된다. https://www.cloudflare.com/ko-kr/learning/ssl/what-happens-in-a-tls-handshake/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9pA0n/btsIg31Tnmb/Tp4oKk7TQ5nOkw6TOOXBU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9pA0n%2FbtsIg31Tnmb%2FTp4oKk7TQ5nOkw6TOOXBU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;731&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;731&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;상위의 tcp 3 way handshake 와 함께 진행된다. https://www.cloudflare.com/ko-kr/learning/ssl/what-happens-in-a-tls-handshake/&lt;/figcaption&gt;
&lt;/figure&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;프레임 549&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 A가 서버 B에 TLS 클라이언트 헬로 패킷을 보냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TLS 핸드셰이크를 시작하여 보안 연결을 설정하기 위함&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;출발지 포트&lt;/b&gt;: 50409&lt;/li&gt;
&lt;li&gt;&lt;b&gt;목적지 포트&lt;/b&gt;: 443 (HTTPS)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로토콜&lt;/b&gt;: TLSv1.3&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메시지&lt;/b&gt;: Client Hello (SNI=&lt;a href=&quot;http://www.naver.com&quot;&gt;www.naver.com&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&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;프레임 551&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 B가 클라이언트 A에 TLS 서버 헬로 및 초기 데이터 패킷을 보냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TLS 핸드셰이크를 계속 진행하여 보안 연결을 설정하기 위함&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;출발지 포트&lt;/b&gt;: 443 (HTTPS)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;목적지 포트&lt;/b&gt;: 50409&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로토콜&lt;/b&gt;: TLSv1.3&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메시지&lt;/b&gt;: Server Hello, Change Cipher Spec, Application Data&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Change Cipher Spec란?&lt;br /&gt;TLS(Transport Layer Security) 프로토콜의 일부로, 클라이언트와 서버가 암호화 설정을 변경할 준비가 되었음을 상호 통보하는 데 사용한다.&lt;/li&gt;
&lt;/ul&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;프레임 556&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 A가 서버 B에 TLS 변경 암호 사양 및 애플리케이션 데이터 패킷을 보냄&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;출발지 포트&lt;/b&gt;: 50409&lt;/li&gt;
&lt;li&gt;&lt;b&gt;목적지 포트&lt;/b&gt;: 443 (HTTPS)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로토콜&lt;/b&gt;: TLSv1.3&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메시지&lt;/b&gt;: Change Cipher Spec, Application Data&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TCP 4-way handshake (close)&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1842&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bY7FRH/btsIhcR6UMv/UsEMek42jKD1YB3d0Y7rIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bY7FRH/btsIhcR6UMv/UsEMek42jKD1YB3d0Y7rIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bY7FRH/btsIhcR6UMv/UsEMek42jKD1YB3d0Y7rIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbY7FRH%2FbtsIhcR6UMv%2FUsEMek42jKD1YB3d0Y7rIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1842&quot; height=&quot;256&quot; data-origin-width=&quot;1842&quot; data-origin-height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;/figure&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;프레임 12121, 12122(재전송)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 A가 서버 B에 TCP FIN-ACK 패킷을 보냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP 연결을 종료하기 위함&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출발지 포트: 443 (HTTPS)&lt;/li&gt;
&lt;li&gt;목적지 포트: 50409&lt;/li&gt;
&lt;li&gt;플래그: FIN, ACK&lt;/li&gt;
&lt;/ul&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;프레임 12123,12124(재전송),12125(재전송)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 A가 서버 B에 TCP ACK 패킷을 보냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버의 FIN-ACK 패킷에 대한 응답&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출발지 포트: 50409&lt;/li&gt;
&lt;li&gt;목적지 포트: 443 (HTTPS)&lt;/li&gt;
&lt;li&gt;플래그: ACK&lt;/li&gt;
&lt;/ul&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;프레임 12126&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 A가 서버 B에 TCP FIN-ACK 패킷을 보냄&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;출발지 포트: 50409&lt;/li&gt;
&lt;li&gt;목적지 포트: 443 (HTTPS)&lt;/li&gt;
&lt;li&gt;플래그: FIN, ACK&lt;/li&gt;
&lt;/ul&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;프레임 12127&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 B가 클라이언트 A에 TCP ACK 패킷을 보냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트의 FIN-ACK 패킷에 대한 응답 및 연결 종료 완료&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출발지 포트: 443 (HTTPS)&lt;/li&gt;
&lt;li&gt;목적지 포트: 50409&lt;/li&gt;
&lt;li&gt;플래그: ACK&lt;/li&gt;
&lt;/ul&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예로 들어 tcp가 닫히는 경우 4번의 요청/응답만 있을줄 알았는데 예시로 사용한 프레임 12---번대 뿐만 아니라 대부분의 과정에서 여러번의 재전송이 발생함을 알수 있었다.&lt;br /&gt;&lt;br /&gt;대부분의 과정은 0.01초만에 이루어지는 것을 보고 상당히 빠른속도로 정보가 만들어지고 프레임으로 캡슐화가 되어서 여러 라우터를 거쳐서 다시 나에게 돌아오는게 당연하지만 눈으로 수치를 확인하니 놀라웠던것 같다.&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;/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;이외에도 포스팅이 길어질까 추가를 하지 않았지만 분석해준 TCP 내부를 확인하면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;815&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNmXJv/btsIiV86Rts/gpPXP9YbCxluX3Q4JOYGvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNmXJv/btsIiV86Rts/gpPXP9YbCxluX3Q4JOYGvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNmXJv/btsIiV86Rts/gpPXP9YbCxluX3Q4JOYGvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdNmXJv%2FbtsIiV86Rts%2FgpPXP9YbCxluX3Q4JOYGvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;815&quot; height=&quot;351&quot; data-origin-width=&quot;815&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1830&quot; data-origin-height=&quot;722&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHezII/btsIg65sKx1/lHQtnP0ck6LaGefd2qk0ok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHezII/btsIg65sKx1/lHQtnP0ck6LaGefd2qk0ok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHezII/btsIg65sKx1/lHQtnP0ck6LaGefd2qk0ok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHezII%2FbtsIg65sKx1%2FlHQtnP0ck6LaGefd2qk0ok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1830&quot; height=&quot;722&quot; data-origin-width=&quot;1830&quot; data-origin-height=&quot;722&quot;/&gt;&lt;/span&gt;&lt;/figure&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;실제로 ISN으로 보낸 값에 +1을 해서 이를 ACK로 돌려보내는 과정도 확인할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <category>Handshake</category>
      <category>TCP</category>
      <category>tls</category>
      <category>와이어샤크</category>
      <category>패킷 분석</category>
      <category>핸드쉐이크</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/205</guid>
      <comments>https://nstgic3.tistory.com/entry/DNS-TCP-TLS-%ED%86%B5%EC%8B%A0%EC%97%90-%EB%8C%80%ED%95%9C-WireShark%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%ED%8C%A8%ED%82%B7-%EB%B6%84%EC%84%9D#entry205comment</comments>
      <pubDate>Sun, 30 Jun 2024 20:03:17 +0900</pubDate>
    </item>
    <item>
      <title>JVM스택메모리 구조 이해를 위한 바이트코드 예시</title>
      <link>https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;JVM의 메모리 영역 구성 요소중 하나인 자바가상머신 스택에 대한 이해를 위해 예제를 통해 각 구역에 데이터가 할당되고 해제되는것을 javap 명령어를 통해 알아본다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;해당 포스팅에서 나오는 상수풀은 런타임 상수풀이 아니라 클래스 상수풀이다.&amp;nbsp;&lt;br /&gt;JVM이 클래스 로드시에 클래스 상수풀 내의 파일이 런타임 상수풀에 적재된다.&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실습 코드 준비 및 컴파일&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1719296038469&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class BytecodeExample {
    public static void main(String[] args) {
        int a = 5;
        int b = 10;
        int result = addAndMultiply(a, b);
        System.out.println(result);
    }

    public static int addAndMultiply(int x, int y) {
        int sum = x + y;
        int product = x * y;
        return sum + product;
    }
}&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dGFmXm/btsIb6wChqg/FSnJxsNMzUHl50IbnT8Uy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dGFmXm/btsIb6wChqg/FSnJxsNMzUHl50IbnT8Uy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dGFmXm/btsIb6wChqg/FSnJxsNMzUHl50IbnT8Uy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdGFmXm%2FbtsIb6wChqg%2FFSnJxsNMzUHl50IbnT8Uy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1420&quot; height=&quot;110&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 컴파일과 javap 옵션으로 바이트 코드를 읽어와보자&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;BytecodeExample 클래스 기본 생성자 바이트 코드&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1630&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXBYUj/btsIbHYfmLa/9OWOCs6GC2wVJC3Sk1Heak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXBYUj/btsIbHYfmLa/9OWOCs6GC2wVJC3Sk1Heak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXBYUj/btsIbHYfmLa/9OWOCs6GC2wVJC3Sk1Heak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXBYUj%2FbtsIbHYfmLa%2F9OWOCs6GC2wVJC3Sk1Heak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1630&quot; height=&quot;280&quot; data-origin-width=&quot;1630&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;/figure&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;aload_0 (0)&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;b&gt;의미&lt;/b&gt;: 로컬 변수 0번 인덱스에 있는 값을 오퍼랜드 스택에 푸시&lt;/li&gt;
&lt;li&gt;클래스의 자신을 가르키는 this 는 만들어진 인스턴스 메서드의 첫번째 인자로 전달되고 로컬 변수 배열의 0번 인덱스에 저장된다.&lt;/li&gt;
&lt;li&gt;이후의 invokespecial 명령어에서 사용&lt;/li&gt;
&lt;/ul&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt; &lt;b&gt;invokespecial (1)&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;b&gt;의미&lt;/b&gt;: 상위 클래스, 생성자, 또는 private 메서드를 호출, 여기에서는 생성자 호출 후에 객체 초기화를 한다.&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택에 있는 this 참조를 사용하여 java/lang/Object의 생성자를 호출한다.&lt;/li&gt;
&lt;li&gt;this 참조가 사용되어 상위 클래스 생성자가 호출된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;return (4)&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;b&gt;의미&lt;/b&gt;: 메서드를 종료하고, 호출한 위치로 제어를 반환한다.&lt;/li&gt;
&lt;li&gt;return 명령어는 현재 실행 중인 메서드나 생성자를 종료하고 오퍼랜드 스택을 비운다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt; 최종적으로 BytecodeExample의 객체가 생성되고, 모든 초기화 작업이 완료된 상태가 된다.&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;main 메서드와 addAndMultiply 메서드 호출/복귀 바이트코드&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1612&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kxxiH/btsIc1abgDa/iIAcgV2TSWaRDa6tb3cKRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kxxiH/btsIc1abgDa/iIAcgV2TSWaRDa6tb3cKRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kxxiH/btsIc1abgDa/iIAcgV2TSWaRDa6tb3cKRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkxxiH%2FbtsIc1abgDa%2FiIAcgV2TSWaRDa6tb3cKRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1612&quot; height=&quot;480&quot; data-origin-width=&quot;1612&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 로컬 변수 배열의 관점&lt;/h4&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 변수 배열: [args, 0, 0, 0]&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택: []&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;iconst_5&lt;b&gt;&amp;lt;&lt;a href=&quot;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.iconst_i&quot;&gt;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.iconst_i&lt;/a&gt;&amp;gt;&lt;/b&gt;&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;상수 5를 오퍼랜드 스택에 푸시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 변수 배열: [args, 0, 0, 0]&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택: [5]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;istore_1&amp;lt;&lt;a href=&quot;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.istore&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.istore&lt;/a&gt;&amp;gt;&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;오퍼랜드 스택의 값을 로컬 변수 배열의 인덱스 1에 저장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 변수 배열: [args, 5, 0, 0]&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택: []&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;iconst_10(bipush)&amp;lt;&lt;a href=&quot;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.bipush&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.bipush&lt;/a&gt;&amp;gt;&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;상수 10을 오퍼랜드 스택에 푸시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 변수 배열: [args, 5, 0, 0]&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택: [10]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;istore_2&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;오퍼랜드 스택의 값을 로컬 변수 배열의 인덱스 2에 저장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 변수 배열: [args, 5, 10, 0]&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택: []&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 오퍼랜드 스택의 관점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;iload_1&amp;lt;&lt;a href=&quot;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.istore&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.istore&lt;/a&gt;&amp;gt;&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;로컬 변수 배열의 인덱스 1 값을 오퍼랜드 스택에 푸시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 변수 배열: [args, 5, 10, 0]&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택: [5]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;iload_2&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;로컬 변수 배열의 인덱스 2 값을 오퍼랜드 스택에 푸시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 변수 배열: [args, 5, 10, 0]&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택: [5, 10]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1694&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPge91/btsIbg7XWYN/XZn2LVOvVJbbckXA3J91sK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPge91/btsIbg7XWYN/XZn2LVOvVJbbckXA3J91sK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPge91/btsIbg7XWYN/XZn2LVOvVJbbckXA3J91sK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPge91%2FbtsIbg7XWYN%2FXZn2LVOvVJbbckXA3J91sK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1694&quot; height=&quot;486&quot; data-origin-width=&quot;1694&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 메서드 호출과 복귀 주소&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;invokestatic #2&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;addAndMultiply 메서드를 호출&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로컬 변수 배열&lt;/b&gt;: [x, y, sum, product]&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오퍼랜드 스택&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;iload_0: 5 (x)&lt;/li&gt;
&lt;li&gt;iload_1: 10 (y)&lt;/li&gt;
&lt;li&gt;iadd: 15 (sum)&lt;/li&gt;
&lt;li&gt;istore_2: sum 저장&lt;/li&gt;
&lt;li&gt;iload_0: 5 (x)&lt;/li&gt;
&lt;li&gt;iload_1: 10 (y)&lt;/li&gt;
&lt;li&gt;imul: 50 (product)&lt;/li&gt;
&lt;li&gt;istore_3: product 저장&lt;/li&gt;
&lt;li&gt;iload_2: 15 (sum)&lt;/li&gt;
&lt;li&gt;iload_3: 50 (product)&lt;/li&gt;
&lt;li&gt;iadd: 65 (결과)&lt;/li&gt;
&lt;li&gt;ireturn: 65 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1612&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kxxiH/btsIc1abgDa/iIAcgV2TSWaRDa6tb3cKRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kxxiH/btsIc1abgDa/iIAcgV2TSWaRDa6tb3cKRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kxxiH/btsIc1abgDa/iIAcgV2TSWaRDa6tb3cKRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkxxiH%2FbtsIc1abgDa%2FiIAcgV2TSWaRDa6tb3cKRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1612&quot; height=&quot;480&quot; data-origin-width=&quot;1612&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;2. 오퍼랜드 스택의 관점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;istore_3&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;오퍼랜드 스택의 값을 로컬 변수 배열의 인덱스 3에 저장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 변수 배열: [args, 5, 10, 55]&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택: []&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 상수 풀 참조&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;getstatic #13&amp;lt;&lt;a href=&quot;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.getstatic&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.getstatic&lt;/a&gt;&amp;gt;&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;System.out을 13번 인덱스 상수 풀에서 정적 필드를 참조하여 오퍼랜드 스택에 푸시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 변수 배열: [args, 5, 10, 55]&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택: [System.out]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;2. 오퍼랜드 스택의 관점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;iload_3&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;로컬 변수 배열의 인덱스 3 값을 오퍼랜드 스택에 푸시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 변수 배열: [args, 5, 10, 55]&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택: [System.out, 55]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3. 메서드 호출과 복귀 주소&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;invokevirtual #19&amp;lt;&lt;a href=&quot;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokevirtual&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokevirtual&lt;/a&gt;&amp;gt;&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;b&gt;작업&lt;/b&gt;: println 메서드를 호출하여 값을 출력합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변경 후&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 변수 배열: [args, 5, 10, 55]&lt;/li&gt;
&lt;li&gt;오퍼랜드 스택: []&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;이외에도 자바의 JVM구조에 대해 알고 싶으면 아래 포스팅을 참고해보자&lt;br /&gt;&lt;/span&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;BytecodeExample 클래스를 컴파일하여 javap 명령어를 통해 분석함으로써 로컬 변수 배열, 오퍼랜드 스택, 메서드 호출과 복귀, 그리고 상수 풀의 역할을 구체적으로 알아보았는데 JVM 스택의 구성요소를 정리하고 마무리 하겠다.&lt;br /&gt;&lt;br /&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;로컬 변수 배열&lt;/b&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;예제에서 변수 a와 b가 각각 인덱스 1과 2에 저장된것을 확인할수 있다.(결과도 저장됌)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오퍼랜드 스택&lt;/b&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;예제에서 iconst_5와 bipush 10 명령어로 각각 상수 5와 10을 오퍼랜드 스택에 푸시하고(계산을 위해), istore 명령어는 이를 로컬 변수 배열에 저장하였다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메서드 호출과 복귀&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;invokestatic 명령어는 정적 메서드를 호출하고 호출된 메서드가 실행되는 동안 새로운 프레임이 생성되었다.&lt;/li&gt;
&lt;li&gt;invokevirtual 명령어는 인스턴스 메서드를 호출하고 해당 객체의 참조와 인수를 오퍼랜드 스택에서 꺼내어 메서드를 호출했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상수 풀 참조&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;getstatic 명령어는 상수 풀에서 정적 필드를 참조하여 오퍼랜드 스택에 푸시한다.&lt;/li&gt;
&lt;li&gt;예제에서 System.out 필드는 상수 풀에서 참조되어 오퍼랜드 스택에 푸시되고, println 메서드를 호출하여 결과를 출력한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/204</guid>
      <comments>https://nstgic3.tistory.com/entry/%EC%9E%90%EB%B0%94%EA%B0%80%EC%83%81%EB%A8%B8%EC%8B%A0-%EC%8A%A4%ED%83%9D-%EC%9D%B4%ED%95%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C#entry204comment</comments>
      <pubDate>Tue, 25 Jun 2024 17:22:11 +0900</pubDate>
    </item>
    <item>
      <title>JVM에서 자바 메서드와 네이티브 메서드 실행의 차이점</title>
      <link>https://nstgic3.tistory.com/entry/JVM%EC%97%90%EC%84%9C-%EC%9E%90%EB%B0%94-%EB%A9%94%EC%84%9C%EB%93%9C%EC%99%80-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%8B%A4%ED%96%89%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목차&lt;/span&gt;&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;JVM의 메모리 구조 이해를 위한 글로 두 메서드의 실행 차이점을 알아본다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;Java 9 이전보다 최근들어서는 자바로 쓰인 라이브러리의 종류도 많아져 잘 사용하지 않기에 사용이 적다. 이펙티브 자바에서도 최대한 네이티브 메서드의 실행을 지양하고 있다. 하지만 해당 내용이 JVM 의 구조를 이해하기에 도움이 되기에 간단히 적어본다.&lt;/span&gt;&lt;/span&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;자바 네이티브 인터페이스(Java Native Interface, JNI) -&amp;gt; 자바&amp;nbsp;프로그램이&amp;nbsp;네이티브&amp;nbsp;메서드를&amp;nbsp;호출하는&amp;nbsp;기술&lt;br /&gt;네이티브 메서드 -&amp;gt;&amp;nbsp; C나 C++같은 네이티브 프로그래밍 언어로 작성한 메서드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네이티브 메모리 -&amp;gt; 자바가 실행되고 있는 운영체제의 메모리, 운영체제에 의해 관리되기에 자바 힙보다 확장성이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*네이티브 메모리는 네이티브 메서드의 실행에만 국한되는게 아니다. JIT 컴파일러에 의해 변환된 자바 코드나 과거 영구세대가 메타스페이스라는 이름으로 바뀌어 네이티브 메모리 내에 저장이 되기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;로딩 과정에서의 차이&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;자바 메서드의 클래스 로딩&lt;/b&gt;&lt;br /&gt;자바 메서드는 자바 클래스 파일에 정의되어 있고 JVM의 클래스 로더에 의해 로드된다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;클래스 로더는 클래스 파일을 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;메모리의 메소드 영역(Method Area)에 로드&lt;/span&gt;하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;클래스의 메타데이터를 초기화와 클래스의 정적 변수와 상수 풀도 메모리에 로드한다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;네이티브&amp;nbsp;메서드의&amp;nbsp;라이브러리&amp;nbsp;로딩&lt;/b&gt;&lt;br /&gt;네이티브 메서드는 자바가 아닌 다른 언어(C, C++)로 작성된 메서드로 네이티브 라이브러리에 포함되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;System.loadLibrary() 메서드를 통해 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;네이티브 라이브러리를 로드&lt;/span&gt;하여 사용한다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실행 방식에서의 차이&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;자바&amp;nbsp;메서드의&amp;nbsp;실행&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;자바 메서드는 JVM의 실행 엔진에 의해 바이트코드로 실행된다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt; 실행 엔진은 바이트코드를 해석하여 명령어를 실행하거나 JIT(Just-In-Time) 컴파일러를 사용해 자주 실행되는 코드를 네이티브 기계어로 변환하여 성능을 최적화한다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;네이티브&amp;nbsp;메서드의&amp;nbsp;실행&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;네이티브&amp;nbsp;메서드는&amp;nbsp;JNI(Java&amp;nbsp;Native&amp;nbsp;Interface)를&amp;nbsp;통해&amp;nbsp;호출된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&amp;nbsp;JNI는 자바 코드에서 네이티브 메서드를 직접 호출하여 JVM의 실행 엔진을 거치지 않고, 네이티브 메서드 스택에서 직접 실행된다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메모리 관점에서의 차이(중요)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;자바 메서드의 스택메모리 사용&lt;/b&gt;&lt;br /&gt;자바 메서드 호출 시 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;자바 가상머신 스택에 새로운 스택 프레임&lt;/span&gt;(자바 가상머신 스택)이 생성되고 생성된 스택 위에서 작동한다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;네이티브&amp;nbsp;메서드의&amp;nbsp;스택&amp;nbsp;사용&lt;/b&gt;&lt;br /&gt;네이티브 메서드 호출 시 네이티브 메서드 스택이 사용된다. 자바 메서드와 비슷하게 작동하며 몇몇 가상머신에서는 두 스택을 합쳐서 구현해놓은 경우도 있다고 한다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;자바&amp;nbsp;메서드의&amp;nbsp;메모리&amp;nbsp;관리&lt;/b&gt;&lt;br /&gt;자바&amp;nbsp;메서드에서&amp;nbsp;생성된&amp;nbsp;객체는&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;힙(Heap)&amp;nbsp;영역에&amp;nbsp;할당&lt;/span&gt;되어 JVM의&amp;nbsp;가비지&amp;nbsp;컬렉터가&amp;nbsp;관리를 한다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;네이티브&amp;nbsp;메서드의&amp;nbsp;메모리&amp;nbsp;관리&lt;/b&gt;&lt;br /&gt;네이티브 메서드는 자바의 가비지 컬렉션에 의해 관리되지 않는 메모리만을 사용할 수 있다. 네이티브 메모리는 개발자가 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;직접 할당하고 해제&lt;/span&gt;해야 합니다(예: malloc/free). &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이로 인해 메모리 누수나 잘못된 메모리 접근과 같은 문제가 발생할 수 있다.&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;이외의 특성&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt; &lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;자바&amp;nbsp;메서드의&amp;nbsp;플랫폼&amp;nbsp;독립성&lt;/b&gt;&lt;br /&gt;자바 메서드는 플랫폼 독립적인 JVM 바이트코드로 실행되기에(자바의 장점이기도 하다) JVM이 설치된 모든 플랫폼에서 동일한 코드가 실행될 수 있으므로 &quot;Write Once, Run Anywhere&quot; 구호(?) 를 지킬수 있다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;네이티브&amp;nbsp;메서드의&amp;nbsp;플랫폼&amp;nbsp;종속성&lt;/b&gt;&lt;br /&gt;네이티브 메서드는 특정 플랫폼에 종속되어 운영 체제에 따라 다르므로, 플랫폼 간의 이식성이 떨어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;nbsp;네이티브 메서드를 사용할 때는 대상 플랫폼에 맞는 라이브러리를 제공해야 하는 문제가 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Java</category>
      <category>JVM</category>
      <category>네이티브 메서드</category>
      <category>자바 메서드</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/202</guid>
      <comments>https://nstgic3.tistory.com/entry/JVM%EC%97%90%EC%84%9C-%EC%9E%90%EB%B0%94-%EB%A9%94%EC%84%9C%EB%93%9C%EC%99%80-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%8B%A4%ED%96%89%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90#entry202comment</comments>
      <pubDate>Mon, 24 Jun 2024 23:27:39 +0900</pubDate>
    </item>
    <item>
      <title>'24 1h</title>
      <link>https://nstgic3.tistory.com/entry/24-1h</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2024-06-24-01-28-28.jpeg&quot; data-origin-width=&quot;1331&quot; data-origin-height=&quot;998&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnm45v/btsIajvtDfJ/GzR8ErxL6c12kzxBYFDz9k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnm45v/btsIajvtDfJ/GzR8ErxL6c12kzxBYFDz9k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnm45v/btsIajvtDfJ/GzR8ErxL6c12kzxBYFDz9k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcnm45v%2FbtsIajvtDfJ%2FGzR8ErxL6c12kzxBYFDz9k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1331&quot; height=&quot;998&quot; data-filename=&quot;KakaoTalk_Photo_2024-06-24-01-28-28.jpeg&quot; data-origin-width=&quot;1331&quot; data-origin-height=&quot;998&quot;/&gt;&lt;/span&gt;&lt;/figure&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;시작&lt;/b&gt;&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;카테캠을 졸업한 1기 학생이었고 수료시에도 좋은 평을 들었어서 현재 와서 돌아보면 꽤나 괜찮은 기회였는데 반대로 현재와서 그때의 내 cs 수준을 생각해보니 합격했어도 버텼을까? 라는 생각이 들기도 한다. 이후에 네이버 공채를 비롯해서 올리브영이나 금융쪽 개발직군 등 10여군데를 지원했지만 네이버만 코테를 볼 기회가 있었고 나머지는 서류에서 떨어지는 대참사(?)를 맞게 된다.&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;&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;사실 글을 쓰는 현재로써 내가 it 직군으로의 전환 결심을 하고 유우명한 유튜버인 노마드 코더의 '바닐라 js 로 만드는 todo list' 를 주섬주섬 만들었던 순간으로부터 만2년을 채워가는 시점이다.&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;기회가 운좋게 닿았던 카카오에서 진행한 부트 캠프나 어렸을때부터 선망했던, 여러 대회실적과 나쁘지 않은 교수님들의 호평이 있던 항공쪽 학과를 그만두면서까지 선택을 한 분야에 대한 집착과 열정을 감안하더라도 현재는 개발자를 모셔가던 3여년전이 아닌 이쪽업계(대기업 같은 메인스트림)로의 진출은 어려운 상황인것 같다.&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;결론은 생각보다 내가 더 준비해야되고 기다려야된다는 시간이 많다는 점인것 같다.&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;새로운 사회를 경험하는게 기대되는 성향인지라 대학을 선택할때도 재수보다는 하향으로 가더라도 내가 원하는걸 할수 있는 곳으로 선택했었다.&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;지금은 그런 성향을 좀 억누른채 느긋하게(처음부터 이러지는 않았다) 준비를 해나가고 있는데 나름 문제 분석을 해보니 paper 가 좀 부족한것 같았다. 내가 심사위원이라해도 이것저것 한게 많은데 정량적인 데이터가 부족했다. 복수 전공도 부전공도 아니고 대학 마지막 1년에나 부트캠프를 졸업했지 않은가 그래서 저번주 금요일 자로(21일) 정보처리기사와 sqld 를 취득했다. 앞으로는 9월에 있을 aws의 saa 나 sqlp를 따보려한다.&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;&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;&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;사실 대회보다는 운영하는 사이트를 리팩터링하기에 바쁜데, 실제로 sqld 를 따기 위해서 공부했던 튜닝 방식들을 조금씩 적용해보고 있다. 1년 전 잘 모른 상태에서 카피페로 구현했던 Oauth2 인증 필터 부분도 원래의 형체를 찾아볼수 없을정도로(?) 리팩터링을 진행했고 한번씩 건들지 않은 도메인이 없을 정도로 관심을 가져준것 같다.&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;&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;사실 이 분야가 매력적인건 이 부분이었다. 높은 샐러리나 타 직종에 비해서 자유로운 분위기도 마음에 들었지만 테크트리에 있어서 잔가지가 많다고 해야하나? 항공업계는 산업사이클이 무척이나 길고 대부분의 정보가 국가 안보에 묶여있어서 이런 부분에 있어서는 자유도가 낮다고 본다. 복잡한걸 좋아하는게 아닐까 생각을 해봤다.&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;todo&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sqld 를 공부할때 문제를 풀어봤는데 토익의 파랭이 빨갱이 책 처럼 이쪽 업계에는 노랭이 책이 있다. 해당 책의 3장에는 상위 자격증인 sqlp를 위한 기출문제가 나와있는데 그정도 수준이 되면 sql의 구동 방식을 알아야되더라 눈을 돌려서 내가 취업을 준비하는 자바스프링을 보았는데 단순히 우리가 상황을 검색해서 기술블로그에 나오는 효율적인 구현방법~ 작동방식~ 은 얉은 수준의 정보였다는걸 알았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;쓸만한 책을 찾다가 요새는 jvm 밑바닥 파헤치기 라는 책을 재미있게 읽고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 암기식으로 외워왔던 tdd나 디자인패턴-아키텍처 부분도 내가 실제로 리팩터링을 하면서 들었던 생각들이 정리되어 작성되어있는걸 보고 관련 서적을 찾아서 읽어보고 있다.&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;사실 취업을 빨리하면 좋기는 하다. 지금 내가 하고 있는걸 어디 회사에 나를 의탁(?)해서 공부도 하고 시니어의 조언도 듣고 일도하면 좋은일이 아닌가라는 마음이 크기는 하지만 준비가 좀 필요한 때인것 같다. 취업에는 좋은 결과가 없었지만 내 최애 취미인 자전거 관련되서 어쩌다 브롬톤이 한대 생겨서 재미있게 타고다니기도 하고있다. 계획으로는 날이 좀 시원해지면 들고 해외에서 자전거 한번 타고 오려는데 큰 이변이 없으면 갔다와야겠다ㅋㅋㅋ 회고가 너무 길어졌는데 다음 회고는 3분기 회고로 돌아오길 바라면서 여기서 마무리하겠다.&lt;/p&gt;</description>
      <category>Life</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/201</guid>
      <comments>https://nstgic3.tistory.com/entry/24-1h#entry201comment</comments>
      <pubDate>Mon, 24 Jun 2024 01:30:18 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스의 물리적 구조(Oracle/MySQL)</title>
      <link>https://nstgic3.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%9D%98-%EB%AC%BC%EB%A6%AC%EC%A0%81-%EA%B5%AC%EC%A1%B0OracleMySQL</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목차&lt;/span&gt;&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;본 포스팅은 Oracle, MySQL의 공식문서를 참고 하였다.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/glossary.html#glos_segment&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev.mysql.com/doc/refman/8.4/en/glossary.html#glos_segment&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1717636354556&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;MySQL :: MySQL 8.4 Reference Manual :: MySQL Glossary&quot; data-og-description=&quot;MySQL 8.4 Reference Manual &amp;nbsp;/&amp;nbsp; MySQL Glossary These terms are commonly used in information about the MySQL database server. A .ARM file Metadata for ARCHIVE tables. Contrast with .ARZ file. Files with this extension are always included in backups produce&quot; data-og-host=&quot;dev.mysql.com&quot; data-og-source-url=&quot;https://dev.mysql.com/doc/refman/8.4/en/glossary.html#glos_segment&quot; data-og-url=&quot;https://dev.mysql.com/doc/refman/8.4/en/glossary.html#glos_segment&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/glossary.html#glos_segment&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.mysql.com/doc/refman/8.4/en/glossary.html#glos_segment&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MySQL :: MySQL 8.4 Reference Manual :: MySQL Glossary&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;MySQL 8.4 Reference Manual &amp;nbsp;/&amp;nbsp; MySQL Glossary These terms are commonly used in information about the MySQL database server. A .ARM file Metadata for ARCHIVE tables. Contrast with .ARZ file. Files with this extension are always included in backups produce&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.mysql.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/cd/B13789_01/server.101/b10743/logical.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.oracle.com/cd/B13789_01/server.101/b10743/logical.htm&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1717636360603&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;2 Data Blocks, Extents, and Segments&quot; data-og-description=&quot;Oracle maintains information to nullify changes made to the database. Such information consists of records of the actions of transactions, collectively known as 'undo.' Oracle uses the undo to do the following: Automatic undo management is undo-tablespace &quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/cd/B13789_01/server.101/b10743/logical.htm&quot; data-og-url=&quot;https://docs.oracle.com/cd/B13789_01/server.101/b10743/logical.htm&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/cd/B13789_01/server.101/b10743/logical.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/cd/B13789_01/server.101/b10743/logical.htm&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;2 Data Blocks, Extents, and Segments&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Oracle maintains information to nullify changes made to the database. Such information consists of records of the actions of transactions, collectively known as 'undo.' Oracle uses the undo to do the following: Automatic undo management is undo-tablespace&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;용어 및 개념 설명&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ekRTsd/btsHRm6UuPv/dP5IJXENvPFfxBWuM8iiJ1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ekRTsd/btsHRm6UuPv/dP5IJXENvPFfxBWuM8iiJ1/img.gif&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;464&quot; data-is-animation=&quot;false&quot; style=&quot;width: 27.5427%; margin-right: 10px;&quot; data-widthpercent=&quot;27.87&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ekRTsd/btsHRm6UuPv/dP5IJXENvPFfxBWuM8iiJ1/img.gif&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FekRTsd%2FbtsHRm6UuPv%2FdP5IJXENvPFfxBWuM8iiJ1%2Fimg.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;266&quot; height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmlTM5/btsHPHknr9Z/Omwx2QCZUVVkpmyVKCJg5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmlTM5/btsHPHknr9Z/Omwx2QCZUVVkpmyVKCJg5K/img.png&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;529&quot; data-is-animation=&quot;false&quot; style=&quot;width: 71.2945%;&quot; data-widthpercent=&quot;72.13&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmlTM5/btsHPHknr9Z/Omwx2QCZUVVkpmyVKCJg5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmlTM5%2FbtsHPHknr9Z%2FOmwx2QCZUVVkpmyVKCJg5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;785&quot; height=&quot;529&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Oracle 의 구조 (좌), MySQL의 구조 (우) ; 최소 단위의 구좀 명칭만 다른것을 확인할 수 있다. 물론 특성도 조금씩 다르다.&lt;/figcaption&gt;
&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;테이블스페이스 (Tablespace)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;데이터 파일 (Data File)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;세그먼트 (Segment)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;4.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;익스텐트 (Extent)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;5.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;데이터 블록 (Data Block) 또는 페이지 (Page)&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;&lt;b&gt;1. 테이블스페이스 (Tablespace)&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;/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;&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;2. 데이터 파일 (Data File)&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;/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;span&gt;&lt;b&gt;예시&lt;/b&gt;: &lt;/span&gt;userspace01.dbf&lt;span&gt;, &lt;/span&gt;system01.dbf&lt;span&gt; 등.&lt;/span&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;3. 세그먼트 (Segment)&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;세그먼트는 테이블, 인덱스, LOB 등 데이터베이스 객체의 데이터를 저장하는 논리적 저장 단위.&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;&lt;b&gt;인덱스 세그먼트&lt;/b&gt;: 인덱스 데이터 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LOB 세그먼트&lt;/b&gt;: 대용량 객체(BLOB, CLOB) 저장&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;&lt;b&gt;언두 세그먼트&lt;/b&gt;: 트랜잭션 복구를 위한 undo 데이터 저장&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;MySQL에서는 Oracle과 달리 별도의 LOB(Large Object) 세그먼트가 존재하지 않다.&lt;br /&gt;&lt;br /&gt;MySQL InnoDB 스토리지 엔진은 LOB 데이터(BLOB, TEXT 등)를 테이블의 기본 세그먼트에 저장하고 필요에 따라 기본 행 데이터와 연결한다.&lt;/blockquote&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. 익스텐트 (Extent)&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;/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;5. 데이터 블록 (Data Block for Oracle) 또는 페이지 (Page for MySQL)&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 데이터 블록은 운영 체제 블록의 배수로 설정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Oracle은 DB_BLOCK_SIZE 파라미터를 이용해 사이즈를 지정하고 2KB~32KB까지 이용이 가능하다.&amp;nbsp;&lt;br /&gt;MySQL은 innodb_page_size 파라미터를 이용하고 5.5 버전이하 에서는 16KB 페이지 크기가 고정 되어있었지만 이후에는 다양한 크기를 지원한다.&lt;br /&gt;&lt;br /&gt;두 DB 모두 서로 다른 블록 크기를 가지는 테이블 스페이스를 생성하는 다중 블록(페이지) 관리 기법 사용이 가능하다.&amp;nbsp;&lt;/blockquote&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인덱스의 유무, 파티션의 유무에 따른 세그먼트 개수 예상해보기&lt;/span&gt;&lt;/h3&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: 파티션이 없는 테이블과 인덱스&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;span&gt;&lt;b&gt;상황&lt;/b&gt;: &lt;/span&gt;employees&lt;span&gt; 테이블이 있으며, 인덱스가 3개(&lt;/span&gt;employee_id&lt;span&gt;, &lt;/span&gt;last_name&lt;span&gt;, &lt;/span&gt;department_id&lt;span&gt;) 존재&lt;/span&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;세그먼트 개수&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;테이블 세그먼트: 1개&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;인덱스 세그먼트: 3개&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개&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;&lt;b&gt;예시 2: 파티션이 있는 테이블과 인덱스 (범위 파티션 2개, 인덱스 2개)&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;상황&lt;/b&gt;: &lt;span&gt;sales&lt;/span&gt; 테이블이 범위 파티션 2개로 나누어져 있으며, 인덱스가 2개(&lt;span&gt;sale_id&lt;/span&gt;, &lt;span&gt;sale_date&lt;/span&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;세그먼트 개수&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;테이블 세그먼트: 2개 (각 파티션당 1개)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;인덱스 세그먼트: 4개 (각 파티션당 2개 인덱스)&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;6개&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;&lt;b&gt;예시 3: 파티션이 있는 테이블과 인덱스 (범위 파티션 4개, 인덱스 2개)&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;상황&lt;/b&gt;: &lt;span&gt;orders&lt;/span&gt; 테이블이 범위 파티션 4개로 나누어져 있으며, 인덱스가 2개(&lt;span&gt;order_id&lt;/span&gt;, &lt;span&gt;order_date&lt;/span&gt;) 존재&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;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;테이블 세그먼트: 4개 (각 파티션당 1개)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;인덱스 세그먼트: 8개 (각 파티션당 2개 인덱스)&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;12개&lt;/b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;파티션이 존재하는 경우, 테이블 세그먼트는 파티션으로 나누어져 개별 파티션이 각각 독립적인 세그먼트를 갖기 때문에 따라서 파티션된 테이블은 독립적인 &amp;ldquo;단일&amp;rdquo; 테이블 세그먼트를 가지지 않고, 각 파티션이 독립적으로 세그먼트를 갖게 된다.&lt;/span&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&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;</description>
      <category>SQLP</category>
      <category>데이터 베이스 구조</category>
      <category>블록</category>
      <category>세그먼트 개수</category>
      <category>페이지</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/200</guid>
      <comments>https://nstgic3.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4%EC%9D%98-%EB%AC%BC%EB%A6%AC%EC%A0%81-%EA%B5%AC%EC%A1%B0OracleMySQL#entry200comment</comments>
      <pubDate>Thu, 6 Jun 2024 10:34:33 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스 성능 최적화를 위한 하드 파싱과 소프트 파싱 : Spring 에서의 활용방법</title>
      <link>https://nstgic3.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%95%98%EB%93%9C-%ED%8C%8C%EC%8B%B1%EA%B3%BC-%EC%86%8C%ED%94%84%ED%8A%B8-%ED%8C%8C%EC%8B%B1-Spring-%EC%97%90%EC%84%9C%EC%9D%98-%ED%99%9C%EC%9A%A9%EB%B0%A9%EB%B2%95</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목차&lt;/span&gt;&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQLP 자격증 준비중에 하드/소프트 파싱에 대해서 나왔고 대용량 트래픽이 몰리는 상황에서 로그인 시에 db에서 회원 정보를 받아오는 것을 예시로 들어 순회시에 바인딩 변수를 이용하면 db엔진에 SQL 이 N개가 수행되는것이 아니라 1개만 수행되고 이후엔 소프트파싱을 이용해 최적화를 한다고 명시되어 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;따라서 Spring 에서는 바인딩 변수를 어떻게 이용되고 있는지 찾아보고 작성하게 되었다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로는 Spring에는 @RequestParam 등 Data binding 을 도와주고 있는 어노테이션들이 존재하였는데 오늘 살펴볼 SQL과의 Data binging 에서는 = :{속성} 의 JPQL 쿼리에 해당 속성을 @Param 어노테이션을 이용하여 지정해주는 방식을 이용하고 있었다.&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;a href=&quot;https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html#jpa.named-parameters&quot;&gt;https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html#jpa.named-parameters&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1717578767480&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;JPA Query Methods :: Spring Data JPA&quot; data-og-description=&quot;By default, Spring Data JPA uses position-based parameter binding, as described in all the preceding examples. This makes query methods a little error-prone when refactoring regarding the parameter position. To solve this issue, you can use @Param annotati&quot; data-og-host=&quot;docs.spring.io&quot; data-og-source-url=&quot;https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html#jpa.named-parameters&quot; data-og-url=&quot;https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html#jpa.named-parameters&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html#jpa.named-parameters&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html#jpa.named-parameters&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;JPA Query Methods :: Spring Data JPA&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;By default, Spring Data JPA uses position-based parameter binding, as described in all the preceding examples. This makes query methods a little error-prone when refactoring regarding the parameter position. To solve this issue, you can use @Param annotati&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하드 파싱과 소프트 파싱&lt;/span&gt;&lt;/h3&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;하드 파싱(Hard Parsing)&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;하드 파싱은 데이터베이스가 새로운 SQL 쿼리를 처음으로 처리할 때 수행되는 과정이다. 아래와 같이 하드 파싱은 자원 사용량이 많고 시간이 오래 걸린다.&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;span&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;SQL 텍스트 분석&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;최적화&lt;/b&gt;: 최적의 실행 계획을 수립하기 위해 쿼리 최적화를 수행 (옵티마이저)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;실행 계획 생성&lt;/b&gt;: 쿼리 실행에 필요한 단계를 계획&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;4.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;캐시에 저장&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBMS 에서의 과도한 부하는 대부분 I/O 과정에서 일어나는데 서론부에서 설명했던 하드파싱이 여러번 발생하는 상황에서는 이에 못지 않게 CPU 사용률의 급격한 증가와 라이브러리 캐시 내에서의 경합으로 인해서 제대로 Select 가 처리되지 않는 상황이 발생할 수 있다.&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;소프트 파싱(Soft Parsing)&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;소프트 파싱은 하드 파싱의 비용을 줄이기 위해 동일한 SQL 쿼리를 재사용할 때 수행되는 과정으로 라이브러리 캐시에 저장된 실행 계획을 재사용함으로써 성능을 최적화한다.&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;span&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;캐시 검색&lt;/b&gt;: 라이브러리 캐시에서 동일한 SQL 텍스트의 실행 계획을 검색&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;/span&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;title 없는 SQL와 파라미터 Driven 방식&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;DB에서 프로시저, 트리거 등은 생성 시에 이름을 가지고 해당 이름으로 호출, 삭제가 가능하다. SQL 의 경우에는 따로 이름을 가지고 있지 않고 들어온 SQL 텍스트가 곧 이름의 역할을 한다. 따라서 모든 파라미터를 하드 파싱하게 된다면 라이브러리 캐시에 캐싱을 해두어도 검색순회 하는데에만 오랜 시간이 걸려서 성능상 문제가 생길수 있다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;따라서 파라미터 부분을 바인딩 변수로 대체하여 하드파싱은 최초 1회에 한해서 발생하게 하고 이후에는 소프트 파싱을 이용해 자원 사용의 이점을 가져올 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;스프링에서 @Param 을 이용한 파라미터 Driven 쿼리&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;실제 운영중인 코드 조각을 가져와 봤다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1717580224845&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface ProductRepository extends JpaRepository&amp;lt;Product, Long&amp;gt; {

    @Query(&quot;SELECT p.id FROM Product p WHERE p.subCategory.category.name = :categoryName&quot;)
    List&amp;lt;Long&amp;gt; findIdsByCategoryName(@Param(&quot;categoryName&quot;) String categoryName);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;@Query&lt;/span&gt; 어노테이션은 JPQL(Java Persistence Query Language) 쿼리를 정의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:categoryName&lt;/span&gt;은 바인딩 변수로, 실행 시점에 &lt;span&gt;@Param&lt;/span&gt; 어노테이션을 통해 값을 전달받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;Spring 내에서 @Param을 사용하여 동적으로 쿼리 작성이 가능하다 라는 사실만 알고 있었지만 JPQL 작성시 := 등의 표현법으로 파라미터 Driven 방식의 SQL 을 통해 데이터 베이스 내에서 하드/소프트 파싱 전략을 사용하게 된다는 개념을 확실히 잡게 된것 같다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>SQLP</category>
      <category>바인딩 변수</category>
      <category>소프트 파싱</category>
      <category>하드 파싱</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/199</guid>
      <comments>https://nstgic3.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%95%98%EB%93%9C-%ED%8C%8C%EC%8B%B1%EA%B3%BC-%EC%86%8C%ED%94%84%ED%8A%B8-%ED%8C%8C%EC%8B%B1-Spring-%EC%97%90%EC%84%9C%EC%9D%98-%ED%99%9C%EC%9A%A9%EB%B0%A9%EB%B2%95#entry199comment</comments>
      <pubDate>Wed, 5 Jun 2024 18:39:41 +0900</pubDate>
    </item>
    <item>
      <title>Dayner 2차 리팩토링 계획(feat: 멀티 모듈화)</title>
      <link>https://nstgic3.tistory.com/entry/%EB%8F%84%EC%BB%A4</link>
      <description>&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;기획부터 운영까지 반년이 넘어가는 시점이다.&lt;/h3&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1576&quot; data-origin-height=&quot;1196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m7Fd6/btsJq2FQ1mK/olYujIZsTz9bUJkIbeNn01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m7Fd6/btsJq2FQ1mK/olYujIZsTz9bUJkIbeNn01/img.png&quot; data-alt=&quot;새 디자인! 역시 전문가는 다른것같다..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m7Fd6/btsJq2FQ1mK/olYujIZsTz9bUJkIbeNn01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm7Fd6%2FbtsJq2FQ1mK%2FolYujIZsTz9bUJkIbeNn01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1576&quot; height=&quot;1196&quot; data-origin-width=&quot;1576&quot; data-origin-height=&quot;1196&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;새 디자인! 역시 전문가는 다른것같다..&lt;/figcaption&gt;
&lt;/figure&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;/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호점도 생길 예정이며, 토스 결제 기능이 추가된 주문 기능도 포함될 예정이다.&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b65YiK/btsJqAwgi32/VuKATegvnEVXgzWJHEXSoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b65YiK/btsJqAwgi32/VuKATegvnEVXgzWJHEXSoK/img.png&quot; data-alt=&quot;처음 계획했을때의 기능과 현재의 기능(포장 주문의 경우에는 구현 예정이다)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b65YiK/btsJqAwgi32/VuKATegvnEVXgzWJHEXSoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb65YiK%2FbtsJqAwgi32%2FVuKATegvnEVXgzWJHEXSoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1202&quot; height=&quot;768&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;처음 계획했을때의 기능과 현재의 기능(포장 주문의 경우에는 구현 예정이다)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;모듈화의 필요성&lt;/h3&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;최근 회자 되고 있는 DDD(Domain-Driven Design)나 MSA(Microservices Architecture)와 같은 접근 방식을 고려할 수 있는데, 계속 연락을 주고 받고 있는 동아리원의 말에 따르면 요새 협업 프로젝트로도 대용량 처리를 염두한 다중 서버를 구축한다고도 한다.&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;하지만 실제 운영 환경은 이상적이지 않다. 현재의 상황에서는 여러 대의 API 서버를 두고 운용하기보다는, 부하가 걸리는 API의 경우 메시지 큐(Message Queue)를 사용할 필요 없이 Async로 처리하는 것이 대부분의 상황에서 충분하다. 이는 비동기 처리로도 대부분의 성능 요구 사항을 충족할 수 있기 때문이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;향후 계획 및 고려 사항&lt;/span&gt;&lt;/h3&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차 리팩토링을 수행하는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;가장 큰 이유는&lt;/span&gt;&amp;nbsp;초기 단계에서 고려하지 않았던 포장 주문 기능의 추가와 2호점 개설에 따른 Stock 관리의 이중화 같은 요구 사항을 반영하기 위해서 인데, 상품과 결제 모듈을 별도로 분리하면, 원두나 영업 일정과 같은 다른 도메인과도 격리되어 기능 추가나 수정 시 영향이 적고, 새로운 재고 관리 시스템 추가에도 용이할 것으로 판단된다.&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;현재로서는 결제 트랜잭션이 1000건 남짓 이지만, 추후 활성화로 인해서 데이터가 증가할 경우에는 결제 데이터 관리를 하는 모듈에서 개인정보법에 따라 주기적으로 파기, 보존 하는 배치 작업을 모듈로 구현하여 장점을 챙겨갈수 있을것 같다.&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;추가적으로, 필요한 경우 서버를 다중화하고 메시지 큐 등의 비동기 처리 기법을 고려할 수 있지만, 현재 상황에서는 복잡도를 줄이기 위해 Async 방식이 충분할 것으로 판단된다.&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Dayner 프로젝트</category>
      <category>리팩토링</category>
      <category>운영기</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/198</guid>
      <comments>https://nstgic3.tistory.com/entry/%EB%8F%84%EC%BB%A4#entry198comment</comments>
      <pubDate>Wed, 3 Apr 2024 23:40:22 +0900</pubDate>
    </item>
    <item>
      <title>EC2상의 스프링프로젝트 Promethus+Grafana 로 모니터링 세팅</title>
      <link>https://nstgic3.tistory.com/entry/EC2%EC%83%81%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-PromethusGrafana-%EB%A1%9C-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81-%EC%84%B8%ED%8C%85</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;24년 2월에 처음 오픈하여 운영하기 시작한 &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Dayner 커피 사이트 운영 중 발생한 접속 장애 및 최근 도입한 캐시 메커니즘의 성능 분석 필요성을 느껴서 도입하게 되었습니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt; AWS 내부에서도 Cloud Watch 로 지원을 해주고 있지만 캐시히트율이나 JVM 내부에 대한 분석은 지원해주지 않기 때문에 &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;AWS EC2 상의 스프링 애플리케이션을 로컬 환경에서 Grafana를 통해 모니터링하기로 결정했습니다. &lt;/span&gt;&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;이틀간 테스트 해본결과 로컬에서 계속 가동하여도 큰 문제는 없었으나 추후에 안쓰는 라즈베리파이나 무료 ec2 에 올려놔도 좋을것 같습니다ㅎㅎ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;준비&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1. AWS EC2 인스턴스에서 실행 중인 스프링 부트 애플리케이션+promethus 엔드포인트 활성화&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2. Docker (Promethus, Grafana)&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;3. 로컬 - Ec2 포워딩&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;4. 연결 및 캐시히트율 설정&lt;/span&gt;&amp;nbsp;&lt;/b&gt;&lt;/blockquote&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;Actuator?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;스프링 부트 애플리케이션에 내장된 기능으로, 다양한 애플리케이션 정보를 HTTP 엔드포인트를 통해 제공한다.&lt;/p&gt;
&lt;figure id=&quot;og_1712125919181&quot; style=&quot;color: #333333; text-align: start;&quot; data-og-image=&quot;&quot; data-og-url=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html&quot; data-og-source-url=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html&quot; data-og-host=&quot;docs.spring.io&quot; data-og-description=&quot;You can enable recording of HTTP exchanges by providing a bean of type HttpExchangeRepository in your application&amp;rsquo;s configuration. For convenience, Spring Boot offers InMemoryHttpExchangeRepository, which, by default, stores the last 100 request-response&quot; data-og-title=&quot;Production-ready Features&quot; data-og-type=&quot;website&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html&quot; data-source-url=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('&amp;quot;&amp;quot;');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;Production-ready Features&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;You can enable recording of HTTP exchanges by providing a bean of type HttpExchangeRepository in your application&amp;rsquo;s configuration. For convenience, Spring Boot offers InMemoryHttpExchangeRepository, which, by default, stores the last 100 request-response&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;docs.spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션 상태 -healty check 가능&lt;/li&gt;
&lt;li&gt;컨텍스트 빈 목록&lt;/li&gt;
&lt;li&gt;JVM 상태 -메모리 사용 상태 추적 가능&lt;/li&gt;
&lt;li&gt;HTTP 요청 및 응답 추적 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Prometheus?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로메테우스는 오픈 소스 모니터링 시스템으로, 다양한 데이터 소스에서 시계열 데이터를 수집, 저장 및 쿼리할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 위의 엑츄에이터는 프로메테우스와 쉽게 통합되어 애플리케이션 메트릭을 프로메테우스에 노출할 수 있다.&lt;/p&gt;
&lt;figure id=&quot;og_1712125919182&quot; style=&quot;color: #333333; text-align: start;&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gZvBk/hyVGIQWwb4/Rnnk7QtwQc9llRQX9TMhF1/img.png?width=192&amp;amp;height=192&amp;amp;face=0_0_192_192,https://scrap.kakaocdn.net/dn/cxFoRf/hyVJ4Lx84l/ZC7OXhOHkQm3eWh6oyLrNK/img.png?width=1351&amp;amp;height=811&amp;amp;face=0_0_1351_811&quot; data-og-url=&quot;https://prometheus.io/docs/introduction/overview/&quot; data-og-source-url=&quot;https://prometheus.io/docs/introduction/overview/&quot; data-og-host=&quot;prometheus.io&quot; data-og-description=&quot;An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.&quot; data-og-title=&quot;Overview | Prometheus&quot; data-og-type=&quot;website&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://prometheus.io/docs/introduction/overview/&quot; data-source-url=&quot;https://prometheus.io/docs/introduction/overview/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gZvBk/hyVGIQWwb4/Rnnk7QtwQc9llRQX9TMhF1/img.png?width=192&amp;amp;height=192&amp;amp;face=0_0_192_192,https://scrap.kakaocdn.net/dn/cxFoRf/hyVJ4Lx84l/ZC7OXhOHkQm3eWh6oyLrNK/img.png?width=1351&amp;amp;height=811&amp;amp;face=0_0_1351_811');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;Overview | Prometheus&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;prometheus.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함께 사용하는 이점&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;프로메테우스는 PromQL이라는 강력한 쿼리 언어를 제공하여 원하는 메트릭 데이터를 추출하고 분석할 수 있다.&lt;/li&gt;
&lt;li&gt;프로메테우스는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메트릭 기반 알림을 설정&lt;/b&gt;하여 특정 조건 충족 시 어드민에게 알릴 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Grafana?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;엑츄에이터와 프로메테우스에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;수집된 데이터를 시각화&lt;/b&gt;한다.&lt;/p&gt;
&lt;figure id=&quot;og_1712125919183&quot; style=&quot;color: #333333; text-align: start;&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Z08K0/hyVGEgFVsM/bmYsKvuZTfi45LVGkowjxk/img.jpg?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/mIYZZ/hyVGJWBMYt/hSRlRWbwKayaOipLKckdnk/img.jpg?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700&quot; data-og-url=&quot;https://grafana.com/docs/&quot; data-og-source-url=&quot;https://grafana.com/docs/&quot; data-og-host=&quot;grafana.com&quot; data-og-description=&quot;Thank you! Your message has been received!&quot; data-og-title=&quot;Technical documentation | Grafana Labs&quot; data-og-type=&quot;website&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://grafana.com/docs/&quot; data-source-url=&quot;https://grafana.com/docs/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Z08K0/hyVGEgFVsM/bmYsKvuZTfi45LVGkowjxk/img.jpg?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/mIYZZ/hyVGJWBMYt/hSRlRWbwKayaOipLKckdnk/img.jpg?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;Technical documentation | Grafana Labs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;Thank you! Your message has been received!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;grafana.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 우리는 Springb&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;oot 애플리케이션에서&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;b&gt;1. Actuator를 사용하여 애플리케이션의 내부 상태와 메트릭 데이터를 특정 엔드포인트로 노출&lt;/b&gt;&lt;/span&gt;하고&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;2. Prometheus가 데이터&lt;/span&gt;&amp;nbsp;수집을 한 후&lt;/b&gt;에&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Grafana 로 수집된 데이터를 시각화&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;스프링 &lt;b&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;promethus 엔드포인트 활성화&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;스프링의 build. gradle 파일에 &lt;b&gt;actuator 와 promethus 를 임포트&lt;/b&gt;&amp;nbsp;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;146&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blhVtI/btsGh6s1dym/kvJwuzFzKwQBf8jkvj2apK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blhVtI/btsGh6s1dym/kvJwuzFzKwQBf8jkvj2apK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blhVtI/btsGh6s1dym/kvJwuzFzKwQBf8jkvj2apK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblhVtI%2FbtsGh6s1dym%2FkvJwuzFzKwQBf8jkvj2apK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1270&quot; height=&quot;146&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;146&quot;/&gt;&lt;/span&gt;&lt;/figure&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;추가적으로 노출할 metric 이나 포트 등 설정을 해주어야하는데 보안상 프로젝트가 실행되는 포트(8080)에 deploy 하거나 default 값인 url (/actuator/prometheus)로 설정을 하면 공격 당하기 쉽기 때문에 적절히 바꿔주는게 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz8hqh/btsGjOeigBa/tsau8C9uT97pzsGKozoNM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz8hqh/btsGjOeigBa/tsau8C9uT97pzsGKozoNM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz8hqh/btsGjOeigBa/tsau8C9uT97pzsGKozoNM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz8hqh%2FbtsGjOeigBa%2Ftsau8C9uT97pzsGKozoNM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1562&quot; height=&quot;392&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;/figure&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;(추천) 코드를 업데이트 하여 먼저 로컬에서 실행을 시켜서 localhost:{ 포트 }/{ 원하는 url } 로 접속하여 정보가 보여지는지 확인합니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qmvF8/btsGkCEpWp2/xmejKSKdKfGDLb8Wq5dDTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qmvF8/btsGkCEpWp2/xmejKSKdKfGDLb8Wq5dDTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qmvF8/btsGkCEpWp2/xmejKSKdKfGDLb8Wq5dDTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqmvF8%2FbtsGkCEpWp2%2FxmejKSKdKfGDLb8Wq5dDTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1288&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1288&quot;/&gt;&lt;/span&gt;&lt;/figure&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;위와 같은 화면이 보이면 OK&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1858&quot; data-origin-height=&quot;1004&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctOKa8/btsGmvEgK08/go7FNopBuWd48TcHE1Jh6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctOKa8/btsGmvEgK08/go7FNopBuWd48TcHE1Jh6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctOKa8/btsGmvEgK08/go7FNopBuWd48TcHE1Jh6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctOKa8%2FbtsGmvEgK08%2Fgo7FNopBuWd48TcHE1Jh6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1858&quot; height=&quot;1004&quot; data-origin-width=&quot;1858&quot; data-origin-height=&quot;1004&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 Ec2 에도 코드를 업데이트 해줍니다.&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;이후로는 프로젝트가 Deploy 되어있는 구조에 따라서 &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt; 접근 방식이 달라집니다. 예를 들어, 단순히 Spring 애플리케이션을 EC2에 배포하고 AWS가 제공하는 엔드포인트를 통해 접근하는 경우, 동일한 방식으로 Prometheus에 접근할 수 있습니다. 그러나 제 경우에는 아래와 같은 인프라 구조로&lt;/span&gt;&amp;nbsp;배포중에 있기에&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;866&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btcB5r/btsGlgVdMPO/xVhxd05MxiFWUJIBedhDN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btcB5r/btsGlgVdMPO/xVhxd05MxiFWUJIBedhDN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btcB5r/btsGlgVdMPO/xVhxd05MxiFWUJIBedhDN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtcB5r%2FbtsGlgVdMPO%2FxVhxd05MxiFWUJIBedhDN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;606&quot; height=&quot;410&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;866&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;도메인을 통한 접속을 위해 CloudFront를 사용하고 있지만, Prometheus의 포트를 CloudFront에서 직접 열어 접근하는 방식은 보안상 적절하지 않다고 판단했습니다. 이외에도 &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt; 모니터링 데이터를 수집하는 시스템은 &lt;/span&gt;&lt;/span&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;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;SH 포워딩을 사용하여 EC2 인스턴스 상의 Prometheus 포트와 로컬 시스템의 Prometheus 와 Grafana 로 모니터링 할 계획입니다.&lt;/span&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;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Docker 로 Prometheus , Grafana 말아주기&lt;/span&gt;&lt;/h3&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;span&gt;Prometheus.yml&amp;nbsp; 설정파일을 따로 만들어주었다.&lt;/span&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;span&gt;아래 공식문서를 참고했다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1712128208356&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Configuration | Prometheus&quot; data-og-description=&quot;An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.&quot; data-og-host=&quot;prometheus.io&quot; data-og-source-url=&quot;https://prometheus.io/docs/prometheus/latest/configuration/configuration/&quot; data-og-url=&quot;https://prometheus.io/docs/prometheus/latest/configuration/configuration/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/caCIM6/hyVGJh09Bg/K7k2tnBKuHJYKG1F5CLKuk/img.png?width=192&amp;amp;height=192&amp;amp;face=0_0_192_192&quot;&gt;&lt;a href=&quot;https://prometheus.io/docs/prometheus/latest/configuration/configuration/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://prometheus.io/docs/prometheus/latest/configuration/configuration/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/caCIM6/hyVGJh09Bg/K7k2tnBKuHJYKG1F5CLKuk/img.png?width=192&amp;amp;height=192&amp;amp;face=0_0_192_192');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Configuration | Prometheus&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;prometheus.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;1118&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4HWZg/btsGlfhLoiG/1FB8yQJQNeIKZ2225IlJd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4HWZg/btsGlfhLoiG/1FB8yQJQNeIKZ2225IlJd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4HWZg/btsGlfhLoiG/1FB8yQJQNeIKZ2225IlJd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4HWZg%2FbtsGlfhLoiG%2F1FB8yQJQNeIKZ2225IlJd0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;712&quot; height=&quot;289&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;1118&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Global 설정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;scrape_interval: 15s: Prometheus가 메트릭을 수집하는 간격&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Scrape 설정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;prometheus 메트릭을 수집
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타겟으로 localhost:{ 포트} 을 지정하여 Prometheus 자체 모니터링을 한다.&lt;/li&gt;
&lt;li&gt;이후에 grafana를 외부 pc에 올렸을때 prometheus 의 상태를 확인 하기 위함이나&lt;span style=&quot;color: #666666;&quot;&gt; 지금 다시 생각해보니 쿠버네티스에서 관리해버리면 굳이 필요없을것 같다ㅎㅎ&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;spring-actuator 스프링 애플리케이션의 메트릭을 수집
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;metrics_path는 스프링 actuator 가 메트릭을 노출하는 경로&lt;/li&gt;
&lt;li&gt;scrape_interval은 job의 메트릭 수집 간격, 나중에 조금 늘릴 생각이다. 30s~1m 정도&lt;/li&gt;
&lt;li&gt;targets host.docker.internal:{ ssh로 포워딩 한 포트 }을 지정&lt;br /&gt;&lt;b&gt;(Docker 컨테이너가 호스트 시스템의 서비스에 접근할 때 사용하는 DNS 이름) &lt;/b&gt;아래 공식 문서 참고&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1712129064188&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Explore networking features on Docker Desktop&quot; data-og-description=&quot;Understand how networking works on Docker Desktop and see the known limitations&quot; data-og-host=&quot;docs.docker.com&quot; data-og-source-url=&quot;https://docs.docker.com/desktop/networking/&quot; data-og-url=&quot;https://docs.docker.com/desktop/networking/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.docker.com/desktop/networking/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.docker.com/desktop/networking/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Explore networking features on Docker Desktop&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Understand how networking works on Docker Desktop and see the known limitations&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.docker.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; Docker-compose.yml&amp;nbsp;  &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Prometheus와 Grafana를 Docker 컨테이너로 실행하기 위한 설정을 하였다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt; 이 또한 문서에 친절히 나와있다. 여담으로 이번엔 기술블로그를 보지 않고 이렇게 구현하면 되지 않을까? 구조를 예상하고 메뉴얼로만 만들었는데 뚝딱 되서 쾌감이 좀 있었다 ㅎㅎ&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1712129228293&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Installation | Prometheus&quot; data-og-description=&quot;An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.&quot; data-og-host=&quot;prometheus.io&quot; data-og-source-url=&quot;https://prometheus.io/docs/prometheus/latest/installation/&quot; data-og-url=&quot;https://prometheus.io/docs/prometheus/latest/installation/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/doqnmM/hyVGIcjGLK/MykvOsjt8DK5N29nknDoZk/img.png?width=192&amp;amp;height=192&amp;amp;face=0_0_192_192&quot;&gt;&lt;a href=&quot;https://prometheus.io/docs/prometheus/latest/installation/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://prometheus.io/docs/prometheus/latest/installation/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/doqnmM/hyVGIcjGLK/MykvOsjt8DK5N29nknDoZk/img.png?width=192&amp;amp;height=192&amp;amp;face=0_0_192_192');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Installation | Prometheus&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;An open-source monitoring system with a dimensional data model, flexible query language, efficient time series database and modern alerting approach.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;prometheus.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1712129260182&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Run Grafana Docker image |  Grafana documentation&quot; data-og-description=&quot;Enterprise Open source Run Grafana Docker image You can use Grafana Cloud to avoid installing, maintaining, and scaling your own instance of Grafana. Create a free account to get started, which includes free forever access to 10k metrics, 50GB logs, 50GB t&quot; data-og-host=&quot;grafana.com&quot; data-og-source-url=&quot;https://grafana.com/docs/grafana/latest/setup-grafana/installation/docker/&quot; data-og-url=&quot;https://grafana.com/docs/grafana/latest/setup-grafana/installation/docker/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ckNDM9/hyVGIKbjHx/UkqgstaZN9r8KR8UCQVmK1/img.jpg?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/yFsar/hyVGRNUDNF/rAtW0PDiSEfDNMHoUoEuY0/img.jpg?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700&quot;&gt;&lt;a href=&quot;https://grafana.com/docs/grafana/latest/setup-grafana/installation/docker/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://grafana.com/docs/grafana/latest/setup-grafana/installation/docker/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ckNDM9/hyVGIKbjHx/UkqgstaZN9r8KR8UCQVmK1/img.jpg?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/yFsar/hyVGRNUDNF/rAtW0PDiSEfDNMHoUoEuY0/img.jpg?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Run Grafana Docker image | Grafana documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Enterprise Open source Run Grafana Docker image You can use Grafana Cloud to avoid installing, maintaining, and scaling your own instance of Grafana. Create a free account to get started, which includes free forever access to 10k metrics, 50GB logs, 50GB t&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;grafana.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1682&quot; data-origin-height=&quot;1148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnx71I/btsGiY2QWO9/Q0WMudmk3u9k8v3q8UIHRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnx71I/btsGiY2QWO9/Q0WMudmk3u9k8v3q8UIHRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnx71I/btsGiY2QWO9/Q0WMudmk3u9k8v3q8UIHRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbnx71I%2FbtsGiY2QWO9%2FQ0WMudmk3u9k8v3q8UIHRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1682&quot; height=&quot;1148&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1682&quot; data-origin-height=&quot;1148&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Prometheus&amp;nbsp;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;image: prom/prometheus: Prometheus 공식 Docker 이미지&lt;/li&gt;
&lt;li&gt;ports: - &quot; ----:9090&quot;: 호스트의 포트를 컨테이너의 9090 포트에 바인딩&lt;/li&gt;
&lt;li&gt;volumes: Prometheus 데이터를 저장할 볼륨을 마운트&lt;/li&gt;
&lt;li&gt;command: &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;현재 디렉토리의 prometheus.yml 파일(아까 만든거)을 컨테이너의 /etc/prometheus/prometheus.yml에 마운트하여 Prometheus 설정을 제공, &lt;/span&gt;Prometheus 실행 시 사용할 명령어를 미리 지정&lt;/li&gt;
&lt;li&gt;networks: 서비스가 monitoring-network라는 Docker 브리지 네트워크에 연결되도록 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Grafana&amp;nbsp;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;image: grafana/grafana: Grafana 공식 Docker 이미지를 사용합니다.&lt;/li&gt;
&lt;li&gt;ports: - &quot;3030:3000&quot;: 호스트의 3030 포트를 컨테이너의 3000 포트에 바인딩&lt;/li&gt;
&lt;li&gt;volumes: - grafana-data:/var/lib/grafana: Grafana 데이터를 저장할 볼륨을 /var/lib/grafana에 마운트&lt;/li&gt;
&lt;li&gt;environment: Grafana의 관리자 패스워드와 사용자 가입 허용 여부(로컬에서 사용하기에 문제없다)&lt;/li&gt;
&lt;li&gt;networks: - &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;Docker 브리지 네트워크에 연결되도록 설정&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 및 볼륨 설정&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;monitoring-network: 서비스 간 통신을 위한 사용자 정의 Docker 네트워크입니다.&lt;/li&gt;
&lt;li&gt;grafana-data: Grafana 데이터를 저장하기 위한 볼륨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2498&quot; data-origin-height=&quot;1324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0SjD8/btsGjPRZU6E/lWR9wdEnmt7FD3I0B5LiwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0SjD8/btsGjPRZU6E/lWR9wdEnmt7FD3I0B5LiwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0SjD8/btsGjPRZU6E/lWR9wdEnmt7FD3I0B5LiwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0SjD8%2FbtsGjPRZU6E%2FlWR9wdEnmt7FD3I0B5LiwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2498&quot; height=&quot;1324&quot; data-origin-width=&quot;2498&quot; data-origin-height=&quot;1324&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;로컬 특정 포트로 SSH 이용하여 포워딩&lt;/span&gt;&lt;/h3&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;pre id=&quot;code_1712134217827&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ssh -L { 포워딩 하고싶은 로컬 대상 포트} :localhost:{ 스프링 actuator 포트} user@your-ec2-public-dns&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;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;이렇게 매번 명령어를 입력해도 좋지만 난 .ssh 내의 config 파일에 또 다른 호스트를 추가해주었다.&lt;/span&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;/p&gt;
&lt;figure id=&quot;og_1712134383709&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;SSH Tunneling: Client Command &amp;amp; Server Configuration&quot; data-og-description=&quot;SSH port forwarding is a mechanism in SSH for tunneling application ports from the client machine to the server machine or vice versa.&quot; data-og-host=&quot;www.ssh.com&quot; data-og-source-url=&quot;https://www.ssh.com/academy/ssh/tunneling-example#local-forwarding&quot; data-og-url=&quot;https://www.ssh.com/academy/ssh/tunneling-example&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/BL7DJ/hyVJYq4afw/MbONFmBL5zS1AdbzVdQ8jK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/YIGrD/hyVJ4dMJhF/TzoXvFrww03UxyhIISgpw0/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/buDqWY/hyVJXMt8oK/MKUgY6hAQlCmIfwKWDTCrK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400&quot;&gt;&lt;a href=&quot;https://www.ssh.com/academy/ssh/tunneling-example#local-forwarding&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.ssh.com/academy/ssh/tunneling-example#local-forwarding&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/BL7DJ/hyVJYq4afw/MbONFmBL5zS1AdbzVdQ8jK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/YIGrD/hyVJ4dMJhF/TzoXvFrww03UxyhIISgpw0/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/buDqWY/hyVJXMt8oK/MKUgY6hAQlCmIfwKWDTCrK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SSH Tunneling: Client Command &amp;amp; Server Configuration&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SSH port forwarding is a mechanism in SSH for tunneling application ports from the client machine to the server machine or vice versa.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.ssh.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zmfdR/btsGjFozuAJ/LkO0eIfrnPmjW8f8JdFBY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zmfdR/btsGjFozuAJ/LkO0eIfrnPmjW8f8JdFBY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zmfdR/btsGjFozuAJ/LkO0eIfrnPmjW8f8JdFBY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzmfdR%2FbtsGjFozuAJ%2FLkO0eIfrnPmjW8f8JdFBY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;544&quot; height=&quot;215&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;로컬 포워드 옵션을 이용해&amp;nbsp; &amp;nbsp;[ 로컬 대상 포트 : localhost:EC2 인스턴스의 포트 ] 해주면 된다.&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;이후에 ssh (호스트명)으로 ssh 접속을 한 후에 localhost:로컬 대상 포트 로 접근을 하면 Ec2 에 올라와있는 스프링 부트의 actuator 가 뿌려주는 메트릭들을 받을수 있는걸 확인할 수있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qmvF8/btsGkCEpWp2/xmejKSKdKfGDLb8Wq5dDTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qmvF8/btsGkCEpWp2/xmejKSKdKfGDLb8Wq5dDTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qmvF8/btsGkCEpWp2/xmejKSKdKfGDLb8Wq5dDTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqmvF8%2FbtsGkCEpWp2%2FxmejKSKdKfGDLb8Wq5dDTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;697&quot; height=&quot;299&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1288&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; data-ke-style=&quot;style7&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Grafana 에 Prometheus&amp;nbsp; 연결&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 deploy 한 Grafana의 로컬 포트로 접속하면 Grafana 에 접속이 가능하다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;좌측에 DataSource&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1073&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSVaxE/btsGkDwxEDl/KVgmYvg1b72Otfd1PMTK5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSVaxE/btsGkDwxEDl/KVgmYvg1b72Otfd1PMTK5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSVaxE/btsGkDwxEDl/KVgmYvg1b72Otfd1PMTK5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSVaxE%2FbtsGkDwxEDl%2FKVgmYvg1b72Otfd1PMTK5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;665&quot; height=&quot;473&quot; data-origin-width=&quot;1073&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&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;우상단에 Add new db&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2126&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTYeW5/btsGlX85Bgj/S6knY2K9AHvWyqY7l7mW9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTYeW5/btsGlX85Bgj/S6knY2K9AHvWyqY7l7mW9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTYeW5/btsGlX85Bgj/S6knY2K9AHvWyqY7l7mW9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTYeW5%2FbtsGlX85Bgj%2FS6knY2K9AHvWyqY7l7mW9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;697&quot; height=&quot;150&quot; data-origin-width=&quot;2126&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;우린 Prometheus 로 했으니 Prometheus 를 선택한다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2130&quot; data-origin-height=&quot;1842&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xlrWx/btsGj4airlE/D74YNB7JSEdr7D5wKOxVn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xlrWx/btsGj4airlE/D74YNB7JSEdr7D5wKOxVn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xlrWx/btsGj4airlE/D74YNB7JSEdr7D5wKOxVn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxlrWx%2FbtsGj4airlE%2FD74YNB7JSEdr7D5wKOxVn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;692&quot; height=&quot;598&quot; data-origin-width=&quot;2130&quot; data-origin-height=&quot;1842&quot;/&gt;&lt;/span&gt;&lt;/figure&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;이후에는 아래와 같은 설정 창이 나오는데 Connection 항목에 위에서 메트릭을 확인했다고 해당 url 을 신나게 적으면 안된다 ㅎㅎ&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 url 에서 메트릭을 수집하는 Prometheus 의 위치로 작성을 해주어야하는데&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker inspect 명령어로 직접 IP 를 찾아서 포트와 함께 입력해두어도 좋고 docker 생성시에 프로필 명으로 사용했던 prometheus 를 그대로 사용해도 무방하다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2118&quot; data-origin-height=&quot;1172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6pDLp/btsGjNmlcRs/qvVBENLmNe9CBvJbLrJd4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6pDLp/btsGjNmlcRs/qvVBENLmNe9CBvJbLrJd4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6pDLp/btsGjNmlcRs/qvVBENLmNe9CBvJbLrJd4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6pDLp%2FbtsGjNmlcRs%2FqvVBENLmNe9CBvJbLrJd4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;714&quot; height=&quot;395&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2118&quot; data-origin-height=&quot;1172&quot;/&gt;&lt;/span&gt;&lt;/figure&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;이후에 Save &amp;amp; Test 로 연결이 되나 확인해보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2144&quot; data-origin-height=&quot;1036&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XS5fC/btsGkBS3AhY/1BbRHYvRlvINz6X0agyQG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XS5fC/btsGkBS3AhY/1BbRHYvRlvINz6X0agyQG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XS5fC/btsGkBS3AhY/1BbRHYvRlvINz6X0agyQG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXS5fC%2FbtsGkBS3AhY%2F1BbRHYvRlvINz6X0agyQG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;693&quot; height=&quot;335&quot; data-origin-width=&quot;2144&quot; data-origin-height=&quot;1036&quot;/&gt;&lt;/span&gt;&lt;/figure&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;br /&gt;&lt;br /&gt;&lt;br /&gt;글이 길어져서 캐시 히트율이나 오픈라이브러리에 사람들이 만들어놓은 대시보드를 이용해서 손쉽게 모니터링 하는 법을 간략하게 작성하겠다.&lt;/p&gt;</description>
      <category>Amazon</category>
      <category>ec2</category>
      <category>Grafana</category>
      <category>prometheus</category>
      <category>ssh 포워딩</category>
      <category>도커 브릿지</category>
      <category>스프링 모니터링</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/197</guid>
      <comments>https://nstgic3.tistory.com/entry/EC2%EC%83%81%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-PromethusGrafana-%EB%A1%9C-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81-%EC%84%B8%ED%8C%85#entry197comment</comments>
      <pubDate>Wed, 3 Apr 2024 18:20:11 +0900</pubDate>
    </item>
    <item>
      <title>Optional: 안정적인 Null 처리 그리고 orElse(), orElseGet(), orElseThrow() 에 대한 이해</title>
      <link>https://nstgic3.tistory.com/entry/Optional-%EC%95%88%EC%A0%95%EC%A0%81%EC%9D%B8-Null-%EC%B2%98%EB%A6%AC-%EA%B7%B8%EB%A6%AC%EA%B3%A0-orElse-orElseGet-orElseThrow-%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B4%ED%95%B4</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목차&lt;/span&gt;&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;br /&gt;스프링 그리고 Java를 사용하다 보면 null 값 핸들링이 무척 중요하다는 사실을 깨닫고 적절한 처리에 대해 고민을 하게 된다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;특히 NullPointerException의 발생 또한 자주 접하게 된다. Java에서는 이러한 문제를 해결하기 위해 Optional 클래스를 도입했다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1698122778438&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Optional (Java Platform SE 8 )&quot; data-og-description=&quot;A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value. Additional methods that depend on the presence or absence of a contained value are provided, such as orEl&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html&quot; data-og-url=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Optional (Java Platform SE 8 )&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value. Additional methods that depend on the presence or absence of a contained value are provided, such as orEl&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;래퍼런스에 따르면 Optional&amp;lt;T&amp;gt;는 값(T 타입)을 포함할 수도, 포함하지 않을 수도 있다고 한다. 따라서 이 클래스는 값의 존재 여부에 따라 여러 유용한 메서드를 제공하며, 이를 통해 null 값 관련 이슈를 안정적으로 처리할 수 있게 된다.&lt;/span&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;래퍼런스를 참조하면 총 세가지의 메서드를 소개해주고 있는데&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;isPresent(): 값이 존재하는지 여부를 확인하는 메서드&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;get(): 값이 존재할 경우 해당 값을 반환&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;orElse(), orElseGet(), orElseThrow(): 값의 존재 여부에 따라 다른 동작을 수행하는 메서드&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;자주 사용하는 종류는 이렇게 크게 세가지 인것 같다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;이번 포스팅에서는 Java의 Optional 클래스의 핵심 메서드 중에서도 orElse, orElseGet, orElseThrow의 사용법과 차이점에 대해 자세히 알아보자&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;orElse와 orElseGet 의 차이&lt;/span&gt;&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;orElse는 Optional 객체가 값이 포함되어 있지 않을 때, 반환할 기본 값을 직접 전달한다.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTGXIB/btsy3N07Bst/lE4CM4fMsYOLUy5gKY5181/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTGXIB/btsy3N07Bst/lE4CM4fMsYOLUy5gKY5181/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTGXIB/btsy3N07Bst/lE4CM4fMsYOLUy5gKY5181/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTGXIB%2Fbtsy3N07Bst%2FlE4CM4fMsYOLUy5gKY5181%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;612&quot; height=&quot;212&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1698123271252&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Optional&amp;lt;String&amp;gt; optional = Optional.ofNullable(null);
String result = optional.orElse(&quot;Default Value&quot;);
System.out.println(result);  // 출력: Default Value&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&lt;br /&gt;&amp;nbsp;orElse 내부의 연산(즉, 인수로 전달된 값)은 Optional의 값의 &lt;b&gt;존재 여부와 상관없이 항상 평가&lt;/b&gt;된다.&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;977&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dkQbvH/btsy0gWZyZp/RKFweUZdhpag43IExaAEK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dkQbvH/btsy0gWZyZp/RKFweUZdhpag43IExaAEK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dkQbvH/btsy0gWZyZp/RKFweUZdhpag43IExaAEK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdkQbvH%2Fbtsy0gWZyZp%2FRKFweUZdhpag43IExaAEK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;589&quot; height=&quot;235&quot; data-origin-width=&quot;977&quot; data-origin-height=&quot;390&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1698123378481&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Optional&amp;lt;String&amp;gt; optional = Optional.ofNullable(null);
String result = optional.orElseGet(() -&amp;gt; {
    // 여기서의 연산은 값이 없는 경우에만 실행됩니다.
    return &quot;Generated Default Value&quot;;
});

System.out.println(result);  // 출력: Generated Default Value&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&lt;br /&gt;&amp;nbsp;orElseGet은 Supplier 혹은 람다 표현식을 통해 제공된 값을 반환한다. 중요한 점은 값이 없는 경우에만 해당 Supplier 혹은 람다 표현식이 실행된다는 것이다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;따라서 정리하자면 둘의 차이점은&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1698124060508&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public T orElse(T other)
public T orElseGet(Supplier&amp;lt;? extends T&amp;gt; other)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&amp;nbsp;orElse는&lt;b&gt; 바로 값을 받기에&lt;/b&gt; 복잡한 계산이나 연산을 필요로 하는 경우에는 그 연산이 무조건 실행되고&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&amp;nbsp;orElseGet은 Supplier&amp;lt;T&amp;gt; 타입의 &lt;b&gt;인자를 받아서&lt;/b&gt; Optional&lt;b&gt; 값이 없을 때만 해당 Supplier (람다식이나 메서드 참조)를 실행&lt;/b&gt;한다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;만일 orElse 에 지정되어있는 연산이 많은 자원을 필요로 하는 연산이라면 orElse는 불필요한 연산을 하기위해서 자원과 시간을 낭비하게 될 것이다.&amp;nbsp;&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;구체적인 성능차이 또한 Baeldung 에서 측정해본 결과 orElseGet이 더 뛰어난 성능을 가짐을 확인할 수 있었다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&lt;a href=&quot;https://www.baeldung.com/java-optional-or-else-vs-or-else-get&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.baeldung.com/java-optional-or-else-vs-or-else-get&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;190&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgbWtz/btsy4csPfz9/XTXnDWpUnizMCven8MXgFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgbWtz/btsy4csPfz9/XTXnDWpUnizMCven8MXgFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgbWtz/btsy4csPfz9/XTXnDWpUnizMCven8MXgFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgbWtz%2Fbtsy4csPfz9%2FXTXnDWpUnizMCven8MXgFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;788&quot; height=&quot;190&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;190&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;orElseThrow&lt;/span&gt; &lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;orElseThrow는 orElseGet과 비슷하게 Optional 객체가 비어 있을 경우, Supplier 혹은 람다 표현식을 통해 제공된 예외를 발생시킨다.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698123477877&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Optional&amp;lt;String&amp;gt; optional = Optional.ofNullable(null);
String result = optional.orElseThrow(() -&amp;gt; new NoSuchElementException(&quot;No value present!&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&lt;br /&gt;예외 공급자가 null일 경우 NullPointerException이 발생한다. 따라서 예외를 제공할 때는 항상 유효한 예외 객체를 반환해야 합니다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;따라서 결론적으로 orElse()를 사용하면 기본 객체를 불필요하게 생성할 수도 있기에 요구 사항이나 코드의 맥락에 따라 orElse()와 orElseGet() 중 어느 것을 사용할지 결정해야 한다.&lt;/span&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;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;추가적으로 멘토분께서 조언해주신 내용을 첨부하고 포스팅 마무리하겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;397&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NsbG5/btsy4bm8WYP/U07Ha0FrpazcB80bzELiyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NsbG5/btsy4bm8WYP/U07Ha0FrpazcB80bzELiyk/img.png&quot; data-alt=&quot;+ 래퍼런스를 확인하는 습관을 기르자&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NsbG5/btsy4bm8WYP/U07Ha0FrpazcB80bzELiyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNsbG5%2Fbtsy4bm8WYP%2FU07Ha0FrpazcB80bzELiyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;754&quot; height=&quot;320&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;397&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;+ 래퍼런스를 확인하는 습관을 기르자&lt;/figcaption&gt;
&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <category>java</category>
      <category>optional</category>
      <category>orElse()</category>
      <category>orElseGet()</category>
      <category>orElseThrow</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/196</guid>
      <comments>https://nstgic3.tistory.com/entry/Optional-%EC%95%88%EC%A0%95%EC%A0%81%EC%9D%B8-Null-%EC%B2%98%EB%A6%AC-%EA%B7%B8%EB%A6%AC%EA%B3%A0-orElse-orElseGet-orElseThrow-%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B4%ED%95%B4#entry196comment</comments>
      <pubDate>Tue, 24 Oct 2023 14:15:40 +0900</pubDate>
    </item>
    <item>
      <title>23년도 3분기</title>
      <link>https://nstgic3.tistory.com/entry/23%EB%85%84%EB%8F%84-3%EB%B6%84%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;917&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yUROw/btsypxR4hcK/d0GWeEc1otlnyRY74pnw51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yUROw/btsypxR4hcK/d0GWeEc1otlnyRY74pnw51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yUROw/btsypxR4hcK/d0GWeEc1otlnyRY74pnw51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyUROw%2FbtsypxR4hcK%2Fd0GWeEc1otlnyRY74pnw51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1384&quot; height=&quot;917&quot; data-origin-width=&quot;1384&quot; data-origin-height=&quot;917&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;블로그에 마지막 글을 쓴지 거의 3달이 지나갔다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;여유가 생겨 여러 포스팅을 하기 전에 마치 책의 커버와 같은 글을 하나 쓰고 싶었다.&lt;/span&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;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그동안,&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;지금까지 만들었던 생활 관성을 잃지는 않았다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;카카오테크 캠퍼스 2차 교육이 끝나고 3차 프로젝트가 진행중이다. 꽤나 흥미로운 주제로 진행중이어서 즐겁다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1년 전 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;모든 부분을 배우는 입장으로 들어간 &lt;/span&gt;학교 개발 동아리에서는 개발 현황을 관리하고 기술지원을 해주는 개발 부장을 하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;또한 내 경험을 살려서 백엔드 개발자들을 위한 스터디도 주기적으로 진행을 하고 있다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개인사업체에서 사용할 세이렌 오더나 재고/회원 관리를 포함한 웹페이지 서비스도 런칭을 준비중이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단순한 외주 작업이 아니라 인연이 생긴 사장님들하고 같이 작업을 하고 있다.&lt;/span&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;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개인적으로는,&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;너무 러프한 표현이지만 나로 돌아온 기분이다. 어떻게 보면 번아웃이 살짝 왔던것이 아닐까&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;최근 많은 변화가 있었고 있어야 했기에 생각하고 행동하는 것이 아니라 빠른 변화와 성취가 필요했기에 행동을 우선시 했는데 그 생각과 행동의 차이에서 오는 불안함이 조금 쌓였던것이 아닐까 싶다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;최근 나답지 않은 행동을 하는 나를 보면서 이런 상태인걸 깨달은것 같기도 하다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; letter-spacing: 0px;&quot;&gt;지금은 개인적인 휴식과 함께 주변 사람들로부터 여러 방식으로 도움을 받았기에 scatter된 느낌은 사라진것 같다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;따라서&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;지금은? 앞으로 1년 내로 있을 졸업과 취직까지 달릴 준비가 된것 같다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 글이 이번에 쓸 책의 앞쪽 커버라면 졸업을 하거나 취직 수기를 쓰는게 내 뒷쪽 커버가 되지 않을까 싶다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Life</category>
      <category>23년3분기</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/195</guid>
      <comments>https://nstgic3.tistory.com/entry/23%EB%85%84%EB%8F%84-3%EB%B6%84%EA%B8%B0#entry195comment</comments>
      <pubDate>Fri, 13 Oct 2023 16:41:02 +0900</pubDate>
    </item>
    <item>
      <title>대학생 동아리 프로젝트에 대한 고찰</title>
      <link>https://nstgic3.tistory.com/entry/%EB%8C%80%ED%95%99%EC%83%9D-%EB%8F%99%EC%95%84%EB%A6%AC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0</link>
      <description>&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20230710_203450663.jpg&quot; data-origin-width=&quot;1404&quot; data-origin-height=&quot;1052&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vBC1i/btsm92gTpO4/panmGT7hBrHFnKyK6TYUyk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vBC1i/btsm92gTpO4/panmGT7hBrHFnKyK6TYUyk/img.jpg&quot; data-alt=&quot;메타45 06/30&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vBC1i/btsm92gTpO4/panmGT7hBrHFnKyK6TYUyk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvBC1i%2Fbtsm92gTpO4%2FpanmGT7hBrHFnKyK6TYUyk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1404&quot; height=&quot;1052&quot; data-filename=&quot;KakaoTalk_20230710_203450663.jpg&quot; data-origin-width=&quot;1404&quot; data-origin-height=&quot;1052&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;메타45 06/30&lt;/figcaption&gt;
&lt;/figure&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;span style=&quot;color: #333333; font-size: 16px; letter-spacing: 0px; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대학 동아리 활동은 다양한 사람들과 함께 프로젝트를 진행하며 협업을 배울 수 있는 기회이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-size: 16px; letter-spacing: 0px; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;나의 경우에는 1년 동안 12명의 다양한 멤버들과 두 가지 프로젝트를 진행했었고 지금도 진행하고 있다. 이 글에서는 한동안 동아리 활동을 하며 경험하고 깨달은 사실들을 나누고자 한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;당연한 이야기이겠지만 동아리에 참여한 대부분의 사람들은 협업의 가치를 알고, 자신의 아이디어를 서비스로 만들어 사람들에게 제공하고자 하는 열망으로 가득 차 시작을 한다. 그러나, 이 열망은 참여 인원 각자에 따라 다르며, 프로젝트의 전 과정을 견디기가 쉽지 않다. 대학생 특성 상 이 분야에 흥미가 떨어질 수도 있고 한창 개발을 할 타이밍에 시험 기간이나 더 흥미로운 프로젝트 등 다양한 이유로 팀에서 빠지는 경우가 적지 않다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇게 된다면 나가는 사람은 미안함을 남아있는 사람들은 허무함을 느끼게 된다. 그나마 남아있는 인원이 실력이 좋다면 영향이 적겠지만 그 팀에 남아있는 이러한 허무함이 프로젝트를 제대로 마무리하지 못하게 만드는 주범이 되는 경우도 많다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;대학생 수준에서의 한계는 존재한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대학생 수준에서 모든 인원이 한 학기 동안 하나의 프로젝트에 몰입하는 경우는 거의 없긴 하다. 굳이 생각해보자면 첫번째로는 해커톤 등 대회를 통해 수상을 위해 몰입하는 경우, 두번째로는 실제 사업을 위해 프로젝트에 투입되는 경우라고 볼 수 있지만 대학 교내 동아리에서는 쉽지 않다고 본다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;나랑 팀 프로젝트를 했던 동료들이 여기까지 읽을 때 쯤이면 오해가 일어날 소지가 존재하는데 사실 이 포스트를 쓴 이유는 현재 진행 중인 프로젝트에 대한 불만 때문이 아니다. 오히려 이번 프로젝트에서 많이 배우고 있으며, 결과물도 꽤나 성공적이다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;그래서 완성을 하면?&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기획자들이 기획을 하고 처음 기획안을 발표하고 피드백을 받을 때 혹은 기획을 확정할 때 고객들의 니즈 분석에 중점을 두지만 완성 후 한 학기 내내 제작을 하면서 쌓아왔던 기대감보다는 열렬하지 않은 시장 반응에 대한 실망감(대부분)은 불가피한 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사실 대학생의 수준에서 만들어진 서비스들은 프론트/디자이너 측에서는 시중에 기업에서 내놓은 서비스에 비해서 유려한 디자인을 가지고 있지도 않고 서버측 개발자도 나름 테스트 코드로 테스트를 진행해보기도 하였겠지만 유저(뭐든지 하는 사람들)들의 실 사용에 에러나 오류가 뻥뻥 터지는건 어쩔수 없는 현실이다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그럼 당연히 오류를 막 직면하게 되는 개발팀과 그걸 지켜보는 팀원들은 실망감을 느낄수 밖에 없다. (사실 경험이 적어 어쩔수 없겠지만) &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;결과적으로 이러한 일련의 한학기 동안의 기대감 끝에 오는 잠깐의 성취 런칭 이후의 실망감은 프로젝트의 리팩터링을 방해하는 주요 원인 중 하나인것 같다. 또한 팀으로 만든 프로젝트이다보니 리팩터링에 있어서 동료들의 호응도가 중요한데 이 부분에 있어서 많은 팀들이 완성 이후에 서비스 관리를 잘 하지는 않게 된다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 중간중간 내가 글을 쓰며 &amp;lsquo;실망감&amp;rsquo;, &amp;lsquo;허무감&amp;rsquo;, &amp;lsquo;기대 끝에 오는 탈력&amp;rsquo; 등 되게 좋지않은 상황만을 이해했는데 이는 주니어 이기에 경험해보지 않았기에 당연히 오는 감정들이며 이는 충분히 감정의 차원에서 대비할 수 있다고 생각한다. 내 나름의 생각을 아래에 적어보았다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;팀원으로서&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;나름 느낀 이러한 감정을 최소화하는 방법 중 하나는 누구나 동의할 수 있는 공통의 목표를 설정하고, 이를 지속적으로 확인하고 갱신하는 것이다. 이 역할은 팀장만이 할 일이 아니라 일단 자기 자시부터 내가 지금 이 프로젝트에 대해서 달성하고 싶은 목표가 무엇인가를 확실하게 깨닫고(상당히 추상적이지만..) 이를 공유하여 주기적으로 서로의 목표를 확인하는 것이 가장 중요하다. 이런 소통의 부재는 결국 기간의 끝에 가서 무작정 나는 안한다 는 유형과 더이상 못참겠다고 화내는 유형과 이렇게 될 줄 몰랐다고 미안해하는 유형의 사람들을 볼 수 있게 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정리하자면 (막연하지만) 팀원들 간의 공감대를 유지하고, 관리할 수 있는 것이 중요하다는 것이다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;팀장/리더 로서&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;팀원들에게 꾸준한 피드백과 응원을 주는 것도 중요한데 팀장이나 리더는 대부분 기획자가 그 역할을 하는 경우가 많지만 모든 인원이 가져야할 덕목이기도 하다. 지속적으로 모두가 프로젝트에 참여하며 얻는 가치를 인지하고, 그 가치를 통해 보람을 느끼도록 도와야 한다. 동아리의 경우는 협업 경험을 얻거나 서비스 런칭 그리고 이 경험을 살린 취직이지 않을까 싶다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;운영진 으로서&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주기적으로 프로젝트에 참여하는 모든 사람들이 본인의 역할에 대해 인지하고, 그 역할을 충실히 수행하도록 도와야한다. 각자가 수행해야 할 역할을 이해하고, 그에 맞는 책임감을 갖게하여 프로젝트의 목표를 이루게 해주어야한다. 결국엔 운영진도 시간과 자원을 충분히 사용할 인원이 해야 한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;너무 힘들어보이는데?&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그럼에도 불구하고 이 경험을 통해 배울 수 있는 점들이 있다. 모든 팀원이 공유하는 목표를 설정하고 이를 명확히 하는 것, 서로에게 피드백과 격려를 주는 것, 그리고 각자의 역할과 책임을 분명히 하는 것 등이 중요하다는 건 지금 이 글을 보는 사람이 이런 경험이 있을지는 모르겠지만 해봐야 느끼는 부분이긴 하다. 결국 취직 시장에서도 협업 활동 유무를 물어보는 이유도 이러한 활동을 통해 팀 내에서의 감정 관리, 각자의 역할과 책임에 대한 이해, 그리고 공통의 목표를 설정하고 지키는 것 등을 경험해본 사람이 필요한게 아닐까?&lt;/span&gt;&lt;/p&gt;</description>
      <category>Life</category>
      <category>생각</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/194</guid>
      <comments>https://nstgic3.tistory.com/entry/%EB%8C%80%ED%95%99%EC%83%9D-%EB%8F%99%EC%95%84%EB%A6%AC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0#entry194comment</comments>
      <pubDate>Mon, 10 Jul 2023 20:17:41 +0900</pubDate>
    </item>
    <item>
      <title>IntelliJ 위에서 Docker deploy하기</title>
      <link>https://nstgic3.tistory.com/entry/IntelliJ-%EC%9C%84%EC%97%90%EC%84%9C-Docker-deploy%ED%95%98%EA%B8%B0</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목차&lt;/span&gt;&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;intelliJ 내에서도 Docker 플러그인을 통해서 프로젝트에 필요한 컨테이너들 관리가 가능하다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;사실 Docker Desktop을 들어가지 않고도 관리가 가능하다 라는 장점,,, (db를 deploy해도 자동으로 잡아주지도 않는다.) 정도 있는것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;IntelliJ IDEA plugin 에서 수동 설정하여 docker 실행하기&lt;/span&gt;&lt;/h3&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;Ctrl+Alt+S&lt;/b&gt; 단축키를 눌러 IDE 설정에서 '플러그인'을 선택가능하다.&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;이후에는 Service 탭에 Docker Connection으로 도커를 실행시키자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dupxX8/btslS326mfm/XEokrF2JHmpWB8kVmUeAD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dupxX8/btslS326mfm/XEokrF2JHmpWB8kVmUeAD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dupxX8/btslS326mfm/XEokrF2JHmpWB8kVmUeAD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdupxX8%2FbtslS326mfm%2FXEokrF2JHmpWB8kVmUeAD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;657&quot; height=&quot;197&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&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;Docker for X(저절로 잡혀있다.&amp;nbsp; ) 이부분에 대해서는 나중에 platform 관련된 설정을 할 필요가 없는것이랑 상통한다. IntelliJ를 설치할때 부터 유저의 OS가 무엇인지 판별하고 설치를 진행하기 때문에 Docker 에 관련된 설정을 할때에도 저절로 유저의 OS를 인식하여 설정하게 된다고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;1283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnEMEm/btslRp7cBvw/v62jT2wgSncwqU02iVk9g0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnEMEm/btslRp7cBvw/v62jT2wgSncwqU02iVk9g0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnEMEm/btslRp7cBvw/v62jT2wgSncwqU02iVk9g0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnEMEm%2FbtslRp7cBvw%2Fv62jT2wgSncwqU02iVk9g0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;472&quot; height=&quot;445&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;1283&quot;/&gt;&lt;/span&gt;&lt;/figure&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;다음으로는 OK를 누르고 난 이후의 화면이다. 드롭다운의 메뉴중에 Images를 클릭해주도록 하자&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6rwXk/btslUL8B4X0/jX7QjN1skLxyCH38kL6qKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6rwXk/btslUL8B4X0/jX7QjN1skLxyCH38kL6qKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6rwXk/btslUL8B4X0/jX7QjN1skLxyCH38kL6qKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6rwXk%2FbtslUL8B4X0%2FjX7QjN1skLxyCH38kL6qKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;762&quot; height=&quot;185&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지에 본인이 원하는 앱을 검색하도록 해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cksDJU/btslYvKWFMe/b3kK13z72I7O7K5lcI4OsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cksDJU/btslYvKWFMe/b3kK13z72I7O7K5lcI4OsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cksDJU/btslYvKWFMe/b3kK13z72I7O7K5lcI4OsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcksDJU%2FbtslYvKWFMe%2Fb3kK13z72I7O7K5lcI4OsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;710&quot; height=&quot;308&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;letter-spacing: 0px;&quot;&gt;default tag는 lastest로 자동으로 할당되어있다.&lt;/span&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;특정 버전이 필요한 경우에는 docker hub에 들어가서 버전 선택을 하면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doxPb5/btslZheIFZC/2bLRVXm7pOvJoWwM6PsFm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doxPb5/btslZheIFZC/2bLRVXm7pOvJoWwM6PsFm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doxPb5/btslZheIFZC/2bLRVXm7pOvJoWwM6PsFm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoxPb5%2FbtslZheIFZC%2F2bLRVXm7pOvJoWwM6PsFm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;669&quot; height=&quot;290&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Images 목록에 mysql:lastest가 형성되었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 mySQL을 실행하기 위한 파일들은 다운로드가 완료되었다. 이후에는 이미지를 완성하기 위해 설정값(환경설정)을 추가하여 도커 이미지를 완성시켜보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;894&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pbCFX/btslYzfvnBH/si2VbN1P5jJTKqQECauThk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pbCFX/btslYzfvnBH/si2VbN1P5jJTKqQECauThk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pbCFX/btslYzfvnBH/si2VbN1P5jJTKqQECauThk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpbCFX%2FbtslYzfvnBH%2Fsi2VbN1P5jJTKqQECauThk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;394&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;894&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 설정값을 설정해야 되는지는 docker hub위에 있는 mySQL탭을 검색해보면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hub.docker.com/_/mysql&quot;&gt;mysql - Official Image | Docker Hub&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1688096581406&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;mysql - Official Image | Docker Hub&quot; data-og-description=&quot;Quick reference Supported tags and respective Dockerfile links 8.0.33, 8.0, 8, latest, 8.0.33-oracle, 8.0-oracle, 8-oracle, oracle 8.0.33-debian, 8.0-debian, 8-debian, debian 5.7.42, 5.7, 5, 5.7.42-oracle, 5.7-oracle, 5-oracle 5.7.42-debian, 5.7-debian, 5-&quot; data-og-host=&quot;hub.docker.com&quot; data-og-source-url=&quot;https://hub.docker.com/_/mysql&quot; data-og-url=&quot;https://hub.docker.com/_/mysql&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://hub.docker.com/_/mysql&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hub.docker.com/_/mysql&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;mysql - Official Image | Docker Hub&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Quick reference Supported tags and respective Dockerfile links 8.0.33, 8.0, 8, latest, 8.0.33-oracle, 8.0-oracle, 8-oracle, oracle 8.0.33-debian, 8.0-debian, 8-debian, debian 5.7.42, 5.7, 5, 5.7.42-oracle, 5.7-oracle, 5-oracle 5.7.42-debian, 5.7-debian, 5-&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hub.docker.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qzrA4/btslRnhgOfc/LLZQOxq8J2RQAiNfwQVXE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qzrA4/btslRnhgOfc/LLZQOxq8J2RQAiNfwQVXE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qzrA4/btslRnhgOfc/LLZQOxq8J2RQAiNfwQVXE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqzrA4%2FbtslRnhgOfc%2FLLZQOxq8J2RQAiNfwQVXE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;607&quot; height=&quot;190&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;/figure&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Enviromental variable&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;포트 구성을 해주어야한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;port&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MYSQL_ROOT_PASSWORD 설정&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;1508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8ruHh/btslS6yEECv/c87IzdKHsE7dwB0FSA9V3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8ruHh/btslS6yEECv/c87IzdKHsE7dwB0FSA9V3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8ruHh/btslS6yEECv/c87IzdKHsE7dwB0FSA9V3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8ruHh%2FbtslS6yEECv%2Fc87IzdKHsE7dwB0FSA9V3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;369&quot; height=&quot;409&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;1508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-e 값 즉 Enviroment Variable 에 root password 설정을 해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MQhci/btslR7kEYpq/Oqk2diwkhBTmqCF4Dul6o0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MQhci/btslR7kEYpq/Oqk2diwkhBTmqCF4Dul6o0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MQhci/btslR7kEYpq/Oqk2diwkhBTmqCF4Dul6o0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMQhci%2FbtslR7kEYpq%2FOqk2diwkhBTmqCF4Dul6o0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;551&quot; height=&quot;162&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Port Binding 하기&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;743&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ByoK3/btslQkxY6mh/qK9LzssSYm39c3OKJWklYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ByoK3/btslQkxY6mh/qK9LzssSYm39c3OKJWklYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ByoK3/btslQkxY6mh/qK9LzssSYm39c3OKJWklYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FByoK3%2FbtslQkxY6mh%2FqK9LzssSYm39c3OKJWklYk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;210&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;743&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;compose 파일에서의 3306:3306과 같다. (여담이지만 mySQL 5.5 기반의 mariaDB도 3306이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이후에 run을 통해 컨테이너를 만들고 실행을 해보자&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;293&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCP9CI/btslQlDFu9W/1oJBoeW6AUdB3wkPArWne1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCP9CI/btslQlDFu9W/1oJBoeW6AUdB3wkPArWne1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCP9CI/btslQlDFu9W/1oJBoeW6AUdB3wkPArWne1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCP9CI%2FbtslQlDFu9W%2F1oJBoeW6AUdB3wkPArWne1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;693&quot; height=&quot;149&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;293&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;IntelliJ에 등록하기&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;1400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ofoPD/btslUMfoZh9/B3NFTKysuia3a9n0EAXLk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ofoPD/btslUMfoZh9/B3NFTKysuia3a9n0EAXLk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ofoPD/btslUMfoZh9/B3NFTKysuia3a9n0EAXLk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FofoPD%2FbtslUMfoZh9%2FB3NFTKysuia3a9n0EAXLk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;412&quot; height=&quot;424&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;1400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;왜않YML? 같은 이미지로 다중 컨테이너 deploy&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;요리를 할때 레시피가 있으면 좋은 이유가 뭘까?&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;A : 같은 맛을 낼 수있다.(당연한게 아닌가?)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;거기에 추가적으로 내가 매운것을 좋아하면 더 맵게.. 더 달게 등등 바리에이션을 줄 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;비슷하게 도커에 적용하여 호스트 포트에 변경을 주어서 같은 컨테이너를 동시에 여러개를 띄워보자&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;1119&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsQIwR/btslV05xQ2w/mNNF3AYKXkkAxsW0FrwVVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsQIwR/btslV05xQ2w/mNNF3AYKXkkAxsW0FrwVVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsQIwR/btslV05xQ2w/mNNF3AYKXkkAxsW0FrwVVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsQIwR%2FbtslV05xQ2w%2FmNNF3AYKXkkAxsW0FrwVVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;458&quot; height=&quot;377&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;1119&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Container port는 mySQL/mariaDB가 3306을 사용해서 써봤고 톰캣은 8080,, 등 설정을 해주면 된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Host port의 경우에는 내 컴퓨터에 어떤 포트로 deploy 될 것인지를 결정하면 된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;711&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AWsPr/btslS8DiwhR/Ua5pL4UWlID3pmVZDKGhVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AWsPr/btslS8DiwhR/Ua5pL4UWlID3pmVZDKGhVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AWsPr/btslS8DiwhR/Ua5pL4UWlID3pmVZDKGhVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAWsPr%2FbtslS8DiwhR%2FUa5pL4UWlID3pmVZDKGhVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;497&quot; height=&quot;260&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;711&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;더블 mySQL이 가능하다!&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;왜않YML?&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사실 docker-compose를 이용하는게 더 편하긴하다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;위의 방법은 port설정 등 설정을 명세하는 것이 번거롭다.&lt;/li&gt;
&lt;li&gt;여러개의 db 혹은 컨테이너를 deploy 할 때 훨씬 편하다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;yml 파일을 만들어준다.&lt;/p&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;version: &quot;3.1&quot;
services:
  db1:
    image: mysql:latest
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
    ports:
      - 3307:3306
  db2:
    image: mysql:latest
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
    ports:
      - 3306:3306
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;마찬가지로 password와 port 설정이 있어야한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이후에 &amp;gt;&amp;gt; 버튼을 누르게 된다면 컨테이너 두개가 형성된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;628&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYFMGm/btslS84m7UQ/SB6of36XoiLF4h9NehYEZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYFMGm/btslS84m7UQ/SB6of36XoiLF4h9NehYEZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYFMGm/btslS84m7UQ/SB6of36XoiLF4h9NehYEZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYFMGm%2FbtslS84m7UQ%2FSB6of36XoiLF4h9NehYEZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;542&quot; height=&quot;250&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;628&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;심지어는 따로 구분이 가능해서 더 효율적인 관리가 가능해졌다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkEwnW/btslR6e0I9O/7QViv8t8t9dkP1kU37ABL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkEwnW/btslR6e0I9O/7QViv8t8t9dkP1kU37ABL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkEwnW/btslR6e0I9O/7QViv8t8t9dkP1kU37ABL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkEwnW%2FbtslR6e0I9O%2F7QViv8t8t9dkP1kU37ABL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;533&quot; height=&quot;210&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;도커는 배포 측면에서 아주 유용한 도구이다. 따라서 환경을 구성할때(DB 가 필요할때 도커 이미지를 이용하여 내가 원하는 설정을 추가하여 컨테이너를 만들어 이용하는 경우) 아주 유용하다. 화면의 이동 없이 intelliJ 내에서 전부 관리가 가능하였기에 유용하다고 느껴져 포스팅을 진행해보았다.&lt;/span&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;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;추가로 말을 하자면 사용할 컨테이너가 하나여도 docker-compose를 통해 deploy 하는것이 좋다고 느껴진다.&amp;nbsp; 해당 방식의 단점이 이미 로컬 내에 container 가 작동중에 있다면 해당 플러그인에서는 이 프로젝트와 관련이 있는 컨테이너만 보여주는 것이 아니라 지금 작동하고 있는 모든 컨테이너와 존재하고 있는 이미지를 전부 보여주기 때문에 이를 적절하게 구분 할 수 있는 docker-compose 을 이용한 실행을 추천한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Docker</category>
      <category>docker</category>
      <category>IntelliJ</category>
      <category>Service plugin</category>
      <category>데이터베이스</category>
      <category>인텔리제이 도커</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/193</guid>
      <comments>https://nstgic3.tistory.com/entry/IntelliJ-%EC%9C%84%EC%97%90%EC%84%9C-Docker-deploy%ED%95%98%EA%B8%B0#entry193comment</comments>
      <pubDate>Fri, 30 Jun 2023 12:56:55 +0900</pubDate>
    </item>
    <item>
      <title>[SecurityContextHolder] Authentication 분석하기, principal 객체로 유저 이름 가져오기</title>
      <link>https://nstgic3.tistory.com/entry/SecurityContextHolder-Authentication-%EB%B6%84%EC%84%9D%ED%95%98%EA%B8%B0-principal-%EA%B0%9D%EC%B2%B4%EB%A1%9C-%EC%9C%A0%EC%A0%80-%EC%9D%B4%EB%A6%84-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목차&lt;/span&gt;&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;br /&gt;웹 애플리케이션에서 사용자 인증은 필수적인 요소 중 하나이고 회원 기능이 있다면 회원 식별을 위한 인증절차는 필수적이다. 따라서 이번 블로그 포스팅에서는 Spring Security에서 사용자 인증 정보를 얻어오는 두 가지 주요 방법, `Principal`과 `SecurityContextHolder`의 차이점에 대해 살펴보겠다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;SecurityContextHolder 개요&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Spring Security는 웹 애플리케이션에서 보안(인증 및 권한 관리)을 다루는 데 사용되는 프레임워크이다. &lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;보안 컨텍스트는 `SecurityContextHolder`를 통해 관리되며, 현재 인증된 사용자는 `Principal` 또는 `Authentication` 객체를 통해 나타낼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;486&quot; data-origin-height=&quot;179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blbTEn/btslKHsq8hk/NTdcKP6clv7KUpQQ8hUl01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blbTEn/btslKHsq8hk/NTdcKP6clv7KUpQQ8hUl01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blbTEn/btslKHsq8hk/NTdcKP6clv7KUpQQ8hUl01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblbTEn%2FbtslKHsq8hk%2FNTdcKP6clv7KUpQQ8hUl01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;486&quot; height=&quot;179&quot; data-origin-width=&quot;486&quot; data-origin-height=&quot;179&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;figure id=&quot;og_1688002635382&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Servlet Authentication Architecture :: Spring Security&quot; data-og-description=&quot;ProviderManager is the most commonly used implementation of AuthenticationManager. ProviderManager delegates to a List of AuthenticationProvider instances. Each AuthenticationProvider has an opportunity to indicate that authentication should be successful,&quot; data-og-host=&quot;docs.spring.io&quot; data-og-source-url=&quot;https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html#servlet-authentication-securitycontextholder&quot; data-og-url=&quot;https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html#servlet-authentication-securitycontextholder&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bfzvxj/hyS9R9dTYk/52k8UD1fAVn2kA4WLYfLhK/img.png?width=786&amp;amp;height=714&amp;amp;face=0_0_786_714,https://scrap.kakaocdn.net/dn/boUj4t/hyS9OxTTpF/hmk2MWknrYUOUsQkXsNz50/img.png?width=728&amp;amp;height=354&amp;amp;face=0_0_728_354,https://scrap.kakaocdn.net/dn/c7WH3v/hyS9IqVSgn/ron1HORjBycHRmusRpdDfK/img.png?width=637&amp;amp;height=305&amp;amp;face=0_0_637_305&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html#servlet-authentication-securitycontextholder&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html#servlet-authentication-securitycontextholder&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bfzvxj/hyS9R9dTYk/52k8UD1fAVn2kA4WLYfLhK/img.png?width=786&amp;amp;height=714&amp;amp;face=0_0_786_714,https://scrap.kakaocdn.net/dn/boUj4t/hyS9OxTTpF/hmk2MWknrYUOUsQkXsNz50/img.png?width=728&amp;amp;height=354&amp;amp;face=0_0_728_354,https://scrap.kakaocdn.net/dn/c7WH3v/hyS9IqVSgn/ron1HORjBycHRmusRpdDfK/img.png?width=637&amp;amp;height=305&amp;amp;face=0_0_637_305');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Servlet Authentication Architecture :: Spring Security&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;ProviderManager is the most commonly used implementation of AuthenticationManager. ProviderManager delegates to a List of AuthenticationProvider instances. Each AuthenticationProvider has an opportunity to indicate that authentication should be successful,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;SecurityContextHolder&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;SecurityContextHolder는 Spring Security에서 현재 보안 컨텍스트를 저장하고 액세스하는 데 사용되는 클래스로 `SecurityContext` 객체를 저장하며, 이 `SecurityContext` 객체에는 현재 인증된 사용자를 나타내는 `Authentication` 객체가 포함되어 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;SecurityContextHolder는 스레드 로컬 저장소를 사용하여 보안 컨텍스트를 유지한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이렇게 함으로써 각 HTTP 요청이 처리되는 동안에만 보안 컨텍스트가 유지되며, 요청이 완료되면 해당 컨텍스트는 자동으로 제거됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;Authentication&amp;nbsp;객체는&amp;nbsp;다음과&amp;nbsp;같은&amp;nbsp;정보를&amp;nbsp;포함한다.&lt;/b&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://docs.spring.io/spring-security/site/docs/6.1.1/api/org/springframework/security/core/Authentication.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.spring.io/spring-security/site/docs/6.1.1/api/org/springframework/security/core/Authentication.html&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1688006528819&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Authentication (spring-security-docs 6.1.1 API)&quot; data-og-description=&quot;Represents the token for an authentication request or for an authenticated principal once the request has been processed by the AuthenticationManager.authenticate(Authentication) method. Once the request has been authenticated, the Authentication will usua&quot; data-og-host=&quot;docs.spring.io&quot; data-og-source-url=&quot;https://docs.spring.io/spring-security/site/docs/6.1.1/api/org/springframework/security/core/Authentication.html&quot; data-og-url=&quot;https://docs.spring.io/spring-security/site/docs/6.1.1/api/org/springframework/security/core/Authentication.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-security/site/docs/6.1.1/api/org/springframework/security/core/Authentication.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.spring.io/spring-security/site/docs/6.1.1/api/org/springframework/security/core/Authentication.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Authentication (spring-security-docs 6.1.1 API)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Represents the token for an authentication request or for an authenticated principal once the request has been processed by the AuthenticationManager.authenticate(Authentication) method. Once the request has been authenticated, the Authentication will usua&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;principal &lt;br /&gt;사용자를&amp;nbsp;식별합니다.&amp;nbsp;사용자&amp;nbsp;이름과&amp;nbsp;비밀번호를&amp;nbsp;사용하여&amp;nbsp;인증하는&amp;nbsp;경우,&amp;nbsp;UserDetails의&amp;nbsp;인스턴스가&amp;nbsp;된다. &lt;br /&gt;&lt;br /&gt;credentials &lt;br /&gt;대부분&amp;nbsp;비밀번호로&amp;nbsp;사용하고&amp;nbsp;많은&amp;nbsp;경우에&amp;nbsp;인증&amp;nbsp;후에&amp;nbsp;이&amp;nbsp;정보는&amp;nbsp;지워집니다.&amp;nbsp;이는&amp;nbsp;자격&amp;nbsp;증명&amp;nbsp;정보가&amp;nbsp;유출되는&amp;nbsp;것을&amp;nbsp;방지하기&amp;nbsp;위함이다. &lt;br /&gt;&lt;br /&gt;authorities &lt;br /&gt;사용자에게&amp;nbsp;부여된&amp;nbsp;고수준&amp;nbsp;권한을&amp;nbsp;나타내는&amp;nbsp;GrantedAuthority&amp;nbsp;인스턴스이다.&amp;nbsp;이는&amp;nbsp;일반적으로&amp;nbsp;사용자의&amp;nbsp;역할(Role)이나&amp;nbsp;범위(권한)를&amp;nbsp;나타낸다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;SecurityContextHolder 세팅 하는법&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1688002698702&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SecurityContext context = SecurityContextHolder.createEmptyContext(); 
Authentication authentication =
    new TestingAuthenticationToken(&quot;username&quot;, &quot;password&quot;, &quot;ROLE_USER&quot;); 
context.setAuthentication(authentication);

SecurityContextHolder.setContext(context);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;1. SecurityContextHolder에서 createEmptyContext 메서드를 통해 SecurityContext 인스턴스를 생성한다.&lt;br /&gt;&amp;nbsp;-&amp;nbsp; ContextHolder은 공유자원 이기에 race condition을 피하기 위해서는SecurityContextHolder. getContext(). setAuthentication (authentication) 방식이 아닌 새 인스턴스를 만들고 거기에 데이터를 추가하는 방식으로 구현해야지 thread-safe 프로그래밍을 진행할 수있다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;2. 이후 Authentication 객체를 만들어주는데 이때 자신이 쓸 토큰 메서드를 사용해서 authentication에 할당해준다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;3. context에 setAuthentication 메서드를 이용하여 만들었던 authentication를 할당한다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;4. 마지막으로 ContextHolder에 setContext를 이용하여 context를 할당한다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;SecurityContextHolder를 이용해 인증된 회원 정보에 접근하는법&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1688005226776&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection&amp;lt;? extends GrantedAuthority&amp;gt; authorities = authentication.getAuthorities();&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 역으로&amp;nbsp; SecurityContextHolder에서 getContext를 하여 얻어낸 context에서 또다시 Authentication을 추출한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. 이후엔 getName으로 username을 Principal로 principal 객체를 가져올수 있다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. Spring Security에서 `GrantedAuthority` 인터페이스는 사용자가 가진 권한(역할)을 표현하는데 사용되는데 Spring Security에서는 사용자의 권한을 기반으로 접근 제어 및 권한 부여를 수행한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 제네릭 와일드카드를 이용해서 GrantedAuthority 를 상속받은 타입이라는 형태이다.&amp;nbsp; authority 저장에 있어서 다형성을 부여해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 결론적으로 GrantedAuthority 인터페이스를 상속받은 객체들을 담을수 있는 Collection 인스턴스 를 선언한 것이다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;##&amp;nbsp;결론&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;`Principal`과&amp;nbsp;`SecurityContextHolder`는&amp;nbsp;Spring&amp;nbsp;Security에서&amp;nbsp;현재&amp;nbsp;인증된&amp;nbsp;사용자의&amp;nbsp;정보를&amp;nbsp;얻는&amp;nbsp;데&amp;nbsp;사용되는&amp;nbsp;두&amp;nbsp;가지&amp;nbsp;방법입니다.&amp;nbsp;필요한&amp;nbsp;정보와&amp;nbsp;상황에&amp;nbsp;따라&amp;nbsp;적절한&amp;nbsp;방법을&amp;nbsp;선택하여&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/span&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Principal&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;security 내의 principal 인터페이스를 뜯어보자면&amp;nbsp;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;equals&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;139&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ysbOE/btslJHNCH5y/3xqwZDbsSOKeDZHaOGkU4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ysbOE/btslJHNCH5y/3xqwZDbsSOKeDZHaOGkU4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ysbOE/btslJHNCH5y/3xqwZDbsSOKeDZHaOGkU4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FysbOE%2FbtslJHNCH5y%2F3xqwZDbsSOKeDZHaOGkU4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;943&quot; height=&quot;139&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;139&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; Principal 객체와 입력받은 다른 객체를 비교해서 입력받은 객체가 현재 Principal 객체와 동일하다면 true를 반환하고, 그렇지 않다면 false를 반환한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;toString&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;91&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1Sg3A/btslKHsuzSi/oJKGMfnU0lKQ89zlKOS3YK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1Sg3A/btslKHsuzSi/oJKGMfnU0lKQ89zlKOS3YK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1Sg3A/btslKHsuzSi/oJKGMfnU0lKQ89zlKOS3YK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1Sg3A%2FbtslKHsuzSi%2FoJKGMfnU0lKQ89zlKOS3YK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;649&quot; height=&quot;91&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;91&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;객체의 문자열 표현을 반환한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;hashCode&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;90&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blSCEe/btslJF3mxKC/IXhHyoT5zxOW4GpWbBk6e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blSCEe/btslJF3mxKC/IXhHyoT5zxOW4GpWbBk6e1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blSCEe/btslJF3mxKC/IXhHyoT5zxOW4GpWbBk6e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblSCEe%2FbtslJF3mxKC%2FIXhHyoT5zxOW4GpWbBk6e1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;623&quot; height=&quot;90&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;90&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;객체의 해시코드를 반환한다(고유한 숫자)&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;getName&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;93&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EhKD3/btslLATZEQW/ibWYnOwkmdurwBKAFsO9q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EhKD3/btslLATZEQW/ibWYnOwkmdurwBKAFsO9q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EhKD3/btslLATZEQW/ibWYnOwkmdurwBKAFsO9q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEhKD3%2FbtslLATZEQW%2FibWYnOwkmdurwBKAFsO9q1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;93&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;93&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대부분 UserDetails의 username을 가져온다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;implies&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;651&quot; data-origin-height=&quot;269&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BpI9H/btslKkqPR55/MNLEGdH8Y1lzCgnvZcJkSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BpI9H/btslKkqPR55/MNLEGdH8Y1lzCgnvZcJkSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BpI9H/btslKkqPR55/MNLEGdH8Y1lzCgnvZcJkSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBpI9H%2FbtslKkqPR55%2FMNLEGdH8Y1lzCgnvZcJkSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;651&quot; height=&quot;269&quot; data-origin-width=&quot;651&quot; data-origin-height=&quot;269&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;뒤에 주어진 Subject가 현재 Principal에 implicated 되는지 여부를 반환한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Principal과 getAuthentication() 장단점&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;SecurityContextHolder 통해 얻은 Authentication 객체는 보안 컨텍스트의 전체 인증 정보를 제공한다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;여기에는 `Principal`(사용자 ID), `authorities`(사용자 권한), `credentials`(사용자 비밀번호) 등의 훨씬 다양한 정보가 들어가있다. &lt;b&gt;만약 사용자 권한이 필요한 경우에는 Authentication 객체를 불러와야만 한다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;반면에 Principal 은 Authentication 객체의 일부로, 일반적으로 사용자의 식별 정보만을 제공한다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;따라서, 사용자 이름만 필요한 경우 Principal을 사용하면 간편하게 사용자의 이름을 얻을 수 있다. 즉 이 방식을 소개한 이유는 회원별로 권한도 체크해서 특정 권한만 접근 가능한 api를 설계할때에는&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;즉 이 방식을 소개한 이유는 회원별로 권한도 체크해서 특정 권한만 접근 가능한 api를 설계할때에는 당연히 Authentication 객체를 불러와야겠지만 Principal을 사용하게 된다면 컨트롤러 단에 있어서 아래 예시 코드를 보게 된다면&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1688006918395&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@DeleteMapping(&quot;/{eventId}&quot;)
public ResponseEntity&amp;lt;?&amp;gt; deleteEvent(@PathVariable Long eventId, Principal principal) {
    eventService.deleteEvent(principal.getName(), eventId);
    return new ResponseEntity&amp;lt;&amp;gt;(HttpStatus.NO_CONTENT);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1.&amp;nbsp; 딱보면 이 엔드포인트는 유저의 auth가 필요하구나를 확인하는 &lt;b&gt;코드직관성&lt;/b&gt; 이 좋아진다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. 테스트 코드 작성시 Principal 대신에 mock 객체를 보내 &lt;b&gt;테스트 코드 작성이 편해진다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. ContextHolder를 거쳐서 객체를 불러오고 다시 principal 이나 getName을 하는 것보다 단순하게 구현이 가능하다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;결론적으로는 차이와 특징을 잘 이해하고 적절히 사용하여 더 나은 코드를 짜보자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>authentication</category>
      <category>credentials</category>
      <category>principal</category>
      <category>SecurityContextHolder</category>
      <category>Spring Boot</category>
      <category>spring 로그인 원리</category>
      <category>springsecurity 원리</category>
      <category>UserDetail 인터페이스</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/192</guid>
      <comments>https://nstgic3.tistory.com/entry/SecurityContextHolder-Authentication-%EB%B6%84%EC%84%9D%ED%95%98%EA%B8%B0-principal-%EA%B0%9D%EC%B2%B4%EB%A1%9C-%EC%9C%A0%EC%A0%80-%EC%9D%B4%EB%A6%84-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0#entry192comment</comments>
      <pubDate>Thu, 29 Jun 2023 12:08:28 +0900</pubDate>
    </item>
    <item>
      <title>JPA관계매핑시 @JoinColumn 옵션 그리고 JPA명명전략(naming strategy)</title>
      <link>https://nstgic3.tistory.com/entry/JPA%EA%B4%80%EA%B3%84%EB%A7%A4%ED%95%91%EC%8B%9C-JoinColumn-%EC%98%B5%EC%85%98-%EA%B7%B8%EB%A6%AC%EA%B3%A0-JPA%EB%AA%85%EB%AA%85%EC%A0%84%EB%9E%B5naming-strategy</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목차&lt;/span&gt;&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;제목 정하기가 무척이나 어려웠다. 문제를 해결하고 보니 복합적인 문제였기 때문이다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;최종적으로 본 포스팅에서 다룰 내용은 다음과 같다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1. Spring boot JPA 스키마 생성 옵션 (create, create-drop, update .. 등등)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2. 엔티티간 관계 정의(@JoinColumn 오버라이드 옵션 사용)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;3. JPA Hibernate 컬럼 명명 전략&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;4. MySQL workbench 내 FK 설정법&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;5. SQL Error :1146, SQLState: 42S02/ SQL Error:1054, SQLState: 42S22&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6. Unknown column ~ in 'field list'&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;초기 문제 분석&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; &lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;Member 엔티티에&lt;/span&gt; OneToMany 관계로 Event를 매핑하려고 했다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이는 프로젝트 진행시에 유저별 일정을 저장하기 위해서 만든 엔티티인데 회원별로 같은 개인적인 일정을 저장하는 경우는 거의 없기때문에 따로 중간 데이터베이스를 설계하지 않고 OneToMany로 설계하였다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;해당 코드를 확인해보자면&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;- member-&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1687605073049&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@OneToMany(mappedBy = &quot;member&quot;, cascade = CascadeType.ALL, orphanRemoval = true)
    private Set&amp;lt;Event&amp;gt; events;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;- event -&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1687605343600&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@ManyToOne
@JoinColumn(name= &quot;memberId&quot;)
    private Member member;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;딱 이 두 코드를 보고 문제점을 파악했다면 JPA에 대한 이해도가 충분하다고 생각된다.&amp;nbsp;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;결론부터 확인하고 싶으면 아래 포스팅을 확인하자&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이들 간의 관계를 설정하려고 했을 때, 데이터베이스에 Event 테이블이 존재하지 않는다는 오류 메시지가 발생했다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1687605399713&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;2023-06-24T11:15:33.123+09:00  WARN 5444 --- [io-8080-exec-10] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 1146, SQLState: 42S02
2023-06-24T11:15:33.123+09:00 ERROR 5444 --- [io-8080-exec-10] o.h.engine.jdbc.spi.SqlExceptionHelper   : Table 'rdsreminder.reminderevents' doesn't exist
2023-06-24T11:15:33.145+09:00 ERROR 5444 --- [io-8080-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute statement; SQL [n/a]] with root cause&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Spring Boot 애플리케이션에서 Hibernate를 사용하여 데이터베이스 스키마를 자동으로 생성하도록 설정이 되어있었지만 (&quot;update&quot; 옵션) 제대로 생성되지 않았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예상 원인 분석 및 1차 해결&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;br /&gt;1. @JoinColumn 애노테이션의 사용&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;br /&gt;@JoinColumn 애노테이션은 `Event` 엔티티에 위치하고 있었는데, 그 안의 `name` 속성이 실제 데이터베이스의 컬럼명과 일치하지 않았을 가능성&lt;br /&gt;&lt;br /&gt;실제로 나중에 `name` 속성에서 지정했던 &quot;memberId&quot;가 JPA 컬럼 명명 규칙으로 인해서[ {엔티티 이름}_{참조하는 엔티티의 ID 필드 이름} ] 데이터 베이스에는 member_id 로 저장이 되었었다.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2. 실제로 DB가 생성되지 않았다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;br /&gt;DB를 못찾는 이유는 진짜로 없었기 때문이고 이는 이미 member 객체에 대한 DB가 존재했었고 이후에 OneToMany 매핑을 member에 event 객체에 ManyToOne 을 매핑하려 했기에 &quot;update&quot; 옵션을 가지고 제대로 생성되지 않는 이유를 이해하지 못했다.&lt;/span&gt;&lt;/span&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;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;create를 시도해볼까 했지만 api 제작중에 프론트도 테스트를 하면서 저장해놨던 정보들이 많기때문에 변경하지 않았다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;br /&gt;시도했던 해결방안&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;문제를 해결하기 위해 SQL구문을 통해 수동으로 DB를 만들어주었다.&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;MySQL Workbench를 통해 수동으로 `Event` 테이블과 `Member` 테이블 사이의 외래키 설정을 해주는 과정은 아래와 같다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;423&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NT7Qu/btslagI1k8r/2bBWBLtUp1DxTAkf0wWL21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NT7Qu/btslagI1k8r/2bBWBLtUp1DxTAkf0wWL21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NT7Qu/btslagI1k8r/2bBWBLtUp1DxTAkf0wWL21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNT7Qu%2FbtslagI1k8r%2F2bBWBLtUp1DxTAkf0wWL21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;461&quot; height=&quot;350&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;423&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;이렇게 함으로써, JPA가 데이터베이스 스키마를 올바르게 인식하고, 애플리케이션 실행 시점에 `Event` 테이블을 찾을 수 있게 되었지만 또 다른 에러가 발생하였다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1379&quot; data-origin-height=&quot;119&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RM45t/btsla0Ta8yz/0hgTWxh4LbfTDtX9W4NpM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RM45t/btsla0Ta8yz/0hgTWxh4LbfTDtX9W4NpM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RM45t/btsla0Ta8yz/0hgTWxh4LbfTDtX9W4NpM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRM45t%2Fbtsla0Ta8yz%2F0hgTWxh4LbfTDtX9W4NpM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1379&quot; height=&quot;119&quot; data-origin-width=&quot;1379&quot; data-origin-height=&quot;119&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;member_id 가 없다는 것이다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;최종 해결&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1차 원인 분석에 있던 @JoinColumn의 name 속성 특성 때문이었다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span&gt;초기에 저장했던&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;memberId&quot;가 MySQL-JPA 컬럼 명명 규칙으로 인해서[ {엔티티 이름}_{참조하는 엔티티의 ID 필드 이름} ] 데이터 베이스에는 &lt;b&gt;member_member_id&lt;/b&gt; 로 저장이 되었었다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&lt;br /&gt;따라서 Spring에서 memberId (DB에서 member_id) 라는 선언되지 않은 속성이 존재하고 있던 상황이다.&lt;/span&gt;&lt;/span&gt;&lt;/span&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;아래는 JPA명명전략에 관한 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html#naming&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html#naming&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1687624520321&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Hibernate ORM 6.2.5.Final User Guide&quot; data-og-description=&quot;Fetching, essentially, is the process of grabbing data from the database and making it available to the application. Tuning how an application does fetching is one of the biggest factors in determining how an application will perform. Fetching too much dat&quot; data-og-host=&quot;docs.jboss.org&quot; data-og-source-url=&quot;https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html#naming&quot; data-og-url=&quot;https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html#naming&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bEUbyi/hyS6wKCiTg/lTLbKuynBsCEQ1B23Es2bK/img.png?width=717&amp;amp;height=457&amp;amp;face=0_0_717_457&quot;&gt;&lt;a href=&quot;https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html#naming&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html#naming&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bEUbyi/hyS6wKCiTg/lTLbKuynBsCEQ1B23Es2bK/img.png?width=717&amp;amp;height=457&amp;amp;face=0_0_717_457');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Hibernate ORM 6.2.5.Final User Guide&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Fetching, essentially, is the process of grabbing data from the database and making it available to the application. Tuning how an application does fetching is one of the biggest factors in determining how an application will perform. Fetching too much dat&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.jboss.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1687624490851&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;&amp;ldquo;How-to&amp;rdquo; Guides&quot; data-og-description=&quot;Spring Boot has no mandatory logging dependency, except for the Commons Logging API, which is typically provided by Spring Framework&amp;rsquo;s spring-jcl module. To use Logback, you need to include it and spring-jcl on the classpath. The recommended way to do th&quot; data-og-host=&quot;docs.spring.io&quot; data-og-source-url=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-access.configure-hibernate-naming-strategy&quot; data-og-url=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-access.configure-hibernate-naming-strategy&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-access.configure-hibernate-naming-strategy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-access.configure-hibernate-naming-strategy&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;How-to&amp;rdquo; Guides&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot has no mandatory logging dependency, except for the Commons Logging API, which is typically provided by Spring Framework&amp;rsquo;s spring-jcl module. To use Logback, you need to include it and spring-jcl on the classpath. The recommended way to do th&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;시도했던 해결 방안&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제가 복잡할 수 있는데 서순이 중요하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1. memberId로 시도했으나 DB가 없다는 에러가 발생하였다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2. 따라서 수동으로 DB를 만들었고 FK 매핑과정에서 MySQL-JPA 컬럼 명명 규칙을 통해 member_member_id로 저장되었다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;3.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;@JoinColumn의 `name` 속성을 데이터베이스의 컬럼 이름인 &quot;member_member_id&quot;로 수정했다. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;이후에 정상적으로 작동한것을 확인할 수 있었다!&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1161&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4Lakn/btsk9EcRdP2/dCXvXUs30APZep1HTToXVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4Lakn/btsk9EcRdP2/dCXvXUs30APZep1HTToXVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4Lakn/btsk9EcRdP2/dCXvXUs30APZep1HTToXVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4Lakn%2Fbtsk9EcRdP2%2FdCXvXUs30APZep1HTToXVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1161&quot; height=&quot;273&quot; data-origin-width=&quot;1161&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;원인 분석 및 마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;이번 포스트를 통해, 우리는 외래 키 설정 문제를 직면했을 때, JPA의 컬럼 명명 규칙을 이해하고, 이를 바탕으로 문제를 해결하는 방법을 배웠다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;&quot;&gt;아래 코드는 Member 을 구현한 코드인데 보면 Id 부분에 따로 name옵션을 이용해서 member_id 로 만들어 놓은것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;271&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZIZAh/btsk9kesISZ/o13joLjofKGXErlXkfstCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZIZAh/btsk9kesISZ/o13joLjofKGXErlXkfstCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZIZAh/btsk9kesISZ/o13joLjofKGXErlXkfstCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZIZAh%2Fbtsk9kesISZ%2Fo13joLjofKGXErlXkfstCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;589&quot; height=&quot;271&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;전적으로 나의 잘못이었다. 해당 프로젝트를 진행하면서 Spring을 공부하기 시작했고 JPA의 명명 전략을 제대로 알지 못해서 다른 엔티티와의 구분이 필요하다 파악을 해서 id 를 따로 member_id로 명명하였고 이후에 제대로 리팩터링하지 않은 나의 잘못이 크다.&lt;/span&gt;&lt;/span&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;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;따라서 member에 따로 지정해준 name 옵션을 지웠고 DB에서의 컬럼 또한 member_id로 리팩터링 해주었다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1137&quot; data-origin-height=&quot;182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZCSt5/btsk9jNlnVM/uqCVqRxUNJopA2xEhnA2OK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZCSt5/btsk9jNlnVM/uqCVqRxUNJopA2xEhnA2OK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZCSt5/btsk9jNlnVM/uqCVqRxUNJopA2xEhnA2OK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZCSt5%2Fbtsk9jNlnVM%2FuqCVqRxUNJopA2xEhnA2OK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1137&quot; height=&quot;182&quot; data-origin-width=&quot;1137&quot; data-origin-height=&quot;182&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;코드의 일관성을 유지하는것이 무척이나 중요하다고 깨닫게 되는 과정이었다.. 협업시 이런 실수를 했다고 생각하면 이보다 더 헤매서 원인을 찾았을것 같다.&lt;/span&gt;&lt;/span&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;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;이 포스트가 비슷한 문제를 겪었을 때 도움이 되었으면 좋겠다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;&quot;&gt;이 문제를 해결하다가 엔티티간 JPA로 매핑하는 옵션에 대해서 더 깊게 알게되었는데 시간을 내서 포스팅해보아야겠다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>JPA naming Strategy</category>
      <category>JPA 관계매핑</category>
      <category>JPA 컬럼명 규칙</category>
      <category>Request processing failed: org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute statement; SQL [n/a]] with root cause</category>
      <category>SQL Error :1146</category>
      <category>SQL Error:1054</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/190</guid>
      <comments>https://nstgic3.tistory.com/entry/JPA%EA%B4%80%EA%B3%84%EB%A7%A4%ED%95%91%EC%8B%9C-JoinColumn-%EC%98%B5%EC%85%98-%EA%B7%B8%EB%A6%AC%EA%B3%A0-JPA%EB%AA%85%EB%AA%85%EC%A0%84%EB%9E%B5naming-strategy#entry190comment</comments>
      <pubDate>Sun, 25 Jun 2023 01:36:32 +0900</pubDate>
    </item>
    <item>
      <title>[LongTerm/사용기] RealForce APC R3SD11균등</title>
      <link>https://nstgic3.tistory.com/entry/RealForce-APC-R3SD11-%EB%B0%98%EB%85%84-%EC%82%AC%EC%9A%A9%EA%B8%B0</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목차&lt;/span&gt;&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;리얼포스 3가 출시되었을때 사려고 고민중이던 브랜드였어서 바로 사려했으나 블루투스 버전 디자인이 크게 마음에 들지 않았었다.. 이후에 22년 6월 말쯤 3s가 출시되었고 10월에 생일 기념으로 R3SD11 버전을 구매했다!&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;원래 받자마자 개봉기도 쓰려했지만 미루다보니 여기까지 오게 되었다ㅋㅋㅋㅋ&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;가격은 해외직구로 29만원 정도에 구입했었다. 현재는 네이버 스토어에 26언저리에 올라와있던데 환율+관세 생각하면.. 크게 가슴아파하지 않아도된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개봉기 및 전용프로그램 후기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4624&quot; data-origin-height=&quot;3468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgiO3h/btslaJRMRGd/N2YMU8rgrAA6oE8Jar7pXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgiO3h/btslaJRMRGd/N2YMU8rgrAA6oE8Jar7pXk/img.png&quot; data-alt=&quot;개봉 당시 모습ㅋㅋㅋ 저 사진을 보니 청소를 한번 해야될까 싶다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgiO3h/btslaJRMRGd/N2YMU8rgrAA6oE8Jar7pXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgiO3h%2FbtslaJRMRGd%2FN2YMU8rgrAA6oE8Jar7pXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4624&quot; height=&quot;3468&quot; data-origin-width=&quot;4624&quot; data-origin-height=&quot;3468&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;개봉 당시 모습ㅋㅋㅋ 저 사진을 보니 청소를 한번 해야될까 싶다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;718&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZOwf9/btr91xPax8r/p9kOR1nZgU6kxnCZ4acakk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZOwf9/btr91xPax8r/p9kOR1nZgU6kxnCZ4acakk/img.png&quot; data-alt=&quot;전용 소프트웨어를 지원한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZOwf9/btr91xPax8r/p9kOR1nZgU6kxnCZ4acakk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZOwf9%2Fbtr91xPax8r%2Fp9kOR1nZgU6kxnCZ4acakk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1269&quot; height=&quot;718&quot; data-origin-width=&quot;1269&quot; data-origin-height=&quot;718&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;전용 소프트웨어를 지원한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1273&quot; data-origin-height=&quot;716&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/89XUt/btr90URnddn/Duh7K5NaLy53k9IvygbTP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/89XUt/btr90URnddn/Duh7K5NaLy53k9IvygbTP0/img.png&quot; data-alt=&quot;APC기능 - 키별로 감도를 조정할수 있다. 현재는 숫자부와 f 제어 부를 제외하고 0,8mm 이용중이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/89XUt/btr90URnddn/Duh7K5NaLy53k9IvygbTP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F89XUt%2Fbtr90URnddn%2FDuh7K5NaLy53k9IvygbTP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1273&quot; height=&quot;716&quot; data-origin-width=&quot;1273&quot; data-origin-height=&quot;716&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;APC기능 - 키별로 감도를 조정할수 있다. 현재는 숫자부와 f 제어 부를 제외하고 0,8mm 이용중이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1271&quot; data-origin-height=&quot;689&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dekw3/btr93lmSTgd/SnNg6pfKyWcyJheoC6h3T1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dekw3/btr93lmSTgd/SnNg6pfKyWcyJheoC6h3T1/img.png&quot; data-alt=&quot;타건 비율하고 횟수도 나타내준다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dekw3/btr93lmSTgd/SnNg6pfKyWcyJheoC6h3T1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDekw3%2Fbtr93lmSTgd%2FSnNg6pfKyWcyJheoC6h3T1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1271&quot; height=&quot;689&quot; data-origin-width=&quot;1271&quot; data-origin-height=&quot;689&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;타건 비율하고 횟수도 나타내준다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;이외에도 매크로나 fn 키를 이용해서 여러 키를 매핑할수 있는데 처음에는 해피해킹처럼 화살표를 ㅓㅏㅣㅑ에 매핑해서 쓰다가 노트북하고 교차하면서 쓰다보니 혼란스러워서 원래 설정으로 돌아왔다. 그리고 한참 프로젝트 할때만 단축키를 쓰니 시험기간에는 잊어버리고 다시 적응하는 과정이 있었다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;장단점을 설명하기 전에 리얼포스는 기계식 키보드가 아니라 러버돔+정전용량 방식으로 입력되는 원리라서 개인취향 영역이기에 아래의 장단점은 사람에 따라 서로 다른 의견이 있을수 있는 부분이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;장점&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1. 완성도에서 오는 만족감&lt;br /&gt;경제적인 키보드나 축을 이용하는 경우에는 키씹힘 현상이나 오탈의 경우는 없지만 유격등으로 인해서 오는 흔들림이나 찰찰 거리는 스프링 소리가 거슬릴때가 있다. 이건 이 가격이면 당연한거지만 타건시에 항상 비슷하고 정갈한 소리를 낸다.&amp;nbsp;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2. 통울림이 적다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;케이싱이 잘 되어있어서 통울림이 잘 느껴지지 않는다. 추후에 흡음재 추가할 예정&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;3. 내구성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;근 8개월을 매일 6시간 이상씩은 필수적으로 타건했다. 자주 사용하는 키와 잘 사용하지 않는 키와의 압력차이는 확실히 생겼지만 (10원 2개정도) 반년 열심히 치면 찰찰거리는 기계식 키보드들하고는 구조적 차이인지 내구성이 좋다는게 느껴졌다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;단점&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1. 유선&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;무선을 같은 각진 디자인으로 냈으면 무선산다.. 선을 3방향으로 세팅할 수 있게 뒷판에 가이드가 있지만 거슬리는건 사실이다..&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2. 가격&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;토프레를 사야한다면 리얼포스나 레오폴드이지만 20중반~30에는 대안이 많은것도 사실이다. 심지어는 LED도 없다. 모니터등이 필수&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;3.&amp;nbsp;&amp;nbsp;커스텀&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;토프레 키캡이 잘 없다... 그리고 비싸다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;비싼 가격이지만 완성도 높고 사용시 불편함이 없는 잘만든 기계.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;타건감이나 소음측면에서는 정숙하다고 표현하는것이 딱 알맞을 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;8개월간 열심히 사용해도 내구성 체감되지 않았음.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;45g은 빠른 타이핑(500타~)에는 비추천, 게임 또한 비추천, 프로그래밍용으로는 좋다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기변은 생각없지만 사게된다면 해피해킹이 아닐까..&amp;nbsp;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Hardware</category>
      <category>R3SD11</category>
      <category>균등</category>
      <category>리뷰</category>
      <category>리얼포스</category>
      <category>사용기</category>
      <category>저소음</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/154</guid>
      <comments>https://nstgic3.tistory.com/entry/RealForce-APC-R3SD11-%EB%B0%98%EB%85%84-%EC%82%AC%EC%9A%A9%EA%B8%B0#entry154comment</comments>
      <pubDate>Sat, 24 Jun 2023 15:42:05 +0900</pubDate>
    </item>
    <item>
      <title>FetchType.EAGER vs FetchType.LAZY in JPA</title>
      <link>https://nstgic3.tistory.com/entry/FetchTypeEAGER-vs-FetchTypeLAZY-in-JPA</link>
      <description>&lt;div class=&quot;book-toc&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;목차&lt;/span&gt;&lt;/p&gt;
&lt;ul id=&quot;toc&quot; style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;/ul&gt;
&lt;/div&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;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;border-bottom: 3px solid #707070; font-weight: bold; padding: 5px;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;JPA에서 중요한 주제 중 하나인 FetchType에 대해 이야기해보려고 한다. FetchType은 데이터베이스에서 엔티티를 조회할 때 연관된 엔티티를 언제 로드할 것인지 결정하는 로딩 전략으로 EAGER와 LAZY라는 두 가지 전략이 있는데 각 전략에 대해서 예시를 통해 어떤 환경에 쓰여야하는지 확인해보자&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;FetchType.EAGER&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;EAGER 로딩 전략은 한 엔티티가 로드될 때 관련된 모든 엔티티를 함께 로드하는 방식&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;사용자의 역할(User Role)과 같이 사용자 정보를 불러올 때마다 &lt;b&gt;빈번하게 사용하는 정보의 경우&lt;/b&gt; 유용하게 사용됩니다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;예를 들어, 대부분의 웹 서비스에서는 일반 사용자와 관리자의 권한 차이로 인해 사용자가 수행할 수 있는 동작이 달라진다.&lt;br /&gt;이런 경우, 사용자가 로그인하거나 다른 사용자에게 요청을 보낼 때마다 사용자의 역할을 확인해야 한다.&lt;br /&gt;&lt;br /&gt;이때 EAGER 로딩 전략을 사용하면, 사용자 엔티티를 로드할 때마다 해당 사용자의 역할 정보도 함께 로드되므로, 이후에 역할 정보를 사용할 때 별도의 데이터베이스 접근 없이 해당 정보를 사용할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;하지만 EAGER 로딩 전략은 항상 좋은 것만은 아니다. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;필요하지 않은 &lt;b&gt;엔티티를 불필요하게 로드&lt;/b&gt;하게 될 수 있으며, 이는 성능 저하와 메모리 낭비를 초래할 수 있습니다.&lt;/span&gt; 따라서 EAGER 로딩 전략은 신중하게 사용해야 한다.&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;FetchType.LAZY&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;LAZY 로딩 전략은 연관된 엔티티를 실제로 사용하는 시점에 로드하는 방식&lt;/span&gt;&lt;/blockquote&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;UserProfile과 같이 사용자의 &lt;b&gt;상세 정보를 보는 경우와 같이 필요할 때만 데이터베이스에서 조회&lt;/b&gt;하여 성능을 향상시키는데 도움이 됩니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;예를 들어, 웹 서비스에서는 사용자 목록을 보여주거나 특정 사용자의 로그인 상태를 확인하는 경우에는 UserProfile 정보가 필요하지 않기에 이때 LAZY 로딩 전략을 사용하면 UserProfile 정보가 실제로 필요한 시점에만 로드되므로, 불필요한 데이터베이스 접근을 최소화할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;하지만 LAZY 로딩 전략 또한 문제가 존재하는데&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&amp;nbsp;실제로&amp;nbsp;필요한&amp;nbsp;시점에&amp;nbsp;데이터베이스&amp;nbsp;접근이&amp;nbsp;발생하므로,&amp;nbsp;해당&amp;nbsp;시점에서&amp;nbsp;&lt;b&gt;지연이&amp;nbsp;발생&lt;/b&gt;할 수 있습니다. 또한, Hibernate 등의 JPA 구현체에서는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;트랜잭션이 이미 종료된 상태에서 LAZY 로딩을 호출하면 'LazyInitializationException'이 발생할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -304px / 200px 420px no-repeat; width: 200px; height: 19px; padding: 18px 20px 17px;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;font-weight: bold; border-bottom: 1px solid #d83c3c; margin: 10px 0px 5px; border-left: 5px solid #d83c3c; letter-spacing: -0.07em; line-height: 30px; padding: 0px 10px 1px;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;따라서, FetchType.EAGER와 FetchType.LAZY 중 어느 것을 선택할지는 애플리케이션의 요구사항과 데이터 접근 패턴에 따라 결정해야 한다.&lt;br /&gt;&lt;/span&gt;&lt;/span&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;span style=&quot;color: #333333; font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start; background-color: #f6e199;&quot;&gt;EAGER 로딩은 연관된 엔티티를 빈번하게 사용하는 경우 유용하며, LAZY 로딩은 필요한 시점에만 연관된 엔티티를 로드하여 성능을 향상시키는데 도움이 된다.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>eager</category>
      <category>fetchType</category>
      <category>JPA</category>
      <category>LAZY</category>
      <category>스프링 JPA</category>
      <author>nstgic3</author>
      <guid isPermaLink="true">https://nstgic3.tistory.com/189</guid>
      <comments>https://nstgic3.tistory.com/entry/FetchTypeEAGER-vs-FetchTypeLAZY-in-JPA#entry189comment</comments>
      <pubDate>Fri, 23 Jun 2023 01:40:01 +0900</pubDate>
    </item>
  </channel>
</rss>