<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Zzzzz</title>
    <link>https://jonghne.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 26 Aug 2026 02:24:12 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>iwannarest</managingEditor>
    <image>
      <title>Zzzzz</title>
      <url>https://tistory1.daumcdn.net/tistory/5457767/attach/0807b9510b514319ad33cd90a2e87dc7</url>
      <link>https://jonghne.tistory.com</link>
    </image>
    <item>
      <title>테스트 코드에서 LocalDateTime.now() 사용 시 간헐적으로 실패하는 이슈</title>
      <link>https://jonghne.tistory.com/112</link>
      <description>&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;337&quot; data-start=&quot;249&quot; data-ke-size=&quot;size16&quot;&gt;이번 글에서는 제가 실제로 겪은 &lt;b&gt;LocalDateTime.now() 때문에 테스트가 간헐적으로 실패한 경험과 &lt;/b&gt;이를 해결한 방법을 정리해 보았습니다.&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;이슈 발생&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-end=&quot;441&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;제가 회사에서 맡고있는 소개팅 앱의 기능에는 이성의 카드를 받고 좋아요 또는 호감 메시지 보내기 기능이 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;441&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;이런 기능을 액션을 했다고 표현하는데 &lt;b&gt;액션을 하게 되면 카드의 D-DAY를 갱신&lt;/b&gt;해주게 됩니다.&lt;/p&gt;
&lt;p data-end=&quot;441&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;441&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;D-DAY 갱신 방식으로는 기존 D-DAY가 7인 카드는 액션 시 D-7로 갱신하고, D-DAY가 1~6인 카드는 D-6으로 갱신해줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;441&quot; data-start=&quot;357&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 data-end=&quot;441&quot; data-start=&quot;357&quot;&gt;갱신 시에는 카드 데이터의 생성시간을 직접 수정&lt;/li&gt;
&lt;li data-end=&quot;441&quot; data-start=&quot;357&quot;&gt;D-DAY는 별도의 컬럼으로 관리하지 않고 생성일자와 현재시간을 기준으로 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;441&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;441&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;위의 로직과 관련해서 액션한 이후의 D-DAY 값을 검증하는 테스트 코드를 작성했는데&lt;/p&gt;
&lt;p data-end=&quot;441&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;테스트코드를 실행하는 시간에 따라 &lt;b&gt;성공/실패가 갈리는 이슈&lt;/b&gt;가 발생했습니다.&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;원인 분석&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-end=&quot;899&quot; data-start=&quot;843&quot; data-ke-size=&quot;size16&quot;&gt;해당 이슈를 계속 테스트하며 원인을 분석한 결과, &lt;b&gt;12시 30분을 기준으로 이전에는 테스트가 실패하고 이후에는 성공하는 패턴&lt;/b&gt;을 발견했습니다.&lt;/p&gt;
&lt;p data-end=&quot;203&quot; data-start=&quot;136&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;203&quot; data-start=&quot;136&quot; data-ke-size=&quot;size16&quot;&gt;이에 따라 D-DAY를 갱신하는 로직과 D-DAY를 계산하는 로직을 살펴보았고, 원인을 정확히 파악할 수 있었습니다.&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;205&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;205&quot; data-ke-size=&quot;size16&quot;&gt;서비스 정책상 D-DAY가 &lt;b&gt;12시 30분을 기준으로 변경&lt;/b&gt;되는 경우가 있는데, 테스트 코드에서는 이를 고려하지 않고 특정 D-DAY 값을 기대값으로 설정했기 때문에 발생한 문제였습니다.&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;205&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;205&quot; data-ke-size=&quot;size16&quot;&gt;즉, D-DAY가 D-5인 카드가 액션한 이후 D-6으로 D-DAY가 갱신되었는지 테스트를 작성했는데 아래와 같이 D-DAY가 갱신 &amp;amp; 계산 하기 때문에, 실행 시점이 12시 30분 이전인 경우 D-7로 12시 30분 이후에는 D-6으로 결과값이 나오는 문제였습니다.&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;205&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;205&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;D-DAY가 D-5인 카드가 액션된 후 D-6으로 갱신되는지 확인&lt;/b&gt;하는 테스트를 작성했는데,&lt;br /&gt;D-DAY가 갱신되고 계산되는 방식 때문에 &lt;b&gt;실행 시점이 12시 30분 이전이면 D-7&lt;/b&gt;로 나오고&lt;b&gt; 이후면 D-6&lt;/b&gt;으로 결과가 달라지게 되었습니다.&lt;/p&gt;
&lt;p data-end=&quot;313&quot; data-start=&quot;205&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;border: 5px solid #BDCEFF; border-radius: 0px 0px; padding: 15px 30px; margin: 0;&quot;&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; top: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p style=&quot;text-align: left; font-weight: bold;&quot; data-ke-size=&quot;size18&quot;&gt;D-DAY 갱신 &amp;amp; 계산 방식&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-end=&quot;899&quot; data-start=&quot;843&quot;&gt;- 카드 액션한 뒤 현재 D-DAY가 7이면 D-DAY를 오늘 12시 30분으로 갱신하고, 현재 D-DAY가 6 이하인 경우 하루 전 12시 30분으로 카드 생성일자를 갱신한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-end=&quot;899&quot; data-start=&quot;843&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-end=&quot;899&quot; data-start=&quot;843&quot;&gt;- 카드 D-DAY 계산 할 때는 카드 생성일자가 현재 시간으로 부터 24시간이 지나지 않았다면 D-7로 지났다면 D-6로 판단한다.&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; bottom: -26px; margin: 0 auto;&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;해결 방안&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-end=&quot;899&quot; data-start=&quot;843&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;서비스 정책상&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;12시 30분을 기준으로 카드 D-DAY가 변경&lt;/b&gt;되는데, 테스트에서는 실행 시점을 통제하지 못해 문제가 발생했습니다.&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이에 따라 테스트 코드 내에서 시간을 통제하는 방법으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;두 가지 방안&lt;/b&gt;을 고려했습니다.&lt;/p&gt;
&lt;p data-end=&quot;899&quot; data-start=&quot;843&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;border: 5px solid #BDCEFF; border-radius: 0px 0px; padding: 15px 30px; margin: 0;&quot;&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; top: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-start=&quot;843&quot; data-end=&quot;899&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 테스트 코드 내에서 현재 시간이 12시 30분 이전/이후인지에 따라 결과값을 다르게 세팅한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-start=&quot;843&quot; data-end=&quot;899&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 테스트 코드 내의 LocalDatetime.now()를 stubbing 해서 12시 30분 이전/이후에 대한 테스트코드를 각각 생성&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; bottom: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;421&quot; data-start=&quot;336&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;421&quot; data-start=&quot;336&quot; data-ke-size=&quot;size16&quot;&gt;첫 번째 방법은 구현이 비교적 간단하지만, 테스트 코드에 &lt;b&gt;분기문이 포함&lt;/b&gt;되므로 다른 팀원이 읽을 때 이해하기 어려울 수 있다는 단점이 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;421&quot; data-start=&quot;336&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;614&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;반면 두 번째 방법은 &lt;b&gt;static 메서드를 모킹&lt;/b&gt; 처리하므로, 적절히 해제하지 않으면 다른 테스트에서 LocalDateTime.now()가 스터빙된 값으로 실행될 수 있어 테스트가 깨질 위험이 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;614&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;하지만 테스트 코드가 가독성이 1번보다 명확하고, 테스트에 사용되는 값을 &lt;b&gt;확실하게 통제&lt;/b&gt;할 수 있다는 장점이 있어 저는 이 방법을 선택했습니다.&lt;/p&gt;
&lt;p data-end=&quot;614&quot; data-start=&quot;423&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;649&quot; data-start=&quot;616&quot; data-ke-size=&quot;size16&quot;&gt;아래는 두 번째 방법으로 수정한 테스트 코드 일부입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758015214170&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LocalDateTime fixedDate = LocalDateTime.of(2025, 4, 23, 12, 29); 
LocalTime fixedTime = LocalTime.of(12, 29); 

MockedStatic&amp;lt;LocalDateTime&amp;gt; mockLocalDateTime = mockStatic(LocalDateTime.class, CALLS_REAL_METHODS); // close 필수 
MockedStatic&amp;lt;LocalTime&amp;gt; mockLocalTime = mockStatic(LocalTime.class, CALLS_REAL_METHODS); // close 필수 

mockLocalDateTime.when(LocalDateTime::now).thenReturn(fixedDate); 
mockLocalTime.when(LocalTime::now).thenReturn(fixedTime); 

LocalDate today = LocalDate.now(); 
LocalDateTime now = LocalDateTime.now(); // 테스트 끝나면 반드시 close 

...

mockLocalDateTime.close(); 
mockLocalTime.close();&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 data-end=&quot;899&quot; data-start=&quot;843&quot;&gt;CALLS_REAL_METHODS: LocalDateTime.now()/LocalTime.now()만 Mocking하고 나머지 메서드는 실제 실행&lt;/li&gt;
&lt;li data-end=&quot;899&quot; data-start=&quot;843&quot;&gt;close() 필수: 테스트 종료 후 static mock을 해제하지 않으면 다른 테스트에 영향 가능성 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;899&quot; data-start=&quot;843&quot; data-ke-size=&quot;size16&quot;&gt;@TestFactory를 쓸 때는 onClose()로 처리할 수도 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;899&quot; data-start=&quot;843&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-end=&quot;3042&quot; data-start=&quot;3019&quot; data-ke-size=&quot;size16&quot;&gt;이번 이슈를 해결하며 완벽한 테스트 코드를 위해서는 &lt;b&gt;시간을 확실하게 통제하고 있는지&lt;/b&gt;를 확실히 체크 해야겠다라는 생각을 했습니다.&lt;/p&gt;
&lt;p data-end=&quot;587&quot; data-start=&quot;499&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;587&quot; data-start=&quot;499&quot; data-ke-size=&quot;size16&quot;&gt;그리고 이번 이슈에는 해당되지는 않았지만 프로덕션 코드에서도 LocalDateTime.now()와 같은 코드를 repository layer에서 직접 사용하지 말고, &lt;b&gt;적절한 위치에서 주입 해주는게 좋겠다는&lt;/b&gt; 생각이 들었습니다.&lt;/p&gt;</description>
      <category>Trouble Shooting/Java</category>
      <author>iwannarest</author>
      <guid isPermaLink="true">https://jonghne.tistory.com/112</guid>
      <comments>https://jonghne.tistory.com/112#entry112comment</comments>
      <pubDate>Tue, 16 Sep 2025 19:21:32 +0900</pubDate>
    </item>
    <item>
      <title>@SpyBean에서 doReturn().when() 과 when().thenReturn() 비교</title>
      <link>https://jonghne.tistory.com/111</link>
      <description>&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-end=&quot;312&quot; data-start=&quot;195&quot; data-ke-size=&quot;size16&quot;&gt;스프링 테스트에서 Mock 객체를 써야 할 때는 보통 @MockBean을 많이 사용한다.&lt;/p&gt;
&lt;p data-end=&quot;312&quot; data-start=&quot;195&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그러나 &lt;b&gt;@MockBean&lt;/b&gt;은 아예 원래 빈을 가짜 객체로 교체하기 때문에, 원래 구현 로직은 전혀 실행되지 않는다.&lt;/p&gt;
&lt;p data-end=&quot;312&quot; data-start=&quot;195&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;421&quot; data-start=&quot;314&quot; data-ke-size=&quot;size16&quot;&gt;그에 비해 @SpyBean은 &lt;b&gt;실제 빈을 감싸서(Spy) 일부만 Mocking &lt;/b&gt;하게 도와주는 어노테이션이다.&lt;br /&gt;(즉, 원래 로직은 그대로 두되 필요한 메서드만 스텁(stub) 처리할 수 있는 방식이다.)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;516&quot; data-start=&quot;434&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;470&quot; data-start=&quot;434&quot;&gt;@MockBean &amp;rarr; 원래 빈을 전부 Mock으로 교체&lt;/li&gt;
&lt;li data-end=&quot;516&quot; data-start=&quot;471&quot;&gt;@SpyBean &amp;rarr; 원래 빈을 유지하면서 원하는 메서드만 Mock 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;605&quot; data-start=&quot;518&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;605&quot; data-start=&quot;518&quot; data-ke-size=&quot;size16&quot;&gt;그래서 서비스 로직은 그대로 실행하면서, DB 접근이나 외부 API 호출 같은 특정 부분만 가짜 값으로 대체하고 싶을 때 @SpyBean을 사용한다.&lt;/p&gt;
&lt;p data-end=&quot;528&quot; data-start=&quot;406&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;이 @SpyBean을 사용할 때는 특정 메서드를 스텁(stub) 처리하는 방법에는 두 가지 문법이 있다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1757423824064&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;doReturn(1L).when(memberService).checkUserNo(anyString());&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;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1757423830729&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;when(memberService.checkUserNo(anyString())).thenReturn(1L);&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;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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;1. doReturn().when()&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1757423920234&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;doReturn(1L).when(memberService).checkUserNo(anyString());&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;731&quot; data-start=&quot;538&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;526&quot; data-start=&quot;491&quot;&gt;실제 메서드를 실행하지 않고 바로 지정한 값을 리턴한다.&lt;/li&gt;
&lt;li data-end=&quot;578&quot; data-start=&quot;527&quot;&gt;원본 메서드가 DB 호출이나 네트워크 요청처럼 부작용을 일으킬 때 안전하게 막아준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;2. when().thenReturn()&lt;/h3&gt;
&lt;div style=&quot;color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1757423960916&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;when(memberService.checkUserNo(anyString())).thenReturn(1L);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;988&quot; data-start=&quot;841&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;732&quot; data-start=&quot;689&quot;&gt;먼저 실제 메서드가 실행된 뒤, 그 결과를 감싸서 반환하도록 동작한다.&lt;/li&gt;
&lt;li data-end=&quot;799&quot; data-start=&quot;733&quot;&gt;SpyBean을 쓸 때는 원본 메서드가 그대로 호출되기 때문에 원치 않는 DB 접근이나 예외가 발생할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;정리 &lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;div style=&quot;color: #333333; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1104&quot; data-start=&quot;1003&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1052&quot; data-start=&quot;1003&quot;&gt;doReturn().when() &amp;rarr; &lt;b&gt;실제 메서드 실행을 막고&lt;/b&gt; 값만 반환&lt;/li&gt;
&lt;li data-end=&quot;1104&quot; data-start=&quot;1053&quot;&gt;when().thenReturn() &amp;rarr; &lt;b&gt;실제 메서드가 실행된 뒤&lt;/b&gt; 값을 스텁&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1188&quot; data-start=&quot;1106&quot; data-ke-size=&quot;size16&quot;&gt;따라서 @SpyBean과 같이 부분 Mocking이 필요한 상황에서는 대부분 doReturn().when()을 사용하는 것이 안전합니다.&lt;/p&gt;
&amp;nbsp;&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;/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;</description>
      <category>Study/Test</category>
      <author>iwannarest</author>
      <guid isPermaLink="true">https://jonghne.tistory.com/111</guid>
      <comments>https://jonghne.tistory.com/111#entry111comment</comments>
      <pubDate>Tue, 9 Sep 2025 22:26:08 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] @Bean과 @Component의 차이점</title>
      <link>https://jonghne.tistory.com/110</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Spring 웹 애플리케이션을 개발할 때 특정 객체를 Spring 컨테이너가 관리하는 Bean으로 등록하고 싶은 경우에는 @Bean 어노테이션 또는 @Component 어노테이션을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Bean과 @Component 둘 다 Component Scan을 통해 Spring Bean으로 등록되고 Life Cycle이 관리되지만, 사용 방법과 용도에 따라 차이가 있습니다.&lt;/p&gt;
&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;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;@Bean&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 @Bean 어노테이션은 &lt;u&gt;메서드 레벨에 선언하는 어노테이션&lt;/u&gt;으로, &lt;u&gt;생성자 메서드&lt;/u&gt;를 통해 Spring Bean을 등록합니다.&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;해당 어노테이션은 독립적으로 사용할 수 없고, 클래스 레벨에 @Component를 포함하고 있는 어노테이션을 함께 선언해서 Component Scan의 대상이 되도록 해야합니다. (ex) @Configuration, @Component, @Repository ..)&lt;/span&gt;&lt;/p&gt;
&lt;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;@Bean 어노테이션 사용 방법에 대해 간단한 예시로 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;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 Bean으로 등록하고자 하는 Pen 클래스입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710738214484&quot; class=&quot;arduino&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Pen {
    private String name;
    private int price;

    public Pen(String name, int price) {
        this.name = name;
        this.price = 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;Pen을  Bean으로 등록할 클래스 파일을 생성하고, @Bean 어노테이션과 함께 Pen 객체의 생성자 메서드를 선언합니다.&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;그리고 해당 클래스 파일에 @Configuration 을 선언해서 Component Scan의 대상이 되게 합니다.&lt;/p&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가 아닌 @Configuration을 사용하는 이유는 Bean 설정 을 위한 클래스 파일이라는 것을 좀 더 쉽게 파악하기 위해서 입니다.)&lt;/p&gt;
&lt;pre id=&quot;code_1710738310124&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Configuration
public class BeanConfig {
    @Bean
    public Pen pen() {
        return new Pen(&quot;제트 스트림&quot;, 3000);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;@ Component&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;@Component는 &lt;u&gt;클래스 레벨에 선언하는 어노테이션&lt;/u&gt;으로, 별도의 설정 파일 없이 &lt;u&gt;객체를 Spring Bean으로 직접 등록하는 방법&lt;/u&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;@Component 어노테이션이 붙은 객체는 Spring Container 생성 시점에 Component Scan의 대상이 되어 Spring Bean으로 등록되고 Life Cycle이 관리됩니다. (Bean이 등록되는 시점은 Bean Scope 에 따라 달라질 수 있습니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시로 든 Pen 클래스에 대해 @Component 어노테이션만 추가로 선언하면, 별도의 설정 파일에 등록할 필요 없이 Spring Bean으로 등록됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1710739641672&quot; class=&quot;arduino&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import org.springframework.stereotype.Component;

@Component
public class Pen {
    private String name;
    private int price;

    public Pen(String name, int price) {
        this.name = name;
        this.price = 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&gt;참고로 개발 시 자주 사용되는 @Service, @Controller, @Repository와 같은 어노테이션도 내부에는 @Component 어노테이션이 선언 되어 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;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 Bean으로 등록되는 방법은 동일합니다.&amp;nbsp;&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;1052&quot; data-origin-height=&quot;666&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRW2kj/btsFQ9JEdHB/UrT0QDCv5vNV8UyoHmALa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRW2kj/btsFQ9JEdHB/UrT0QDCv5vNV8UyoHmALa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRW2kj/btsFQ9JEdHB/UrT0QDCv5vNV8UyoHmALa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRW2kj%2FbtsFQ9JEdHB%2FUrT0QDCv5vNV8UyoHmALa0%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;1052&quot; height=&quot;666&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;666&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;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;@Bean, @ Component 차이점&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Bean 어노테이션은 @Component가 선언되어 있는 클래스 의 생성자 메서드 레벨에 선언하고, @Component 어노테이션의 경우 클래스 레벨에 직접 선언한다는 차이가 있습니다.&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;그럼 @Bean과 @Component 어노테이션은 언제 어떤 것을 사용하는 것이 좋을까요 ??&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;주로 외부 라이브러리와 같이 개발자가 직접 관리하지 못하는 객체는 @Bean을 사용하고, 개발자가 직접 관리할 수 있는 객체는 간편하게 @Component를 사용해 Spring Bean으로 등록할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 객체들이 복잡하게 관계를 맺고 있는 경우, 하나의 설정파일 내에서 개발자가 Bean을 직접 관리하거나 파악하고 싶은 경우 @Bean을 사용 할 수 있습니다.&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;그러나 개인적으로는 설정 파일을 통해  Bean을 관리하는 것 자체가 관리 포인트가 늘어난다고 생각해서, 외부 라이브러리를 @Bean으로 등록하고자 하는 케이스 외에는 왠만하면 @Component 를 사용하는 것이 좋다고 생각합니다.&lt;/p&gt;</description>
      <category>Study/Spring Framework</category>
      <author>iwannarest</author>
      <guid isPermaLink="true">https://jonghne.tistory.com/110</guid>
      <comments>https://jonghne.tistory.com/110#entry110comment</comments>
      <pubDate>Mon, 18 Mar 2024 14:48:29 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] 이진 탐색 트리(BST)의 개념 및 순회 방법</title>
      <link>https://jonghne.tistory.com/109</link>
      <description>&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;이진 탐색 트리 (Binary Search Tree) 의 개념&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;이진 탐색 트리란 ?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Binary Search Tree (이하, BST)는 모든 노드의 &lt;u&gt;왼쪽 서브 트리가 해당 노드 보다 작은 값&lt;/u&gt;을 가지고, &lt;u&gt;오른쪽 서브 트리가 해당 노드 보다 큰 값&lt;/u&gt;을 가지는 구조의 Binary Tree 입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BdAeO/btsFP7xims4/7uDIlOhXs0AtkKyKKjgva1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BdAeO/btsFP7xims4/7uDIlOhXs0AtkKyKKjgva1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BdAeO/btsFP7xims4/7uDIlOhXs0AtkKyKKjgva1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBdAeO%2FbtsFP7xims4%2F7uDIlOhXs0AtkKyKKjgva1%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;430&quot; height=&quot;453&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;453&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;위의 그림에서는 노드 20의 왼쪽 서브 트리는 모두 20보다 작은 값을 가지고, 오른쪽 서브 트리의 모든 값은 20보다 큰 값을 가지고 있습니다. 그런데 만약 자식 노드 중 이러한 조건을 하나라도 만족하지 않는 노드가 존재한다면 BST가 아니게 됩니다.&lt;/p&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의 자식 노드 중 오른쪽 자식 노드가 1의 값을 가진다면, 해당 트리는 더이상 BST가 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 특징을 가지는 BST는 &lt;span style=&quot;color: #333333; text-align: start;&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; 데이터 탐색,삽입,삭제 시 일반적으로는 O(logN)의 시간 복잡도를 가지지만, 최악의 경우 트리가 편향되어 O(n)의 시간 복잡도가 소요되는 경우가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;이진 탐색 트리의 장단점&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;장점&lt;/span&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;데이터의 삽입 / 삭제가 유연하다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드 간의 Reference만 조절하면 되기 때문에, 물리적으로 연속적인 메모리 공간에 저장하는 Array보다 유연합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;값이 정렬되어 있기 때문에 값의 순서대로 순회할 수 있습니다. (중위 순회)&lt;/li&gt;
&lt;li&gt;값이 정렬되어 있기 때문에, 삽입/삭제/검색의 시간이 일반적으로 빠릅니다 (시간 복잡도 : O(logN))&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&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;만약 이진 탐색 트리가 아래의 그림과 같이 한쪽으로 편향되는 경우에는 삽입/삭제/검색의 수행 시간이 느려지고, 최악의 경우 O(N)의 시간복잡도를 가지게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;492&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clwpkO/btsFN7sgxDA/wfyUW0Glev7ENz9egMF4K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clwpkO/btsFN7sgxDA/wfyUW0Glev7ENz9egMF4K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clwpkO/btsFN7sgxDA/wfyUW0Glev7ENz9egMF4K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclwpkO%2FbtsFN7sgxDA%2FwfyUW0Glev7ENz9egMF4K0%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;492&quot; height=&quot;648&quot; data-origin-width=&quot;492&quot; data-origin-height=&quot;648&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;이러한 문제를 해결하기 위해 스스로 균형을 잡는 이진 탐색 트리인 AVL 트리와 Red-Black 트리가 사용되곤 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;이진 탐색 트리 (Binary Search Tree) 순회 방식&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;BST의 순회 방식으로는 현재 노드를 순회하는 순서에 따라 &lt;u&gt;전위 순회(&lt;u&gt;preorder traversal&lt;/u&gt;)&lt;/u&gt;, &lt;u&gt;중위 순회(&lt;u&gt;inorder traversal&lt;/u&gt;)&lt;/u&gt;, &lt;u&gt;후위 순회(&lt;u&gt;postorder traversal&lt;/u&gt;)&lt;/u&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;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;전위 순회(pre order traversal)&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;전위 순회는 &lt;u&gt;현재 노드를 먼저 방문한 뒤, 재귀적으로 왼쪽 서브 트리를 모두 순회 하고 그 다음 오른쪽 서브 트리를 순회&lt;/u&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&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BdAeO/btsFP7xims4/7uDIlOhXs0AtkKyKKjgva1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BdAeO/btsFP7xims4/7uDIlOhXs0AtkKyKKjgva1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BdAeO/btsFP7xims4/7uDIlOhXs0AtkKyKKjgva1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBdAeO%2FbtsFP7xims4%2F7uDIlOhXs0AtkKyKKjgva1%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;430&quot; height=&quot;453&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;453&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;size18&quot;&gt;&lt;i&gt;&lt;b&gt;&quot;현재 노드 방문 (ex) 값 출력) =&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;재귀적으로 왼쪽 서브 트리 순회 =&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;재귀적으로 오른쪽 서브 트리 순회&quot;&lt;/b&gt;&lt;/i&gt;&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;/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 style=&quot;border: 5px solid #BDCEFF; border-radius: 0px 0px; padding: 15px 30px; margin: 0;&quot;&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; top: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 순회를 시작하게 되면 현재 노드는 20이기 때문에 먼저 본인 노드를 방문하고, 그 다음 왼쪽 서브 트리를 재귀 호출합니다.&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. 왼쪽 서브 트리의 현재 노드가 5가 되고 마찬가지로 본인을 먼저 방문 한 뒤, 왼쪽 서브 트리를 재귀 호출합니다.&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. 왼쪽 서브 트리의 현재 노드인 3번 노드는 본인을 방문 한 뒤, 하위 서브트리가 없기 때문에 부모 노드인 5번으로 돌아갑니다.&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;3. 5번 노드는 왼쪽서브 트리를 모두 순회했기 때문에, 오른쪽 서브 트리를 재귀 호출 합니다.&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;4. 이와 같은 식으로 오른쪽 서브 트리를 모두 순회한 뒤에는 20번 노드로 반환되고, 20번 노드는 동일한 방식으로 오른쪽 서브트리를 순회합니다.&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&gt;  &lt;/span&gt;결과적으로 순회 경로는 다음과 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;20 -&amp;gt; 5 -&amp;gt; 3 -&amp;gt; 15 -&amp;gt; 10 -&amp;gt; 17 -&amp;gt; 50 -&amp;gt; 30 -&amp;gt; 40&lt;/p&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; bottom: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&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;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;중위 순회(in order traversal)&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; text-align: start;&quot;&gt;중위 순회는&lt;span&gt; &lt;/span&gt;&lt;/span&gt;재귀적으로 &lt;u&gt;왼쪽 서브 트리를 모두 순회 한 뒤에 &lt;span style=&quot;text-align: start;&quot;&gt;현재 노드를 방문하고, &lt;/span&gt;그 다음 오른쪽 서브 트리를 순회&lt;/u&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;중위 순회는 값의 순서대로 (ex) 숫자면 크기, 문자면 알파벳 순) 순회를 할 수 있다는 장점이 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BdAeO/btsFP7xims4/7uDIlOhXs0AtkKyKKjgva1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BdAeO/btsFP7xims4/7uDIlOhXs0AtkKyKKjgva1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BdAeO/btsFP7xims4/7uDIlOhXs0AtkKyKKjgva1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBdAeO%2FbtsFP7xims4%2F7uDIlOhXs0AtkKyKKjgva1%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;430&quot; height=&quot;453&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;453&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;size18&quot;&gt;&lt;i&gt;&lt;b&gt;&quot;재귀적으로 왼쪽 서브 트리 순회 =&amp;gt; 현재 노드 방문 (ex) 값 출력) =&amp;gt; 재귀적으로 오른쪽 서브 트리 순회&quot;&lt;/b&gt;&lt;/i&gt;&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;/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 style=&quot;border: 5px solid #BDCEFF; border-radius: 0px 0px; padding: 15px 30px; margin: 0;&quot;&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; top: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 현재 노드 20을 먼저 방문하는 것이 아닌, 왼쪽 서브 트리의 마지막 노드까지 계속해서 순회합니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(경로 : 20번 -&amp;gt; 5번 -&amp;gt; 3번)&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. 왼쪽 서브 트리의 마지막 노드인 3번 노드에 도착하면 더이상 왼쪽 서브 트리가 없기 때문에, 현재 노드인 3번 노드를 방문합니다.&amp;nbsp; 그리고 오른쪽 서브 트리 또한 없기 때문에 부모 노드인 5번 노드로 돌아갑니다.&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;3. 5번 노드는 왼쪽 서브 트리를 모두 순회했기 때문에 본인 노드를 순회하고, 오른쪽 서브트리를 순회합니다.&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;4. 15번 노드는 먼저 왼쪽 서브트리를 모두 순회하고, 본인 노드를 순회한 뒤 오른쪽 서브 트리를 모두 순회합니다. (이 노드의 경우 10번 -&amp;gt; 15번 -&amp;gt; 17번 순으로 순회합니다)&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;5. 15번 노드가 모두 순회를 끝냈기 때문에 5번 노드로 돌아가고, 5번 노드도 모두 순회를 끝냈기 때문에 루트 노드인 20번으로 돌아갑니다.&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;6. 20번 노드는 왼쪽 서브 트리를 모두 순회했기 때문에 본인 노드을 방문하고 (ex) 값 출력), 오른쪽 서브트리 순회를 시작합니다.&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;7. 위와 같은 방식으로 오른쪽 서브 트리를 모두 순회합니다.&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&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&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;3 -&amp;gt; 5 -&amp;gt; 10 -&amp;gt; 15 -&amp;gt; 17 -&amp;gt; 20 -&amp;gt; 30 -&amp;gt; &lt;b&gt;40 -&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;50&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; bottom: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&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;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;후위 순회(post order traversal)&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; text-align: start;&quot;&gt;후위 순회는&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;재귀적으로 &lt;u&gt;왼쪽 서브 트리를 모두 순회하고, 그 다음 오른쪽 서브 트리를 순회한 다음 마지막으로 현재 노드를 방문&lt;/u&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&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BdAeO/btsFP7xims4/7uDIlOhXs0AtkKyKKjgva1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BdAeO/btsFP7xims4/7uDIlOhXs0AtkKyKKjgva1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BdAeO/btsFP7xims4/7uDIlOhXs0AtkKyKKjgva1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBdAeO%2FbtsFP7xims4%2F7uDIlOhXs0AtkKyKKjgva1%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;430&quot; height=&quot;453&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;453&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;size18&quot;&gt;&lt;i&gt;&lt;b&gt;&quot;재귀적으로 왼쪽 서브 트리 순회 =&amp;gt; 재귀적으로 오른쪽 서브 트리 순회&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;=&amp;gt; 현재 노드 방문 (ex) 값 출력)&lt;/b&gt;&quot;&lt;/b&gt;&lt;/i&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;border: 5px solid #BDCEFF; border-radius: 0px 0px; padding: 15px 30px; margin: 0;&quot;&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; top: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 현재 노드 20을 먼저 방문하는 것이 아닌, 왼쪽 서브 트리의 마지막 노드까지 계속해서 순회합니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(경로 : 20번 -&amp;gt; 5번 -&amp;gt; 3번)&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. 3번 노드에 도착하면 왼쪽 서브 트리와 오른쪽 서브 트리가 모두 없기 때문에, 현재 노드를 방문한 뒤 5번 노드로 돌아갑니다.&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;3. 5번 노드는 왼쪽 서브트리를 모두 순회했기 때문에, 오른쪽 서브트리를 위와 같은 방식으로 순회합니다.&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;4. 5번의 오른쪽 서브트리를 모두 순회한 뒤 본인 노드를 방문하고, 다시 20번 노드로 돌아갑니다.&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;5. 20번 노드는 왼쪽 서브 트리를 모두 순회했기 때문에, 오른쪽 서브트리를 순회하기 시작합니다.&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;6. 동일한 방법으로 오른쪽 트리를 모두 순회한 뒤에, 20번 노드로 다시 돌아와서 현재 노드를 방문하고 순회를 마칩니다.&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&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&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;3 -&amp;gt; 10 -&amp;gt; 17 -&amp;gt; 15 -&amp;gt; 5 -&amp;gt; 40 -&amp;gt; 30 -&amp;gt; 50 -&amp;gt; 20&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; bottom: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&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;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;자바 코드 구현&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Binary Searh Tree의 전위,중위,후위 순회는 자바 언어로 다음과 같이 구현할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1710486581086&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 노드를 나타내는 클래스
public static class Node {
    public Node left;
    public Node right;
    public int data;
    
    // 생성자
    public static Node makeNode(Node left, int data, Node right) {
        Node node = new Node();
        node.setLeft(left);
        node.setData(data);
        node.setRight(right);

        return node;
    }
    
    // Getter
    public Node getLeft() {
        return left;
    }

    public Node getRight() {
        return right;
    }
}


public class BST {
    public static void main(String[] args) {		
        Node node10 = Node.makeNode(null, 10, null);
        Node node17 = Node.makeNode(null, 17, null);
        Node node15 = Node.makeNode(node10, 15, node17);
        Node node03 = Node.makeNode(null, 3, null);
        Node node05 = Node.makeNode(node03, 5, node15);

        Node node40 = Node.makeNode(null, 40, null);
        Node node30 = Node.makeNode(null, 30, node40);
        Node node50 = Node.makeNode(node30, 50, null);


        Node root = Node.makeNode(node05, 20, node50);

        System.out.print(&quot;preOrder : &quot;);
        preOrder(root);
        System.out.println();
        
        
        System.out.print(&quot;inOrder : &quot;);
        inOrder(root);
        System.out.println();

        System.out.print(&quot;postOrder : &quot;);
        postOrder(root);
        System.out.println();
    }
    
	public static void preOrder(Node node) {

        // 재귀 종료 조건
        if(node == null) {
            return;
        }

        // 현재 노드 방문 - 값 출력
        System.out.print(node.getData()+&quot; &quot;);
        
        // 왼쪽 서브 트리 순회
        preOrder(node.getLeft());
        
        // 오른쪽 서브 트리 순회
        preOrder(node.getRight());

    }
    
  public static void inOrder(Node node) {
  
        // 재귀 종료 조건
        if(node == null) {
            return;
        }
        
        // 왼쪽 서브 트리 순회
        inOrder(node.getLeft());
        
        // 현재 노드 방문 - 값 출력
        System.out.print(node.getData()+&quot; &quot;);
        
        // 오른쪽 서브 트리 순회
        inOrder(node.getRight());
  }
    
	public static void postOrder(Node node) {
        
        // 재귀 종료 조건
        if(node == null) {
            return;
        }
        
        // 왼쪽 서브 트리 순회
        postOrder(node.getLeft());
        
        // 오른쪽 서브 트리 순회
        postOrder(node.getRight());
        
        // 현재 노드 방문 - 값 출력
        System.out.print(node.getData()+&quot; &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&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;421&quot; data-origin-height=&quot;313&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkSQuP/btsFNxdzPlL/H5b0RhpddlUKMin7Avpj5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkSQuP/btsFNxdzPlL/H5b0RhpddlUKMin7Avpj5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkSQuP/btsFNxdzPlL/H5b0RhpddlUKMin7Avpj5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkSQuP%2FbtsFNxdzPlL%2FH5b0RhpddlUKMin7Avpj5K%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;421&quot; height=&quot;313&quot; data-origin-width=&quot;421&quot; data-origin-height=&quot;313&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;span&gt;  &lt;/span&gt;참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=i57ZGhOVPcI&amp;amp;list=PLcXyemr8ZeoR82N8uZuG9xVrFIfdnLd72&amp;amp;index=8&amp;amp;ab_channel=%EC%89%AC%EC%9A%B4%EC%BD%94%EB%93%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=i57ZGhOVPcI&amp;amp;list=PLcXyemr8ZeoR82N8uZuG9xVrFIfdnLd72&amp;amp;index=8&amp;amp;ab_channel=%EC%89%AC%EC%9A%B4%EC%BD%94%EB%93%9C&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Data Structure</category>
      <author>iwannarest</author>
      <guid isPermaLink="true">https://jonghne.tistory.com/109</guid>
      <comments>https://jonghne.tistory.com/109#entry109comment</comments>
      <pubDate>Fri, 15 Mar 2024 16:36:48 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] Binary Tree의 개념과 종류</title>
      <link>https://jonghne.tistory.com/108</link>
      <description>&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;이진 트리란 ?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진 트리는 트리 형태의 자료 구조 중 가장 많이 사용하는 트리로, 각 노드의 자녀 노드 수가 최대 두개인 트리를 이진 트리(Binary Tree)라고 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;424&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dE1zhv/btsFMrLba0A/X9FbHRIcMIKNMkbq9XuUnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dE1zhv/btsFMrLba0A/X9FbHRIcMIKNMkbq9XuUnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dE1zhv/btsFMrLba0A/X9FbHRIcMIKNMkbq9XuUnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdE1zhv%2FbtsFMrLba0A%2FX9FbHRIcMIKNMkbq9XuUnK%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;424&quot; height=&quot;436&quot; data-origin-width=&quot;424&quot; data-origin-height=&quot;436&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;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;형태에 따른 이진 트리 종류&lt;/b&gt;&lt;/h2&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Full Binary Tree (정 이진 트리)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Full Binary Tree란 &lt;u&gt;모든 노드가 자녀 노드가 없거나 또는 두 개의 자녀 노드를 가지는&lt;/u&gt; 이진 트리입니다. (즉, 자녀 노드를 1개를 가지는 노드가 없어야 합니다)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;457&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b475si/btsFOZsHyTt/j53Lkob5VTs4L15sMSfwnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b475si/btsFOZsHyTt/j53Lkob5VTs4L15sMSfwnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b475si/btsFOZsHyTt/j53Lkob5VTs4L15sMSfwnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb475si%2FbtsFOZsHyTt%2Fj53Lkob5VTs4L15sMSfwnK%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;444&quot; height=&quot;457&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;457&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;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;2. complete binary tree (완전 이진 트리)&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;complete binary tree는 &lt;u&gt;마지막 레벨을 제외한 모든 레벨의 노드가 두 개씩 노드를 가지고&lt;/u&gt;, &lt;u&gt;마지막 레벨은 왼쪽 부터 빠짐없이 노드가 채워지는&lt;/u&gt; 이진 트리입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;449&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/roHpk/btsFNuN1Fme/vAs1ky5YElMOsVVWmgKUok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/roHpk/btsFNuN1Fme/vAs1ky5YElMOsVVWmgKUok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/roHpk/btsFNuN1Fme/vAs1ky5YElMOsVVWmgKUok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FroHpk%2FbtsFNuN1Fme%2FvAs1ky5YElMOsVVWmgKUok%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;453&quot; height=&quot;449&quot; data-origin-width=&quot;453&quot; data-origin-height=&quot;449&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;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3. perfect binary tree (포화 이진 트리)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;perfect binary tree란 &lt;u&gt;모든 레벨에서 노드가 빠짐없이 채워져 있는&lt;/u&gt; 이진 트리입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;455&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3neuM/btsFPrWPDQ8/mVPOkNLwjvs7CKyQWkApy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3neuM/btsFPrWPDQ8/mVPOkNLwjvs7CKyQWkApy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3neuM/btsFPrWPDQ8/mVPOkNLwjvs7CKyQWkApy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3neuM%2FbtsFPrWPDQ8%2FmVPOkNLwjvs7CKyQWkApy0%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;463&quot; height=&quot;455&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;455&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;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. degenerate binary tree (변질 이진 트리)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;degenerate binary tree는 &lt;u&gt;모든 부모 노드가 하나의 자녀 노드만 가지는&lt;/u&gt; 이진 트리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 degenerate binary tree는 자녀 노드의 위치에 따라 left skewed binary tree, right skewed binary tree로 나뉩니다.&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;4.1. left skewed binary tree&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;left skewed binary tree는 왼쪽으로 편향된 이진 트리라는 뜻으로, 모든 노드가 왼쪽 자녀 노드 한개만 가지는 이진 트리입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;338&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/le4c8/btsFOXV0rWW/Mj1nqOrafyNosMAIoest3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/le4c8/btsFOXV0rWW/Mj1nqOrafyNosMAIoest3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/le4c8/btsFOXV0rWW/Mj1nqOrafyNosMAIoest3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fle4c8%2FbtsFOXV0rWW%2FMj1nqOrafyNosMAIoest3K%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;338&quot; height=&quot;456&quot; data-origin-width=&quot;338&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4.2.&lt;span&gt; right&lt;/span&gt;&amp;nbsp;skewed binary tree&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;right skewed binary tree는 오른쪽으로 편향된 이진 트리라는 뜻으로, 모든 노드가 왼쪽 자녀 노드 한개만 가지는 이진 트리입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;366&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JGzkJ/btsFO1jNf0o/tidx6u3Dx5lxwnbRPKWXoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JGzkJ/btsFO1jNf0o/tidx6u3Dx5lxwnbRPKWXoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JGzkJ/btsFO1jNf0o/tidx6u3Dx5lxwnbRPKWXoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJGzkJ%2FbtsFO1jNf0o%2Ftidx6u3Dx5lxwnbRPKWXoK%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;366&quot; height=&quot;466&quot; data-origin-width=&quot;366&quot; data-origin-height=&quot;466&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;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;5. balanced binary tree (균형 이진 트리)&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;balanced binary tree는 &lt;u&gt;모든 노드&lt;/u&gt;에서 &lt;u&gt;왼쪽 서브트리와 오른쪽 서브 트리의 높이 차이가 최대 1인&lt;/u&gt; 트리를 말합니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;  서브트리란 ?&lt;br /&gt;특정 노드의 자식 노드들이 각각을 루트 노드로 트리를 구성하는 트리의 부분 집합을 말합니다.&lt;br /&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;아래의 예시 그림에서 모든 노드의 서브트리가 balanced 한지 알아보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;378&quot; data-origin-height=&quot;477&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rIis9/btsFP2bsSjR/eFPHhxCGrSJOHfLzJPUzkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rIis9/btsFP2bsSjR/eFPHhxCGrSJOHfLzJPUzkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rIis9/btsFP2bsSjR/eFPHhxCGrSJOHfLzJPUzkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrIis9%2FbtsFP2bsSjR%2FeFPHhxCGrSJOHfLzJPUzkk%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;378&quot; height=&quot;477&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;378&quot; data-origin-height=&quot;477&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;(1) 노드 2 :&amp;nbsp; 왼쪽 서브 트리 {5,7} 은 트리의 높이가 1이고, 오른쪽 서브 트리 {9,1,3,4} 의 트리의 높이가 2입니다.&lt;br /&gt;&lt;br /&gt;(2) 노드 5 : 왼쪽 서브 트리는 없기 때문에 트리 높이가 -1 이고, 오른쪽 서브트리 {7} 은 트리 높이가 0입니다.&lt;br /&gt;&lt;br /&gt;(3) 노드 9 : 왼쪽 서브 트리인 {1,4} 는 트리 높이가 1 이고, 오른쪽 서브트리 {3} 은 트리 높이가 0입니다.&lt;br /&gt;&lt;br /&gt;(4) 노드 1 : 왼쪽 서브트리 {1}은 트리 높이가 0이고, 오른쪽 서브트리는 없기 때문에 -1 입니다.&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;모든 노드의 왼쪽 서브트리와 오른쪽 서브트리의 트리 높이 차이가 1을 넘지 않기 때문에, balanced binary tree(균형 이진 트리)라고 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 7번 노드가 없을 때는 2번 노드의 왼쪽 서브트리와 오른쪽 서브트리의 트리 높이 차이가 2가 되기 때문에 balanced binary tree라고 할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&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;text-align: left;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;출처&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=ohrwGtqeW-I&amp;amp;list=PLcXyemr8ZeoR82N8uZuG9xVrFIfdnLd72&amp;amp;index=8&amp;amp;ab_channel=%EC%89%AC%EC%9A%B4%EC%BD%94%EB%93%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=ohrwGtqeW-I&amp;amp;list=PLcXyemr8ZeoR82N8uZuG9xVrFIfdnLd72&amp;amp;index=8&amp;amp;ab_channel=%EC%89%AC%EC%9A%B4%EC%BD%94%EB%93%9C&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;</description>
      <category>Study/Data Structure</category>
      <author>iwannarest</author>
      <guid isPermaLink="true">https://jonghne.tistory.com/108</guid>
      <comments>https://jonghne.tistory.com/108#entry108comment</comments>
      <pubDate>Fri, 15 Mar 2024 13:32:12 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] Tree의 구조와 용어, 주요 특징</title>
      <link>https://jonghne.tistory.com/107</link>
      <description>&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Tree의 개념&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리(Tree) 란 노드(Node)들의 집합으로, 노드는 값(value)과 다른 노드들을 가리키는 레퍼런스(Reference)들로 구성되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Tree의 주요 용어&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xb34o/btsFMBfUQDp/idJhNKnsSyihhwWA8tPYxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xb34o/btsFMBfUQDp/idJhNKnsSyihhwWA8tPYxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xb34o/btsFMBfUQDp/idJhNKnsSyihhwWA8tPYxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXb34o%2FbtsFMBfUQDp%2FidJhNKnsSyihhwWA8tPYxK%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;975&quot; height=&quot;551&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;551&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;간선&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간선 (Edge)란 노드와 노드를 연결하는 선을 의미하고, 구현 관점에서는 노드 간의 주소 값 레퍼런스(참조)를 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&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;각 노드들이 무엇이고 어떤 역할을 하는지 그림을 통해 알아보겠습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 루트 노드 (Root Node)&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;/li&gt;
&lt;li&gt;위 그림에서 P에 해당합니다.&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. 자녀 노드 (Child Node)&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;/li&gt;
&lt;li&gt;부모 노드로 부터 직접적으로 연결된 노드&lt;/li&gt;
&lt;li&gt;위 그림에서 E,F,G 노드는 L 노드의 자식 노드입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 부모 노드 (Parent Node)&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;/li&gt;
&lt;li&gt;위 그림에서 L 노드는&amp;nbsp;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;E,F,G 노드의&lt;/span&gt;&amp;nbsp;부모 노드입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 형제 노드&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Parent Node)&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;/li&gt;
&lt;li&gt;위 그림에서 A, B 노드는 Q 노드를 부모로 가지는 형제 노드입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. 조상 노드 (Ancestor Node)&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;/li&gt;
&lt;li&gt;위 그림에서 E 노드의 조상 노드는 L, A, Q, P 노드 입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6. 자손 노드 (Ancestor Node)&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;/li&gt;
&lt;li&gt;위 그림에서 A의 자손 노드는 L, E, F, G 입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;7. 내부 노드 (Internal Node)&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;/li&gt;
&lt;li&gt;리프 노드를 제외한 모든 노드가 이에 해당합니다.&lt;/li&gt;
&lt;li&gt;위 그림에서 내부 노드는 B, D, E, F, G, H, I 노드를 제외한 모든 노드가 이에 해당합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;8. 외부 노드 (External Node)&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;/li&gt;
&lt;li&gt;흔히, Leaf Node라고 부르곤 합니다.&lt;/li&gt;
&lt;li&gt;위 그림에서 외부 노드는 B, D, E, F, G, H, I 노드입니다.&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;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xb34o/btsFMBfUQDp/idJhNKnsSyihhwWA8tPYxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xb34o/btsFMBfUQDp/idJhNKnsSyihhwWA8tPYxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xb34o/btsFMBfUQDp/idJhNKnsSyihhwWA8tPYxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXb34o%2FbtsFMBfUQDp%2FidJhNKnsSyihhwWA8tPYxK%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;975&quot; height=&quot;551&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;551&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;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;트리 및 노드의 경로 / 길이 / 높이&lt;/h3&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;/li&gt;
&lt;li&gt;위 그림에서 P 노드에서 G 노드까지의 경로는 다음과 같습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;P -&amp;gt; Q -&amp;gt; A -&amp;gt; L -&amp;gt; G&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&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;경로에 있는 노드들의 수를 의미합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;위 그림에서 P 노드에서 G 노드까지의 경로의 길이는 5입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;P, Q, A, L, G 노드를 거치기 때문입니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&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;특정 노드에서 리프 노드까지의 &lt;u&gt;가장 긴 경로의 간선(Edge) 수&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;리프 노드의 높이는 0&amp;nbsp;&lt;/li&gt;
&lt;li&gt;위 그림에서 Q 노드의 높이는 가장 아래에 있는 리프 노드 까지의 간선의 수인 3입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;즉, 리프 노드 B 까지의 간선의 수가 아닌 &lt;u&gt;가장 하위에 있는 리프 노드&lt;/u&gt;인 E,F,G 까지의 간선의 수입니다.&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;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 트리의 높이&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;/li&gt;
&lt;li&gt;위 그림에서는 P 노드의 높이인 4가 트리의 높이입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;b&gt;5. 노드의 깊이&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;루트 노드에서 특정 노드까지 경로의 간선(Edge) 수&lt;/li&gt;
&lt;li&gt;루트 노드의 깊이는 0&lt;/li&gt;
&lt;li&gt;노드의 높이는 리프노드가 기준이었다면, 노드의 깊이는 루트 노드가 기준입니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;위 그림에서 Q 노드의 깊이는 1입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6. 트리의 깊이&amp;nbsp;&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;트리에 있는 노드들의 깊이 중 가장 긴 깊이(Depth)&lt;/li&gt;
&lt;li&gt;위 그림에서 트리의 깊이는 리프노드의 깊이인 4입니다.&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-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xb34o/btsFMBfUQDp/idJhNKnsSyihhwWA8tPYxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xb34o/btsFMBfUQDp/idJhNKnsSyihhwWA8tPYxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xb34o/btsFMBfUQDp/idJhNKnsSyihhwWA8tPYxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXb34o%2FbtsFMBfUQDp%2FidJhNKnsSyihhwWA8tPYxK%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;975&quot; height=&quot;551&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;551&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;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;차수 (degree) /&amp;nbsp; 거리 (distance)&amp;nbsp;&lt;/h3&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;노드의 자녀 노드 수를 의미합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;위 그림에서 L의 차수는 3입니다.&lt;/li&gt;
&lt;/ul&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;트리에 있는 노드들의 차수 중 가장 큰 차수&lt;/li&gt;
&lt;li&gt;위 그림에서 트리의 차수는 L 노드의 차수인 3입니다.&lt;/li&gt;
&lt;/ul&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;두 노드 사이의 최단 경로의 간선 수&lt;/li&gt;
&lt;li&gt;위 그림에서 E 노드와 P 노드의 거리는 4입니다 (E -&amp;gt; L -&amp;gt; A -&amp;gt; Q -&amp;gt; P)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;노드의 레벨 / 너비(width)&lt;/h3&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;/li&gt;
&lt;li&gt;위 그림에서 Q 노드는 루트 노드 P까지 간선의 수가 1개이기 때문에 Level 1 입니다.&lt;/li&gt;
&lt;li&gt;위 그림에서 E 노드는 루트 노드 P까지 간선의 수가 4개이기 때문에 Level 4 입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 너비 (width)&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;/li&gt;
&lt;li&gt;위 그림에서 Level 2의 width는 2입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;트리 및 노드의 크기(size)&lt;/h3&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;/li&gt;
&lt;li&gt;위 그림에서 A 노드의 크기는 자손 노드 L, E, F, G의 수인 4입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; 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;트리의 모든의 노드 수&lt;/li&gt;
&lt;li&gt;위 그림에서 트리의 크기는 13입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;서브 트리&amp;nbsp;&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;위 그림에서는 L 을 루트 노드로 가지는 서브트리가 존재합니다.&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Tree의 주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;1. 루트 노드는 하나만 존재한다.&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;401&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n4syJ/btsFPGM9InW/WuddBsHDsB4km9iHYSlOZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n4syJ/btsFPGM9InW/WuddBsHDsB4km9iHYSlOZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n4syJ/btsFPGM9InW/WuddBsHDsB4km9iHYSlOZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn4syJ%2FbtsFPGM9InW%2FWuddBsHDsB4km9iHYSlOZ0%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;401&quot; height=&quot;377&quot; data-origin-width=&quot;401&quot; data-origin-height=&quot;377&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;2. 트리는 사이클이 존재하지 않는다. &lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;365&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JQWWM/btsFPoZ1rix/jaOB9E8NTsVxrJViyTZzn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JQWWM/btsFPoZ1rix/jaOB9E8NTsVxrJViyTZzn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JQWWM/btsFPoZ1rix/jaOB9E8NTsVxrJViyTZzn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJQWWM%2FbtsFPoZ1rix%2FjaOB9E8NTsVxrJViyTZzn0%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;365&quot; height=&quot;381&quot; data-origin-width=&quot;365&quot; data-origin-height=&quot;381&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;3. 자녀 노드는 하나의 부모 노드만 존재한다.&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;370&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNmMMH/btsFNyv2sFj/xEnMhYR3lue54b9DaKGZLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNmMMH/btsFNyv2sFj/xEnMhYR3lue54b9DaKGZLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNmMMH/btsFNyv2sFj/xEnMhYR3lue54b9DaKGZLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNmMMH%2FbtsFNyv2sFj%2FxEnMhYR3lue54b9DaKGZLK%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;370&quot; height=&quot;360&quot; data-origin-width=&quot;370&quot; data-origin-height=&quot;360&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 데이터를 순차적으로 저장하지 않는 비선형 구조이다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터의 순서를 지키며 저장하는 ArrayList 또는 LinkedList와 다르게 데이터를 순차적으로 저장하지 않습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1001&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QoblI/btsFOeK9RjV/4eXzt6QQkxqKmBtF6Oj7Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QoblI/btsFOeK9RjV/4eXzt6QQkxqKmBtF6Oj7Kk/img.png&quot; data-alt=&quot;https://www.codesdope.com/course/data-structures-binary-trees/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QoblI/btsFOeK9RjV/4eXzt6QQkxqKmBtF6Oj7Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQoblI%2FbtsFOeK9RjV%2F4eXzt6QQkxqKmBtF6Oj7Kk%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;500&quot; height=&quot;461&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1001&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.codesdope.com/course/data-structures-binary-trees/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. 서브 트리를 가지는 재귀적 구조이다.&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1290&quot; data-origin-height=&quot;1282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bE46tF/btsFPcsmjqT/mFZX7iPyUI6Ye6lB4cUC1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bE46tF/btsFPcsmjqT/mFZX7iPyUI6Ye6lB4cUC1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bE46tF/btsFPcsmjqT/mFZX7iPyUI6Ye6lB4cUC1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbE46tF%2FbtsFPcsmjqT%2FmFZX7iPyUI6Ye6lB4cUC1k%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;500&quot; height=&quot;497&quot; data-origin-width=&quot;1290&quot; data-origin-height=&quot;1282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6. 부모-자식 관계를 가지는 계층적 구조이다.&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;477&quot; data-origin-height=&quot;337&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVTA5N/btsFQdjYG1W/6IoV8gbH5Sk8ib2hMkkSjk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVTA5N/btsFQdjYG1W/6IoV8gbH5Sk8ib2hMkkSjk/img.gif&quot; data-alt=&quot;https://velog.io/@roycewon/Tree-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVTA5N/btsFQdjYG1W/6IoV8gbH5Sk8ib2hMkkSjk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cVTA5N/btsFQdjYG1W/6IoV8gbH5Sk8ib2hMkkSjk/img.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;477&quot; height=&quot;337&quot; data-origin-width=&quot;477&quot; data-origin-height=&quot;337&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://velog.io/@roycewon/Tree-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0&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;&lt;b&gt;&lt;span&gt;  &lt;/span&gt;참고&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=ohrwGtqeW-I&amp;amp;list=PLcXyemr8ZeoR82N8uZuG9xVrFIfdnLd72&amp;amp;index=7&amp;amp;ab_channel=%EC%89%AC%EC%9A%B4%EC%BD%94%EB%93%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=ohrwGtqeW-I&amp;amp;list=PLcXyemr8ZeoR82N8uZuG9xVrFIfdnLd72&amp;amp;index=7&amp;amp;ab_channel=%EC%89%AC%EC%9A%B4%EC%BD%94%EB%93%9C&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Data Structure</category>
      <author>iwannarest</author>
      <guid isPermaLink="true">https://jonghne.tistory.com/107</guid>
      <comments>https://jonghne.tistory.com/107#entry107comment</comments>
      <pubDate>Fri, 15 Mar 2024 12:32:56 +0900</pubDate>
    </item>
    <item>
      <title>Garbage Collection의 동작 방식과 종류</title>
      <link>https://jonghne.tistory.com/106</link>
      <description>&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt; Garbage Collection 이란 ?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Garbage Collection (이하 GC)는 자바의 메모리 관리 기법 중 하나로, Heap 영역에서 제거 대상(Garbage)를 찾아내고 제거해서 힙 메모리를 회수하는 기능을 한다.&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;일반적으로 C, C++ 와 같은 언어에서는 이와 같은 GC가 없기 때문에 개발자가 직접 메모리 할당과 해제를 직접 관리해야 한다. &lt;/span&gt;&lt;/p&gt;
&lt;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;그러나 Java는 JVM내에 GC가 내장되어 있어 개발자는 메모리 관리에 신경쓰지 않고 개발에만 집중할 수 있다는 장점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;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;하지만 이런 GC에는 몇가지 단점이 존재하는데, GC가 메모리를 언제 해제하는지 개발자는 정확하게 알 수 없어서 제어하기 힘들다는 점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;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;또한 GC가 발생하는 동안에는 다른 스레드들이 일을 멈추게 되는 Stop-The-World가 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;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;이 Stop-The-World는 사용자 입장에서는 오버헤드가 발생한 것이기 때문에 너무 잦은 GC가 발생하면 성능 이슈로 이어질 수 있다.&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 style=&quot;color: #333333; text-align: start;&quot;&gt;결론적으로 자바 개발자들은 평소 GC가  메모리를 관리해주기 때문에 메모리 관련해서 신경쓰지 않고 편하게 개발할 수 있지만, 만약 GC로 인해 성능 저하가 생긴다면 GC튜닝을 통해 해결해야 할 수 있기 때문에 GC의 종류와 특징에 대해 잘 알아둬야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt; Garbage Collection 의 제거 대상&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java의 GC는 도달 능력(reachability)라는 개념을 사용해서 유효한 참조가 있는 객체(reachable object)와 유효한 참조가 없는 객체(unreachable object)를 구분하고, 유효한 참조가 없는 객체에 대해 GC를 수행한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;그럼, GC는 유효한 참조가 있는 지 어떻게 알아낼까?&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;힙의 객체가 참조되는 경우는 다음과 같은 4가지 경우가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1. 힙 내의 다른 객체에 의한 참조&lt;br /&gt;2. Java 스택의 지역 변수 또는 파라미터에 의한 참조&lt;br /&gt;3. 네이티브 스택 내의 JNI(자바 네이티브 인터페이스)에 의한 참조&lt;br /&gt;4. 메서드 영역의 정적 변수에 의한 참조&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙의 객체가 1번의 경우를 제외한 나머지 경우에 의해 참조 되는 경우를 Root Set이라고 하는데, 이 Root Set으로 부터 시작해서 참조 사슬로 속한 객체들은 유효한 참조가 있는 객체 (reachable object)로 간주한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 Root Set으로 부터 시작하지 않고 힙 내의 객체들끼리 연결되어 있는 경우를 unreachable object라고 하고 GC의 대상이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yL0GK/btsECv7MqIl/QysHAOOnWQqKWU1j0DKZKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yL0GK/btsECv7MqIl/QysHAOOnWQqKWU1j0DKZKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yL0GK/btsECv7MqIl/QysHAOOnWQqKWU1j0DKZKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyL0GK%2FbtsECv7MqIl%2FQysHAOOnWQqKWU1j0DKZKK%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;668&quot; height=&quot;443&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Garbage Collection 진행 과정&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GC는 다음과 같은 두가지의 가설(전제조건)을 토대로 만들어진다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1. 대부분의 객체는 금방 unreachable한 상태가 된다.&amp;nbsp;&lt;br /&gt;2. 생성된지 오래된 객체에서 생성된지 얼마 안 된 젊은 객체로의 참조는 아주 드물게 발생한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 가설(전제조건)을 Weak Generational Hypothesis 라고 하는데, 대부분의 GC는 이러한 전제조건의 특징을 살려서 힙 영역을 크게 Young Generation과 Old Generation이라는 물리적인 공간으로 나누고 각 영역 별로 GC를 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;Young Generation&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Young Generation 영역에는 새로 생성된 객체가 위치하는 영역으로 대부분의 객체가 금방 unreachable 상태가 되어 제거되고 메모리가 꽉 차면 Minor 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;이 Young Generation 영역은 세부적으로 Eden / Survivor0 / Survivor1 영역으로 나뉘게 된다.&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;최초 생성되는 객체는 Eden에 머무르다가 메모리가 가득 차면 Minor GC에 의해 제거되고, 살아남은 객체는 Survivor 영역에 번갈아가며 위치하다가 일정 수준의 Age 값에 도달한다면 Old Generation 영역으로 이동하게 된다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;동작 방식&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 애플리케이션이 동적으로 생성한 객체가 Eden 영역에 쌓이게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;660&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqZn90/btsEBldRuUI/lAwf2NtWRayXYyJEt0x2m0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqZn90/btsEBldRuUI/lAwf2NtWRayXYyJEt0x2m0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqZn90/btsEBldRuUI/lAwf2NtWRayXYyJEt0x2m0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqZn90%2FbtsEBldRuUI%2FlAwf2NtWRayXYyJEt0x2m0%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;1920&quot; height=&quot;660&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;660&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;2. 계속 객체가 생성되다가 Eden 영역의 메모리가 꽉 차면 Minor GC가 발생해서 GC 대상인 객체는 제거하고, 살아남은 객체는 Survivor 영역 중 한 곳으로 옮긴다 (현재 활성화 되어 있는)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;680&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWhXtb/btsEEwLYsec/cBmb9zSCLVAzK2rxdCj4Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWhXtb/btsEEwLYsec/cBmb9zSCLVAzK2rxdCj4Kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWhXtb/btsEEwLYsec/cBmb9zSCLVAzK2rxdCj4Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWhXtb%2FbtsEEwLYsec%2FcBmb9zSCLVAzK2rxdCj4Kk%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;1920&quot; height=&quot;680&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;680&quot;/&gt;&lt;/span&gt;&lt;/figure&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;3. Minor GC 이후 다시 Eden 영역에 객체가 가득 차면 또 다시 Minor GC가 발생하고, 이 때 살아남은 객체들은 또다른 Survivor 영역으로 옮긴다. (이 때, 기존 Survivor 영역의 객체도 함께 옮겨진다)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;655&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crevVH/btsEDgpmUY3/tVH2aqcCIFEVPH3JCHp4tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crevVH/btsEDgpmUY3/tVH2aqcCIFEVPH3JCHp4tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crevVH/btsEDgpmUY3/tVH2aqcCIFEVPH3JCHp4tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrevVH%2FbtsEDgpmUY3%2FtVH2aqcCIFEVPH3JCHp4tk%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;1920&quot; height=&quot;655&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;655&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;4. 이런 방식으로 Survivor 영역을 옮겨가며 생존하는 객체들은 Minor GC가 발생할 때 마다 객체가 살아남은 횟수를 의미하는 Age 값이 증가하게 되고, JVM 별로 설정한 특정 Age값에 도달하면 Old Generation 영역으로 이동하는 Promotion이 발생한다.&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;1920&quot; data-origin-height=&quot;639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OEbG2/btsECvfZWiy/RRmiD0WXSjdktHDds954Q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OEbG2/btsECvfZWiy/RRmiD0WXSjdktHDds954Q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OEbG2/btsECvfZWiy/RRmiD0WXSjdktHDds954Q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOEbG2%2FbtsECvfZWiy%2FRRmiD0WXSjdktHDds954Q0%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;1920&quot; height=&quot;639&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;639&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;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;Old Generation&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Old Generation은 Young Generation에서 오랫동안 살아남은 객체들이 Promotion을 통해 이동하는 영역이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 영역은 대부분 Young Generation 보다 큰 메모리 공간을 할당 받아서 GC가 자주 발생하지는 않는다. 하지만 이 영역에서도 객체가 계속 쌓이다가 메모리가 꽉 차면 GC가 발생하는데 이 것을 Major GC 또는 Full 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;이 Major GC / Full GC 가 발생하면 애플리케이션이 GC를 수행하는 동안 잠시 멈추는 Stop-The-World가 발생한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;참고 !&amp;nbsp;&lt;br /&gt;Minor GC에서도 GC를 하는 순간에는 Stop-The-World 가 발생할 수 있지만, Old Generation 영역 보다 메모리 공간이 작기 때문에 GC를 수행하는 동안 발생하는  Stop-The-World 시간이 비교적 짧다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;666&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCEVHJ/btsEARYKtLB/3B76P9laP8nECvW1KEgpJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCEVHJ/btsEARYKtLB/3B76P9laP8nECvW1KEgpJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCEVHJ/btsEARYKtLB/3B76P9laP8nECvW1KEgpJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCEVHJ%2FbtsEARYKtLB%2F3B76P9laP8nECvW1KEgpJk%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;1920&quot; height=&quot;666&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;666&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;GC 종류&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자바가 발전됨에 따라 Heap 사이즈가 커지게 되었고, 이를 효율적으로 사용하기 위해 다양한 GC 알고리즘이 개발 되었다.&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;900&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnI1Ui/btsEFc8gepU/RDwmJ6HnwsLi9VMbX0pSA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnI1Ui/btsEFc8gepU/RDwmJ6HnwsLi9VMbX0pSA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnI1Ui/btsEFc8gepU/RDwmJ6HnwsLi9VMbX0pSA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnI1Ui%2FbtsEFc8gepU%2FRDwmJ6HnwsLi9VMbX0pSA1%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;900&quot; height=&quot;550&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;550&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;Serial GC&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싱글 스레드로 동작하는 가장 단순한 방식의 GC이다. CPU 코어가 한개만 있을 때 사용하기 위해 만든 GC이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Serial GC는 Stop-The-World 시간이 다른 GC에 비해 매우 길기 때문에 실무에선 사용하지 않는 것이 좋다.&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;1920&quot; data-origin-height=&quot;2129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/duBDNi/btsEEyQGXp0/PpdCAPUAYNqhmiYdEXzYYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/duBDNi/btsEEyQGXp0/PpdCAPUAYNqhmiYdEXzYYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/duBDNi/btsEEyQGXp0/PpdCAPUAYNqhmiYdEXzYYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FduBDNi%2FbtsEEyQGXp0%2FPpdCAPUAYNqhmiYdEXzYYK%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;1920&quot; height=&quot;2129&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;2129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Serial GC는 Young Generation에서는 가장 기본적인 GC 알고리즘인 Makr-Sweep을 사용해서 Minor 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;Mark-Sweep 알고리즘은 객체 그래프 탐색을 통해 객체 참조 정보를 마킹해서 reachable / unreachable 객체를 구분하고, unreachable 객체를 힙에서 제거하는 알고리즘이다.&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;Old Generation에서는 이 Mark-Sweep 이후 단편화된 메모리를 압축시켜주는 Compact 단계가 추가된 Mark-Sweep-Compact 알고리즘을 사용해서 Full GC를 수행한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;Mark-Sweep-Compact&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBonY2/btsEDpzYW6U/BQyOTkyltL6CBSbEkWvpi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBonY2/btsEDpzYW6U/BQyOTkyltL6CBSbEkWvpi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBonY2/btsEDpzYW6U/BQyOTkyltL6CBSbEkWvpi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBonY2%2FbtsEDpzYW6U%2FBQyOTkyltL6CBSbEkWvpi1%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;1920&quot; height=&quot;500&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;500&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;Mark : 객체 그래프 탐색을 통해 각각의 객체에 대한 참조 정보를 마킹한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Sweep : Mark 과정에서 찾은 unreachable 객체를 제거한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Compaction : Sweep 과정 이후 파편화 된 메모리 공간을 압축해서 빈 공간을 없앤다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;Serial GC 설정 방법&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1707372004171&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Java -XX: +UseSerialGC -jar Application.java&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;Parallel GC&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 8까지 Default로 사용된 GC로, Serial GC와 기본적인 GC 알고리즘은 같지만 Minor GC를 멀티 쓰레드로 수행한다는 차이가 있다 (Full 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이다.&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;1920&quot; data-origin-height=&quot;839&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vmelf/btsEDgpwzDD/OhSyqdSdrk7OuxUKOWdUlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vmelf/btsEDgpwzDD/OhSyqdSdrk7OuxUKOWdUlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vmelf/btsEDgpwzDD/OhSyqdSdrk7OuxUKOWdUlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvmelf%2FbtsEDgpwzDD%2FOhSyqdSdrk7OuxUKOWdUlK%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;1920&quot; height=&quot;839&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;839&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;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;Parallel GC 설정 방법&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1707372139548&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;java -XX:+UseParallelGC -jar Application.java

// 사용할 최대 쓰레드 개수를 옵션으로 설정 가능
-XX:ParallelGCThreads=N&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;Parallel Old GC&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Parallel GC의 Old Generation 영역에 새로운 알고리즘이 추가된 업그레이드 버전으로, Old Generation의 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;이 Parallel Old GC는 Old Generation 영역의 Full GC를 Mark-Sweep-Compact가 아닌 멀티 스레드 기반의 Mark-Summary-Compaction 알고리즘을 사용한다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;Mark-Summary-Compaction&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. Mark&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Old Generation 영역을 Region이라는 논리적인 단위로 균일하게 나눈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 여러개의 GC 스레드가 각 Region 영역을 할당 받고,&amp;nbsp;Reachable 객체를 marking 한다&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 이 때, Reachable 객체의 수 / 위치 정보 등의 통계 정보를 계산한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;275&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHFjow/btsEEB1hakM/gxiDPoNoWraB0Nr8s5Y0j0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHFjow/btsEEB1hakM/gxiDPoNoWraB0Nr8s5Y0j0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHFjow/btsEEB1hakM/gxiDPoNoWraB0Nr8s5Y0j0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHFjow%2FbtsEEB1hakM%2FgxiDPoNoWraB0Nr8s5Y0j0%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;2000&quot; height=&quot;275&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;275&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;size18&quot;&gt;&lt;b&gt;2. Summary&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 하나의 스레드만 Summary 단계를 수행하고, 나머지 스레드는 애플리케이션을 수행하는 Concurrent 작업을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Mark 단계에서 수집한 Region 별 통계 정보를 토대로 각 Region의 Reachable 객체의 밀도를 평가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Reachable 객체의 밀도를 토대로 Dense Prefix를 설정해서 GC의 수행 범위를 결정한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; -&amp;gt; Dense Prefix 기준 왼쪽에 있는 Region은 GC 대상에서 제외되고, 오른쪽 영역의 Region에 대해 GC와 Compaction을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; -&amp;gt; 이 방법은 오래된 객체일 수록 사용될 확률이 높다고 가정하고 GC에서 제외시켜서 Compcation 범위를 줄이는 것이다.&amp;nbsp;&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;1916&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SYBjB/btsEBXdfYJZ/ZPkIgSgtGRKyroSBUmqllk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SYBjB/btsEBXdfYJZ/ZPkIgSgtGRKyroSBUmqllk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SYBjB/btsEBXdfYJZ/ZPkIgSgtGRKyroSBUmqllk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSYBjB%2FbtsEBXdfYJZ%2FZPkIgSgtGRKyroSBUmqllk%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;1916&quot; height=&quot;320&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;320&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;size18&quot;&gt;&lt;b&gt;3. Compaction&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 힙을 잠시 멈춰두고 모든 스레드들이 Region을 할당 받아 Compaction 작업을 수행한다. (이 때, Stop-The-World가 발생한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 Compaction 작업은 unreachable 객체들을 제거 하고, 살아남은 객체들을 왼쪽으로 모두 몰아서 메모리를 비우는 작업이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 여기서 살아남은 객체가 옮겨지는 Region을 Destination Region, 옮겨질 객체가 포함된 Region을 Source Region이라고 한다 (이는 Summary 단계에서 Dense Prefix 설정 이후 결정된다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R699P/btsED2Su2tR/qLZ1AeJDVIP57DHvJOMdFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R699P/btsED2Su2tR/qLZ1AeJDVIP57DHvJOMdFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R699P/btsED2Su2tR/qLZ1AeJDVIP57DHvJOMdFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR699P%2FbtsED2Su2tR%2FqLZ1AeJDVIP57DHvJOMdFk%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;1914&quot; height=&quot;362&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;362&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;1916&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2jIh7/btsECuvaIhV/iXN6zbWMOtn66DKHKevR3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2jIh7/btsECuvaIhV/iXN6zbWMOtn66DKHKevR3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2jIh7/btsECuvaIhV/iXN6zbWMOtn66DKHKevR3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2jIh7%2FbtsECuvaIhV%2FiXN6zbWMOtn66DKHKevR3k%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;1916&quot; height=&quot;192&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;192&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;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;Parallel Old GC 설정 방법&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1707379128540&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java -XX:+UseParallelOldGC -jar Application.java
# -XX:ParallelGCThreads=N : 사용할 쓰레드의 갯수&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt; CMS GC&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CMS (Concurrent Mark Sweep) GC는 Parallel GC와 멀티 스레드를 이용한다는 점은 같지만, Mark Sweep 알고리즘을 Concurrent하게 수행한다는 차이가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 과정을 애플리케이션 스레드와 동시에 실행되기 때문에 Stop-The-Wolrd 시간이 매우 짧아서, 애플리케이션 응답 속도가 매우 중요한 경우에 이 CMS GC를 사용한다. (Low Latency 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;다른 GC 방식보다 메모리와 CPU를 더 많이 사용하고, Compation 단계가 기본적으로 제공되지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템  운영되다가 파편화된 메모리가 많아져서 Compaction을 따로 수행해야 한다면 오히려 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;CMS GC는 Java 9 버전부터 deprecated 되었고 14버전부터는 사용이 중지된 GC이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 11 이상을 사용하는 시스템에서는 사용될 일이 없기 때문에 아래의 동작 방식은 참고만 하도록 하자&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;CMS GC 동작 방식&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;337&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oO7ql/btsEClecbzf/GinUGBAbke7ExKgnmlRRMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oO7ql/btsEClecbzf/GinUGBAbke7ExKgnmlRRMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oO7ql/btsEClecbzf/GinUGBAbke7ExKgnmlRRMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoO7ql%2FbtsEClecbzf%2FGinUGBAbke7ExKgnmlRRMK%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;548&quot; height=&quot;337&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;337&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;Initial Mark : 클래스 로더에서 가장 가까운 객체들 중 살아있는 객체만 찾는 과정으로 stop-the-world 시간이 매우 짧다&lt;/li&gt;
&lt;li&gt;Concurrent Mark : Initial Mark 단계에서 찾은 객체에 대해 객체그래프 탐색 하며 참조 정보를 확인한다. 이 단계에서는 애플리케이션 스레드들과 동시에 진행된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Remark : Concurrent Mark 단계에서 애플리케이션에 의해 새로 추가되거나 참조가 끊긴 객체가 있는 지 확인한다.&lt;/li&gt;
&lt;li&gt;Concurrent Sweep : Remark 단계까지를 통해 찾은 unreachable 객체를 제거한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;G1 GC&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;G1&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Garbage-First)&lt;/span&gt; GC는 서버의 CPU와 메모리 사이즈가 커짐에 따라 개선된 GC로, CMS GC를 대체하기 위해 만들어진 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;CMS GC는 Old Generation 영역에 대해서만 동시에 진행하고 Young Generation 영역은 GC를 수행할 때 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;그에 비해 G1 GC는 객체를 마킹하기 위해 GC를 시작하는 순간 외에는 거의 모든 작업을 애플리케이션과 동시에 처리한다는 장점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 기존 GC와는 다르게 힙을 물리적으로 나눠놓지 않고 Region이라는 잘게 나눈 영역으로 관리하기 때문에 작업이 빠르게 진행된다.&lt;/p&gt;
&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;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;G1 GC의 Heap 구조&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 장점에서 말한것과 같이 G1 GC는 기존 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들은 힙 영역을 물리적으로 고정된 Young Generation과 Old Generation으로 나누어 사용했다.&lt;/p&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 GC는 Region이라는 고정된 크기의 논리적인 단위를 새로 도입했고, 힙 영역을 여러개의 Region으로 나누어서 역할을 동적으로 부여한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SlEXz/btsEGSA7fEQ/Xow4b3iMFskxKc4mN9P8iK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SlEXz/btsEGSA7fEQ/Xow4b3iMFskxKc4mN9P8iK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SlEXz/btsEGSA7fEQ/Xow4b3iMFskxKc4mN9P8iK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSlEXz%2FbtsEGSA7fEQ%2FXow4b3iMFskxKc4mN9P8iK%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;700&quot; height=&quot;395&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;395&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;G1 GC의 힙 영역에는 Eden, Survivor, Old 외에 Homonogous와 Available/Unused 라는 영역이 추가되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Homonogous 는 Region 크기의 50%를 초과하는 객체를 저장하는 영역이고, Available/Unused 는 사용되고 있지 않은 영역을 의미한다.&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 GC의 핵심은 이러한 &lt;u&gt;Region 중에 Garbage의 비중이 높은 Region 순으로 GC를 수행&lt;/u&gt;해서 Full GC가 최대한 발생하지 않게 하는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;G1 GC 동작 방식&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;G1 GC도 다른 GC와 마찬가지로 MinorGC와 MajorGC를 나누어서 수행한다.&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;size18&quot;&gt;&lt;b&gt;1. Minor GC (Young GC)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티 스레드로 Minor GC를 수행하고, Stop-The-World가 발생한다.&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/doWIyy/btsEEI7C8pm/M8e1rhfz0jKhMvwUy8MiRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doWIyy/btsEEI7C8pm/M8e1rhfz0jKhMvwUy8MiRK/img.png&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;724&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.3837%; margin-right: 10px;&quot; data-widthpercent=&quot;48.95&quot; id=&quot;kEditorPhotosEditingImage-16&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doWIyy/btsEEI7C8pm/M8e1rhfz0jKhMvwUy8MiRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoWIyy%2FbtsEEI7C8pm%2FM8e1rhfz0jKhMvwUy8MiRK%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;1004&quot; height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lkmOV/btsEE3wU2QJ/hQAoxwZf6W6svVoJ5RMeb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lkmOV/btsEE3wU2QJ/hQAoxwZf6W6svVoJ5RMeb0/img.png&quot; data-origin-width=&quot;992&quot; data-origin-height=&quot;686&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.4535%;&quot; data-widthpercent=&quot;51.05&quot; id=&quot;kEditorPhotosEditingImage-17&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lkmOV/btsEE3wU2QJ/hQAoxwZf6W6svVoJ5RMeb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlkmOV%2FbtsEE3wU2QJ%2FhQAoxwZf6W6svVoJ5RMeb0%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;992&quot; height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;/div&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;Young Generation Region의 객체가 기준치를 초과하면 Mark-Sweep을 수행하고, 살아남은 객체는 다른 Region으로 옮긴다.&lt;/li&gt;
&lt;li&gt;만약 Available/Unused 영역에 옮겨지면 해당 Region은 Young Generation 영역이 되고, 객체가 옮겨지기 전의 영역은 Available/Unused 영역이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. Major GC&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k659s/btsEExFmCqO/VtJ68VRkJ3f65ITDXgPpcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k659s/btsEExFmCqO/VtJ68VRkJ3f65ITDXgPpcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k659s/btsEExFmCqO/VtJ68VRkJ3f65ITDXgPpcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk659s%2FbtsEExFmCqO%2FVtJ68VRkJ3f65ITDXgPpcK%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;1004&quot; height=&quot;250&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;250&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;Initial Mark : Old Region 객체가 참조하고 있는 Survivor Region이 있는지 마킹한다. (Stop-The-World 발생)&lt;/li&gt;
&lt;li&gt;Root Region Scan : Initial Mark에서 찾은 Survivor Region에서 GC 대상 객체를 찾는다. (멀티 스레드로 동작함)&lt;/li&gt;
&lt;li&gt;Concurrent Mark : Heap 내의 Old Region에서 생존해 있는 모든 객체들에 대해 Marking 과정을 진행한다. 애플리케이션과 동시에 동작하고 MinorGC와 같이 진행된다.&lt;/li&gt;
&lt;li&gt;Remark : 애플리케이션을 멈추고 Concurrent Mark 에서 체크한 객체들 중 Unreachable 객체를 식별해낸다. (Stop-The-World 발생)&lt;/li&gt;
&lt;li&gt;Cleanup &amp;amp; Copy : 애플리케이션을 멈추고  Unreachable 객체가 많은 Region 순으로 순차적으로 Garbage를 제거해 나간다. 이 때 우선 Reachable 객체를 먼저 다른 Region으로 옮겨놓고 이후에 Garbage를 제거해서 여유 공간을 확보한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;G1 GC 설정 방법&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1707402052220&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java -XX:+UseG1GC -jar Application.java&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;size18&quot;&gt;&lt;b&gt;참고&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://s2choco.tistory.com/14&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://s2choco.tistory.com/14&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://coding-factory.tistory.com/829&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://coding-factory.tistory.com/829&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://d2.naver.com/helloworld/329631&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://d2.naver.com/helloworld/329631&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://d2.naver.com/helloworld/1329&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://d2.naver.com/helloworld/1329&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Java</category>
      <author>iwannarest</author>
      <guid isPermaLink="true">https://jonghne.tistory.com/106</guid>
      <comments>https://jonghne.tistory.com/106#entry106comment</comments>
      <pubDate>Thu, 8 Feb 2024 23:05:13 +0900</pubDate>
    </item>
    <item>
      <title>hELLO 스킨 다크모드 시 글씨 색깔 바뀌는 버그 해결 방법</title>
      <link>https://jonghne.tistory.com/105</link>
      <description>&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; 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;개요&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;평소 기술 블로그를 작성하면서 정상우님이 만드신&amp;nbsp;&lt;a href=&quot;https://pronist.tistory.com/5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;hELLO 스킨&lt;/a&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: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이 부분을 해결하려고 정상우님이 운영중인 &lt;a href=&quot;https://github.com/tidory/hello/discussions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Github Discussions&lt;/a&gt;를 찾아보니 버그가 아니라 &lt;u&gt;스킨 버그가 아니라 사용자의 자유도를 침해하지 않기 위해 결정한 정책&lt;/u&gt;이라고 한다.&lt;/span&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;774&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIsmYg/btsEtkLR4MV/LFcBgQZ2VDu1r6JcbisER1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIsmYg/btsEtkLR4MV/LFcBgQZ2VDu1r6JcbisER1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIsmYg/btsEtkLR4MV/LFcBgQZ2VDu1r6JcbisER1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIsmYg%2FbtsEtkLR4MV%2FLFcBgQZ2VDu1r6JcbisER1%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;774&quot; height=&quot;342&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;342&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;그래서 어쩔수 없이 기존 작성한 글의 깨지는 폰트를 HTML 수정을 통해 직접 하나하나 수정해주고 있었는데 , 너무 노가다 성 작업이라 고통스러워서 다른 스킨을 찾아보려 하고 있었다...&lt;/p&gt;
&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;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; 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;해결 방법&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;1. 복사/붙여넣기 시 생성되는&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&amp;nbsp;span 태그를 삭제해주는 CSS 작성&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블로그 관리 -&amp;gt; 스킨 편집 -&amp;gt; HTML 편집 -&amp;gt; CSS 탭의 가장 상단에 아래 코드 작성&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1105&quot; data-origin-height=&quot;977&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cV6iCg/btsEm9LD7gX/gCWKWwCX52WcaGpOo26eL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cV6iCg/btsEm9LD7gX/gCWKWwCX52WcaGpOo26eL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cV6iCg/btsEm9LD7gX/gCWKWwCX52WcaGpOo26eL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcV6iCg%2FbtsEm9LD7gX%2FgCWKWwCX52WcaGpOo26eL0%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;1105&quot; height=&quot;977&quot; data-origin-width=&quot;1105&quot; data-origin-height=&quot;977&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1707114658598&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.dark span[style*=&quot;color: #333333; text-align: start;&quot;],
.dark span[style*=&quot;color: #000000; text-align: start;&quot;],
.dark span[style*=&quot;color: #333333;&quot;],
.dark span[style*=&quot;color: #000000;&quot;],
.dark span[style*=&quot;background-color: #ffffff;&quot;],
.dark h1[style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;],
.dark h1[style*=&quot;color: #000000; text-align: start;&quot;],
.dark h2[style*=&quot;color: #000000; text-align: left;&quot;],
.dark h2[style*=&quot;color: #000000; text-align: start;&quot;],
.dark h2[style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;],
.dark h3[style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;],
.dark h3[style*=&quot;color: #000000;&quot;][style*=&quot;text-align: left;&quot;],
.dark h3[style*=&quot;color: #000000;&quot;][style*=&quot;text-align: start;&quot;],
.dark h3[style*=&quot;color: #333333;&quot;][style*=&quot;text-align: start;&quot;],
.dark h4[style*=&quot;color: #333333;&quot;][style*=&quot;text-align: start;&quot;],
.dark h4[style*=&quot;color: #000000;&quot;][style*=&quot;text-align: start;&quot;],
.dark ol[style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot;],
.dark ul[style=&quot;list-style-type: disc; background-color: #ffffff; color: #212529; text-align: start;&quot;],
.dark ul[style=&quot;list-style-type: disc; background-color: #ffffff; color: #000000; text-align: start;&quot;][data-ke-list-type=&quot;disc&quot;],
.dark li[style=&quot;list-style-type: decimal; color: #666666;&quot;],
.dark li[style=&quot;list-style-type: disc; color: #666666;&quot;],
.dark p[style=&quot;color: #333333; text-align: start;&quot;],
.dark p[style=&quot;color: #000000; text-align: start;&quot;],
.dark p[style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;]{
    background-color: rgb(30, 31, 33) !important;
    color:  #fff  !important;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;2.&lt;span&gt;&amp;nbsp;특정 Span 태그 아에 삭제하기&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번 방법 만으로는 완벽하게 버그를 해결할 수 없다고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 HTML 탭의 script를 추가해주자&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;985&quot; data-origin-height=&quot;981&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOik9e/btsEnQyhVVe/JPNGtHuEPFb7SWDYAnxTK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOik9e/btsEnQyhVVe/JPNGtHuEPFb7SWDYAnxTK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOik9e/btsEnQyhVVe/JPNGtHuEPFb7SWDYAnxTK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOik9e%2FbtsEnQyhVVe%2FJPNGtHuEPFb7SWDYAnxTK1%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;985&quot; height=&quot;981&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;981&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;pre id=&quot;code_1707115052515&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
        // span 없애는 함수
        function removeSpanTags(htmlString) {
            var regex = /&amp;lt;span\s+style\s*=\s*['&quot;]color:\s*#333333;\s*text-align:\s*start;\s*['&quot;]\s*&amp;gt;(.*?)&amp;lt;\/span&amp;gt;/g;
            var result = htmlString.replace(regex, '$1');
            console.log(result);
            return result;
          }
        var spanElements = document.querySelectorAll('span[style=&quot;color: #333333; text-align: start;&quot;]');  
        spanElements.forEach(function(spanElement) {
            var htmlString = spanElement.outerHTML;
            var result = removeSpanTags(htmlString);
            console.log(htmlString);
            spanElement.outerHTML = result;
          });   
        
        function removeDataKeSizeFromPTags(htmlString) {
            var regex = /&amp;lt;p\s+data-ke-size\s*=\s*['&quot;]size16['&quot;]\s*(.*?)&amp;lt;\/p&amp;gt;/g;
            var result = htmlString.replace(regex, '&amp;lt;p $1&amp;lt;/p&amp;gt;');
            // console.log(result);
            return result;
        }
 
        var pElements = document.querySelectorAll('p[data-ke-size=&quot;size16&quot;]');
        pElements.forEach(function(pElement) {
            var htmlString = pElement.outerHTML;
            var result = removeDataKeSizeFromPTags(htmlString);
            // console.log(htmlString);
            pElement.outerHTML = result;
        });
      });
&amp;lt;/script&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;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;출처 : https://changsroad.tistory.com/418&lt;/blockquote&gt;</description>
      <category>ETC</category>
      <author>iwannarest</author>
      <guid isPermaLink="true">https://jonghne.tistory.com/105</guid>
      <comments>https://jonghne.tistory.com/105#entry105comment</comments>
      <pubDate>Mon, 5 Feb 2024 15:38:00 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Optional의 개념 및 주요 메서드</title>
      <link>https://jonghne.tistory.com/104</link>
      <description>&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt; NullPointException&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;자바 애플리케이션에서 흔히 발생하는 오류로 NulPointerException(이하 NPE) 이 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;NPE 에러가 발생하는 이유는 보통 객체 참조 값이 Null인 상태에서 메서드나 필드에 접근하려고 할 때 발생하게 되는데, 런타임에 발생하는 에러이기 때문에 조심해서 처리해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1705923670617&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str = null;
int length = str.length(); // NullPointerException 에러 발생 !!
System.out.println(&quot;문자열 길이 : &quot; + length);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;NPE는 JDK 8 이전에는 Null 값을 메서드 내에서 예외 처리하거나 또는 Null값을 리턴한 다음 클라이언트 코드에서 Null 체크를 하는 식으로 처리해왔는데 이 방법들은 모두 몇가지 문제가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. Null값 예외 처리 시 문제점&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;div style=&quot;border: 5px solid #BDCEFF; border-radius: 0px 0px; padding: 15px 30px; margin: 0;&quot;&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; top: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CallStack 탐색 비용이 발생한다.&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;text-align: left;&quot;&gt;- 예외 발생 시 JVM은 Exception Handler를 찾기 위한 CallStack 탐색하게 되는데 이 과정에서 클래스명, 메서드명, 코드 줄번호 등의 정보를 수집하게 되어서 Stack Depth가 깊어질수록 비용이 많이 발생하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&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;b&gt;&lt;span style=&quot;text-align: left;&quot;&gt;비정상적인 Thread 종료가 발생할 수 있다.&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;text-align: left;&quot;&gt;- JVM은 Call Stack에서 예외 처리를 할 수 있는 Handler를 발견하지 못한다면 Default Exception Handler에게 예외 객체를 전달하고, 이 handler는 예외 정보를 출력하면서 해당 Thread를 비정상적으로 종료시키게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; bottom: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. Null값을 리턴하고 클라이언트 코드에서 관리할 때의 문제점&lt;/b&gt;&lt;/h4&gt;
&lt;div style=&quot;border: 5px solid #BDCEFF; border-radius: 0px 0px; padding: 15px 30px; margin: 0;&quot;&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; top: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&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;- Null이 발생할 수 있는 지 클라이언트 코드에서 판단하고 if(Obj != null) 와 같이 Null 체크를 해야하기 때문에 코드가 지저분해지고, 개발자가 실수로 Null 체크를 하지 않는다면 런타임 중 에러가 발생할 수 있다.&lt;/p&gt;
&lt;div style=&quot;width: 90%; height: 12px; display: block; position: relative; bottom: -26px; margin: 0 auto;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;JDK 8 버전에서 이러한 문제를 해결하기 위해, Null이 될 수 있는 객체나 값을 Optional이라는 일종의 컨테이너 안으로 감싸서 안전하게 다룰 수 있게 도와주는 Optional API를 제공하기 시작했다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Java Optional&amp;lt;T&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Java 8 버전부터 Null을 안전하고 깔끔하게 처리할 수 있는 Optional 클래스가 추가되었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1758&quot; data-origin-height=&quot;926&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/43tKM/btsDQ6gcUPw/c8BNbAqJk3IJWIDKmxcFT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/43tKM/btsDQ6gcUPw/c8BNbAqJk3IJWIDKmxcFT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/43tKM/btsDQ6gcUPw/c8BNbAqJk3IJWIDKmxcFT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F43tKM%2FbtsDQ6gcUPw%2Fc8BNbAqJk3IJWIDKmxcFT1%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;1758&quot; height=&quot;926&quot; data-origin-width=&quot;1758&quot; data-origin-height=&quot;926&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Optinal은&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; Null일 수 있는 객체나 값을 감싸주는 래퍼(Wrapper) 클래스&lt;/span&gt;&lt;/b&gt;로, Optional 안의 value 값은 제네릭 타입의 Null일 수도 있는 하나의 값이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1609231340191.png&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/emiEBQ/btsDQ6tOZh2/nz42ExNxuQorIlMRuTknLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/emiEBQ/btsDQ6tOZh2/nz42ExNxuQorIlMRuTknLK/img.png&quot; data-alt=&quot;https://www.linkedin.com/pulse/introduction-java-8-optional-aneshka-goyal/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/emiEBQ/btsDQ6tOZh2/nz42ExNxuQorIlMRuTknLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FemiEBQ%2FbtsDQ6tOZh2%2Fnz42ExNxuQorIlMRuTknLK%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;1120&quot; height=&quot;534&quot; data-filename=&quot;1609231340191.png&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.linkedin.com/pulse/introduction-java-8-optional-aneshka-goyal/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Optional 클래스는 value 값을 다양한 메서드를 통해 접근하도록 하고, 이로 인해 NPE가 발생될 여지를 줄여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;주요 메서드로는 Optional 객체 생성 메서드, 비어있는지 확인하는 메서드, 값을 꺼내는 메서드, 중간 연산 메서드가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;Optional 객체 생성&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;ofNullable()&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Optional.ofNullable()은 Null을 허용하는 Optional 객체를 생성하는 메서드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705929745040&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 id;
    private String name;
    private Address address;
    
    public Optional&amp;lt;String&amp;gt; getAddress() {
    	return Optional.ofNullable(this.address);
    }   
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;of()&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Optional.of() 는 Optional.ofNullable()와 다르게 Null을 허용하지 않는다는 특징이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;만약 Null값을 인자로 넣게 된다면 NPE 에러가 발생하게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1705930058763&quot; class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class User {
    private int id;
    private String name;
    private Address address;
    
    public Optional&amp;lt;Address&amp;gt; getAddress() {
    	return Optional.of(this.address);
    }   
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1705930117813&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;User user = new User();
user.setId(1);
user.setName(&quot;jh&quot;);

Optional&amp;lt;Address&amp;gt; addressOpt = user.getAddress(); // NPE 발생 !!

java.lang.NullPointerException
	at java.base/java.util.Objects.requireNonNull(Objects.java:208)
	at java.base/java.util.Optional.of(Optional.java:113)
    ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;Optional 값 가져오기&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;get()&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;get() 메서드는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Optional에 있는 값을 바로 가져오는 메서드인데, 가져올 때 Null이 아닐 것이라고 가정하기 때문에 만약 Null인 경우 NPE가 발생하게 된다.&amp;nbsp;&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;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;그래서 직접 get()으로 Optional 값에 접근하는 것은 지양해야 한다.&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1705971294827&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Address address = addressOpt.get();&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;isPresent() , isEmpty()&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;isPresent() 메서드는 값이 Null이 아니면 true를 Null이면 false를 리턴하고, isEmpty()는 반대로 Null이면 true를 아니면 false를 리턴하는 메서드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;해당 메서드 는 조건문과 get()메서드를 같이 사용하기 때문에, 값을 꺼내는 용도라면 orElseGet() 메서드가 권장되고 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1705931193928&quot; class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;if(addressOpt.isPresent()) {
    Address address = addressOpt.get();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;ifPresent(Consumer)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;값이 Null이 아닌 경우에는 인자값으로 전달한 Consumer 함수형 인터페이스 타입의 함수를 실행하고, Null인 경우에는 무시하는 메서드이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1705931444216&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;addressOpt.ifPresent((address)-&amp;gt; System.out.println(address.getAddressNo()));&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;orElse(T)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;orElse(T) 메서드는  Optional에 값이 있으면 해당 값을 할당하고, 없다면 인자값으로 전달한 대체 값을 리턴하는 메서드이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아래 예시에서 replacedAddress는 전달한 id가 1이고, 주소가 111-111인 Address를 참조하게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1705931930365&quot; class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;Address replacedAddress = addressOpt.orElse(new Address(1, &quot;111-111&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;orElseGet(Supplier)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;orElseGet() 메서드는 값이 있다면 할당하고, 없다면 Supplier 타입의 함수를 통해 생성된 객체를 리턴하게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1705932122756&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Address replacedAddress = addressOpt.orElseGet(() -&amp;gt; new Address(1, &quot;111&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;orElse()와 거의 비슷하지만 orElseGet() 메서드는 Optional 객체에 값이 있다면 인자값으로 전달한 함수는 무시하고, orElse() 메서드는 Optional 객체에 값이 있더라도 인자값의 함수가 실행된다는 차이가 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;즉 아래와 같이 Optional 안에 실제 Address 객체가 존재할 때, replacedAddress 에는 Optional 객체 안의 값을 할당하지만 Address 객체 생성하는 함수 또한 같이 실행된다. (특별한 이유가 없다면 orElseGet을 사용하는게 좋다)&lt;/p&gt;
&lt;pre id=&quot;code_1705932456144&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Optional&amp;lt;Address&amp;gt; addressOpt = Optional.ofNullable(new Address(2,&quot;222-222&quot;));
Address replacedAddress = addressOpt.orElse(new Address(1, &quot;111-111&quot;));

System.out.println(replacedAddress.getAddressId()); // 2를 출력한다&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;orElseThrow()&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Optional에 값이 있으면 가져오고 없다면 에러를 던지는 메서드이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;인자값에 Supplier 함수로 예외를 지정하지 않는다면 NoSuchElementException 에러가 발생하고, 예외를 지정한 경우 해당 에러가 발생한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;orElseThrow()&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1705933073886&quot; class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;Address address = addressOpt.orElseThrow(); // 예외 발생 !!

java.util.NoSuchElementException: No value present
	at java.base/java.util.Optional.orElseThrow(Optional.java:377)
    ...&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;orElseThrow(Supplier)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1705933117400&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Address address = addressOpt.orElseThrow(IllegalStateException::new); // 예외 발생 !!

java.lang.IllegalStateException
	at java.base/java.util.Optional.orElseThrow(Optional.java:403)
    ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;Optional 중간 연산&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Optional에도 StreamAPI와 같이 중간 연산을 수행하는 메서드가 존재한다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt; filter(Predicate)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Optional에 들어있는 값을 Predicate 함수의 조건으로 걸러내는 기능을 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아래의 예시는 filter의 인자값으로 Predicate 타입의 람다식 함수를 전달해서, value값에 특정 문자열이 포함되어있지 않으면 빈 값을 반환하게 하는 코드이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1705933613257&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String value = &quot;Java8 Optional&quot;;

Optional&amp;lt;String&amp;gt; optionalVal = Optional.ofNullable(value);

Optional&amp;lt;String&amp;gt; filterdA = optionalVal.filter(s -&amp;gt; s.contains(&quot;Java&quot;));
System.out.println(filterdA.isPresent()); // true

Optional&amp;lt;String&amp;gt; filterdB = optionalVal.filter(s -&amp;gt; s.contains(&quot;Spring&quot;));
System.out.println(filterdB.isPresent()); // false&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt; map(Function)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;map(Function) 메서드는 Optional 안에 들어있는 값을 Function 조건을 통해 새로운 값으로 변환하는 메서드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1705934001921&quot; class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;Optional&amp;lt;String&amp;gt; optionalVal = Optional.ofNullable(&quot;Java8 Optional&quot;);

Optional&amp;lt;Integer&amp;gt; strLength = optionalVal.map((s) -&amp;gt; s.length()); // s의 길이를 담은 Optional 객체로 변환&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;flatMap(Function)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;flatMap(Function)은 Optional의 값이 Optional&amp;lt;Optional&amp;lt;T&amp;gt;&amp;gt;와 같이 두겹으로 쌓여 있는 경우, Optional&amp;lt;T&amp;gt;로 차원을 줄여서 반환하는 메서드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아래와 같이 User 타입의 객체가 들어가 있는 Optional 객체를 map()을 통해 Address로 변환하면, getAddress 메서드가 Optional 타입을 리턴하기 때문에 Optional&amp;lt;Optional&amp;lt;T&amp;gt;&amp;gt; 형태가 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1705934851031&quot; class=&quot;routeros&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class User {
    private int id;
    private String name;
    private Address address;
    
    public Optional&amp;lt;Address&amp;gt; getAddress() {
    	return Optional.of(this.address);
    }   
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1705934803469&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Optional&amp;lt;User&amp;gt; user = Optional.ofNullable(new User(1, &quot;name&quot;, new Address(1,&quot;address&quot;)));

Optional&amp;lt;Optional&amp;lt;Address&amp;gt;&amp;gt; address = user.map(User::getAddress);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이렇게 map 메서드의 리턴 타입 자체가 Optional 인 경우, 아래와 같이 flatMap(Function) 메서드를 사용하면 Optional을 감싸지 않고 값을 리턴할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1705935031196&quot; class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;Optional&amp;lt;User&amp;gt; user = Optional.ofNullable(new User(1, &quot;name&quot;, new Address(1,&quot;address&quot;)));

Optional&amp;lt;Address&amp;gt; address = user.flatMap(User::getAddress);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Optional 사용 시 주의사항&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;1. Optional은 리턴 타입으로만 사용하자&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Optional은 리턴 타입, 매개 변수 타입, Map의 키 값 등 여러 곳에서 사용할 수 있지만, Effective Java에서는 다음과 같은 이유로 리턴 타입으로만 사용하기를 권장하고 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;- 매개변수 타입으로 사용하는 경우 매개변수에 Null을 넘겨줄수 있어서 NPE 이 발생할 수 있다.&lt;br /&gt;- Map의 키 값으로 사용하는 경우에는 Map 인터페이스는 Key가 Null일 수 없다는 특징을 깨뜨리게 된다.&amp;nbsp;&lt;br /&gt;- 인스턴스의 필드 타입으로 사용하는 경우, 필드의 값이 있을 수도 없을수도 있다는 것은 클래스 설계가 잘못된 것이다.&lt;br /&gt;- 등등..&amp;nbsp;&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;2. Primitive Type 값인 경우 Optional 대신 OptionalInt와 같은 클래스 사용&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Optional 클래스는 Primitive Type 값을 Boxing / Un-Boxing 할 때, Optional에서 꺼냈다가 다시 감싸는 과정이 추가되어서 성능상 좋지 않다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아래와 같은 Primitive Type을 위한 Optional 클래스를 사용하자&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;984&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2RZ0n/btsDQUmDiQR/PnRtvxrqKSHEUesAjckMhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2RZ0n/btsDQUmDiQR/PnRtvxrqKSHEUesAjckMhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2RZ0n/btsDQUmDiQR/PnRtvxrqKSHEUesAjckMhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2RZ0n%2FbtsDQUmDiQR%2FPnRtvxrqKSHEUesAjckMhk%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;984&quot; height=&quot;262&quot; data-origin-width=&quot;984&quot; data-origin-height=&quot;262&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0 0 0 0.2em; font-weight: bold;&quot;&gt;3. 자체적으로 Null 체크를 할 수 있는 컨테이너 타입의 인스턴스는 Optional로 감싸지 말자&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Collection, Map, Stream, Optional과 같은 클래스 / 인터페이스는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;내부에 값이 비어있는지 파악할 수 있는 메서드가 제공되기 때문에 &lt;/span&gt;Optional을 사용하는 것이 불필요하고, 오히려 값을 두번 감싸는 행위가 되기 때문에 지양하는 것이 좋다.&lt;/p&gt;</description>
      <category>Study/Java</category>
      <author>iwannarest</author>
      <guid isPermaLink="true">https://jonghne.tistory.com/104</guid>
      <comments>https://jonghne.tistory.com/104#entry104comment</comments>
      <pubDate>Tue, 23 Jan 2024 00:15:49 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Collection Framework 의 개념과 Collection 종류</title>
      <link>https://jonghne.tistory.com/103</link>
      <description>&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; 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;Collection Framework란 ?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;컬렉션 프레임워크(Collection Framework) 란 다양한 컬렉션(데이터의 집합)을 다루기 쉽게 클래스/인터페이스로 표준화 한 것을 말한다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;컬렉션을 다루는 다양한 클래스를 정의해놓아서 사용자는 데이터를 다루는 기능을 별도로 구현할 필요가 없고,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;다형성이 보장되어 있어서 구현체가 변경되어도 기존 기능을 문제 없이 사용할 수 있다 (ex) ArrayList -&amp;gt; LinkedList)&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;컬렉션 프레임워크의 대표적인 인터페이스로는 List, Set, Map, Queue가 있고 각각을 구현하는 여려 클래스가 존재한다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;List, Set, Queue는 공통 기능을 추출한 Collection 인터페이스를 상속하고 있지만, Map은 구조적 특성으로 인해 독립적으로 정의되어 있다.&amp;nbsp;&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;822&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdGcjg/btsDA2Z7MBV/5ZT1xdRGTmhzu64REXil9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdGcjg/btsDA2Z7MBV/5ZT1xdRGTmhzu64REXil9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdGcjg/btsDA2Z7MBV/5ZT1xdRGTmhzu64REXil9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdGcjg%2FbtsDA2Z7MBV%2F5ZT1xdRGTmhzu64REXil9K%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;822&quot; height=&quot;576&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; 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;List 인터페이스&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;List 인터페이스는 저장되는 객체들의 &lt;u&gt;&lt;b&gt;순서를 보장하고 중복을 허용&lt;/b&gt;&lt;/u&gt;한다는 특징이 있다.(ex) 대기자 명단)&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;구현 클래스로는 ArrayList, LinkedList, Stack, Vector 가 있고 인터페이스의 주요 메서드는 다음과 같다.&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;990&quot; data-origin-height=&quot;738&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BzbOE/btsDDbhFk7T/K4GO2yEkDuIYI1c0qVc2JK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BzbOE/btsDDbhFk7T/K4GO2yEkDuIYI1c0qVc2JK/img.png&quot; data-alt=&quot;https://velog.io/@oyeon/11-36-Collection-List-Set-Map-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BzbOE/btsDDbhFk7T/K4GO2yEkDuIYI1c0qVc2JK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBzbOE%2FbtsDDbhFk7T%2FK4GO2yEkDuIYI1c0qVc2JK%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;990&quot; height=&quot;738&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://velog.io/@oyeon/11-36-Collection-List-Set-Map-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ArrayList&amp;lt;E&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;285&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GQhB1/btsDAtQ8byp/AEAiB2zk0x8MSnkgf3WyFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GQhB1/btsDAtQ8byp/AEAiB2zk0x8MSnkgf3WyFK/img.png&quot; data-alt=&quot;https://chunsubyeong.tistory.com/81&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GQhB1/btsDAtQ8byp/AEAiB2zk0x8MSnkgf3WyFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGQhB1%2FbtsDAtQ8byp%2FAEAiB2zk0x8MSnkgf3WyFK%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;670&quot; height=&quot;285&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;285&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://chunsubyeong.tistory.com/81&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ArrayList는 List 인터페이스의 대표적인 구현 클래스로, 배열에 다양한 타입의 객체를 저장하고 관리할 수 있는 기능을 제공한다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;단방향 포인터 구조로 각 데이터의 인덱스를 가지고 있어서 조회 성능이 뛰어나다는 장점을 가지고 있다.&amp;nbsp;&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;하지만 메모리에 &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;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그리고 ArrayList는 멀티 스레드 환경에서 Thread-Safe하지 않아서 주의해야 한다는 특징이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;LinkedList&amp;lt;E&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;LinkedList는 메모리 주소값 참조를 통해 데이터를 연결하는 이중 연결 리스트(Doubly Linked List) 구조의 클래스이다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;각 노드(Node) 객체 내에 이전 노드(Node)와 다음 노드(Node)의 참조 값을 가지고 있다.&amp;nbsp;&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;805&quot; data-origin-height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/leanl/btsDC5Wh7JN/53kBb50BqBXimkuyFYlR5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/leanl/btsDC5Wh7JN/53kBb50BqBXimkuyFYlR5k/img.png&quot; data-alt=&quot;https://velog.io/@sweet_sumin/LinkedHashMap-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EC%82%B4%ED%8E%B4%EB%B4%A4%EC%96%B4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/leanl/btsDC5Wh7JN/53kBb50BqBXimkuyFYlR5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fleanl%2FbtsDC5Wh7JN%2F53kBb50BqBXimkuyFYlR5k%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;805&quot; height=&quot;327&quot; data-origin-width=&quot;805&quot; data-origin-height=&quot;327&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://velog.io/@sweet_sumin/LinkedHashMap-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EC%82%B4%ED%8E%B4%EB%B4%A4%EC%96%B4&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1046&quot; data-origin-height=&quot;1074&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Mlezw/btsDARdgAFs/Q7d5AMJRBOb87IsKK3OK21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Mlezw/btsDARdgAFs/Q7d5AMJRBOb87IsKK3OK21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Mlezw/btsDARdgAFs/Q7d5AMJRBOb87IsKK3OK21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMlezw%2FbtsDARdgAFs%2FQ7d5AMJRBOb87IsKK3OK21%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;1046&quot; height=&quot;1074&quot; data-origin-width=&quot;1046&quot; data-origin-height=&quot;1074&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&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: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;LinkedList는 데이터를 추가 / 삭제 시 인접한 두개의 노드의 참조값만 변경하면 되기 때문에 ArrayList에 비해 데이터의 추가 / 삭제가 빠르다는 장점이 있다.&amp;nbsp;&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;다만, ArrayList에 비해 각 데이터가 메모리상에 불연속적으로 저장되어 있기 때문에 조회가 느리다는 단점이 있다.&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;span style=&quot;border-bottom: 8px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ArrayList와 LinkedList 비교&lt;/span&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 53px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;컬렉션 종류&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;읽기(접근시간)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;추가/삭제&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;비고&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ArrayList&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;빠르다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;느리다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;순차적인 추가/삭제는 LinkedList 보다 더 빠르다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;LinkedList&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;느리다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;빠르다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&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;&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;요약하자면 ArrayList는 조회 속도가 빠르고 LinkedList는 추가/삭제 속도가 상대적으로 빠르다.&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: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;순차적인 추가 및 삭제 : ArrayList가 LinkedList보다 조금 빠름&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;중간 위치에 추가/삭제 : ArrayList보다 LinkedList가 훨씬 빠름&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;요소에 대한 접근시간 : ArrayList가 LinkedList보다 훨씬 빠름 &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;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Vector&amp;lt;E&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Vector 클래스는 기본적으로 ArrayList와 동일한 자료 구조 및 기능을 가지고 있다. &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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ArrayList와 유일하게 다른 부분은 Synchronized 메서드를 사용해서 Thread-Safe하다는 점인데, 싱글 스레드인 경우에도 동기화를 위한 작업이 추가로 수행되기 때문에 ArrayList보다 성능이 조금 떨어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Stack&amp;lt;E&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Vector 클래스를 상속받은 컬렉션 클래스로 전형적인 Stack 기능을 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;한 방향으로만 저장(Push) 과 추출(Pop)을 할 수 있는 LIFO(Last-In-First-Out) 구조를 가진다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Stack 클래스는 Vector 클래스와 마찬가지로 Thread-Safe 하지만 느리다는 단점이 있다.&amp;nbsp;&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;814&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUMyfV/btsDDVTlABG/YfsaZuRcemwmV9ClTfkkW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUMyfV/btsDDVTlABG/YfsaZuRcemwmV9ClTfkkW1/img.png&quot; data-alt=&quot;https://beenii.tistory.com/161&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUMyfV/btsDDVTlABG/YfsaZuRcemwmV9ClTfkkW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUMyfV%2FbtsDDVTlABG%2FYfsaZuRcemwmV9ClTfkkW1%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;814&quot; height=&quot;482&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://beenii.tistory.com/161&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; 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;Set 인터페이스&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Set 인터페이스는 저장되는 객체들의&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;u&gt;순서를 보장하지 않고 중복을 허용하지 않는다&lt;/u&gt;&lt;/b&gt;는 특징이 있다.(ex) 양의 정수 집합)&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;대표적인 구현 클래스로는 HashSet, TreeSet, LinkedHashSet이 있고 주요 메서드는 다음과 같다.&lt;/span&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;2303&quot; data-origin-height=&quot;1181&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNBn8k/btsDAqfVx5e/B9KPVaD8DPHnWvHGaHB2c0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNBn8k/btsDAqfVx5e/B9KPVaD8DPHnWvHGaHB2c0/img.png&quot; data-alt=&quot;https://st-lab.tistory.com/238&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNBn8k/btsDAqfVx5e/B9KPVaD8DPHnWvHGaHB2c0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNBn8k%2FbtsDAqfVx5e%2FB9KPVaD8DPHnWvHGaHB2c0%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;2303&quot; height=&quot;1181&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2303&quot; data-origin-height=&quot;1181&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://st-lab.tistory.com/238&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 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;HashSet&amp;lt;E&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;HashSet은 Set 인터페이스를 구현한 대표적인 클래스로 순서를 보장하지 않고, 데이터 중복을 허용하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;만약 데이터 순서를 유지하고 싶다면 LinkedHashSet을 사용해야 한다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;HashSet은 HashMap을 사용되어 구현되어 있고, 데이터 추가/삭제 시 중복 체크 과정을 수행해서 List 보다 느리다. (중복 체크 시 equals()와 hashCode()를 사용함)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;TreeSet&amp;lt;E&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;TreeSet은 HashSet과 동일하게 순서를 보장하지 않고, 동일한 객체를 중복해서 저장할 수 없는 클래스이다.&amp;nbsp;&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;HashSet과 다른점으로는 이진 탐색 트리 (Binary Search Tree) 구조로 되어 있어서, 데이터 추가/삭제 성능은 조금 더 안좋지만 정렬 및 검색에는 높은 성능을 보인다.&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;500&quot; data-origin-height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p08fq/btsDyCBwbSw/PJkHAbaYpB9h7YKeKoTYv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p08fq/btsDyCBwbSw/PJkHAbaYpB9h7YKeKoTYv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p08fq/btsDyCBwbSw/PJkHAbaYpB9h7YKeKoTYv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp08fq%2FbtsDyCBwbSw%2FPJkHAbaYpB9h7YKeKoTYv0%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;500&quot; height=&quot;241&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;241&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;TreeSet은 이진 탐색 트리 중에서도 성능을 향상 시킨 레드-블랙 트리(Red-Black Tree)로 구현되어 있다.&amp;nbsp;&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;size18&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;size18&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; 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;Queue 인터페이스&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Queue 인터페이스는 데이터를 일시적으로 쌓아두기 위한 자료 구조로  일반적인 Queue를 구현하기 위해 사용된다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Stack 컬렉션과 다르게 FIFO(First-In-First-Out) 형태를 가지고, 양방향으로 데이터를 저장(Enqueue)하고 추출( Dequeue)할 수 있는 구조이다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Queue를 구현하는 클래스는 PriorityQueue가 있고 주요 메서드는 다음과 같다&amp;nbsp;&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;742&quot; data-origin-height=&quot;510&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bS9OMH/btsDBOOgWkX/2WJE0S8s7wYir0kvkuK7K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bS9OMH/btsDBOOgWkX/2WJE0S8s7wYir0kvkuK7K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bS9OMH/btsDBOOgWkX/2WJE0S8s7wYir0kvkuK7K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbS9OMH%2FbtsDBOOgWkX%2F2WJE0S8s7wYir0kvkuK7K0%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;742&quot; height=&quot;510&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;510&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;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;PriorityQueue&amp;lt;E&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;PriorityQueue(우선순위 큐)는 데이터의 우선순위를 두어서 가장 높은 요소가 먼저 나가도록 하는 자료구조이다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;PriorityQueue는 내부적으로 힙으로 구성되어 있는데, 우선순위를 기준으로 최대힙(MaxHeap) 또는 최소힙(MinHeap)으로 구성되어 있다. (Heap으로 구성되어 있다는 것은 이진트리 구조라는 뜻이다)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1705493841823&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 최소 힙
PriorityQueue&amp;lt;Person&amp;gt; priorityQueueLowest = new PriorityQueue&amp;lt;&amp;gt;();

//최대 힙
PriorityQueue&amp;lt;Person&amp;gt; priorityQueueHighest = new PriorityQueue&amp;lt;&amp;gt;(Collections.reverseOrder());&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;PriorityQueue는 객체 내부에 Comparable 인터페이스를 구현하거나, Comparator 클래스를 매개변수로 전달해서 정렬 조건을 따로 지정해줄 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;1. Comparable 인터페이스 구현&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;compareTo 메서드에 해당 객체의 우선순위 조건을 지정하면 PriorityQueue 내부에서 compareTo 메서드를 참조해서 우선순위가 높은 객체를 추출한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1705494461085&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Getter
@Setter
public class Person implements Comparable&amp;lt;Person&amp;gt; {
    private String name;
    private int age;

    @Override
    public int compareTo(Person person) {
        if(this.age &amp;gt;= person.getAge()) {
            return 1;
        }
        return -1;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;2. Comparator 클래스 구현&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Comparator 클래스의 compare() 클래스를 재정의 한 뒤 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;PriorityQueue 생성자 매개변수로 전달한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1705505066932&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;PriorityQueue&amp;lt;Person&amp;gt; reversedPriorityQueue = new PriorityQueue&amp;lt;&amp;gt;(
        (Person p1, Person p2) -&amp;gt; p1.getAge() &amp;gt;= p2.getAge() ? 1 : -1);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Deque&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Deque 인터페이스는 Queue 인터페이스를 확장한 인터페이스로, 큐(Queue)와 스택(Stack)의 특징을 모두 가지고 있어서 양쪽 끝에서 요소를 추가하거나 제거할 수 있는 구조를 가진다.&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;500&quot; data-origin-height=&quot;193&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lDoYs/btsDAtKwORC/DAOOcv5jCwAd5KKj9gE33K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lDoYs/btsDAtKwORC/DAOOcv5jCwAd5KKj9gE33K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lDoYs/btsDAtKwORC/DAOOcv5jCwAd5KKj9gE33K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlDoYs%2FbtsDAtKwORC%2FDAOOcv5jCwAd5KKj9gE33K%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;500&quot; height=&quot;193&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;193&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Deque 인터페이스를 구현한 클래스는 ArrayDeque, LinkedList 등이 있고 주요 메서드는 다음과 같다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Special Value 라인에 있는 메서드들은 비어있거나 꽉 차있는 경우 false 또는 Null을 리턴하지만 Throws Exception 라인에 있는 메서드들은 예외를 발생시킨다는 차이가 있다.&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;4949&quot; data-origin-height=&quot;1847&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYjP13/btsDC7sZrKX/DUMNTroIAnxPJz4VUAKU3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYjP13/btsDC7sZrKX/DUMNTroIAnxPJz4VUAKU3K/img.png&quot; data-alt=&quot;https://st-lab.tistory.com/185&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYjP13/btsDC7sZrKX/DUMNTroIAnxPJz4VUAKU3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYjP13%2FbtsDC7sZrKX%2FDUMNTroIAnxPJz4VUAKU3K%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;4949&quot; height=&quot;1847&quot; data-origin-width=&quot;4949&quot; data-origin-height=&quot;1847&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://st-lab.tistory.com/185&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 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ArrayDeque&amp;lt;E&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ArrayDeque는 Deque 인터페이스를 구현하는 클래스로, Stack으로 사용할 때는 아래와 같은 Stack 클래스의 단점을 보완하고 Queue로 사용할 때는 Queue 클래스보다 빠르다는 장점을 가지는 컬렉션이다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Stack의 단점 3가지&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;- 모든 메서드에 Synchronized를 통해 동기화 되어 있어서, 단일 스레드에서는 성능 저하 발생 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;- Vector 클래스를 상속받아서, 중간에 데이터를 삭제 및 삽입이 가능하다 (완벽한 LIFO 구조가 아님)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;- Stack 클래스를 만들 때 초기 용량을 설정할 수 없다.&amp;nbsp;&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;단, ArrayDeque은 성능을 높이기 위해 Synchronized 를 사용하지 않기 때문에 Thread-Safe 하지 않아서 멀티 스레드 환경에서는 별도의 조치가 필요하다는 단점이 있고&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;내부 공간의 용량을 초과하는 경우 기존 배열의 크기에서 두배씩 늘려서 새로운 배열을 생성하기 때문에 메모리 효율성이 떨어질 수 있다는 문제가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1705496922377&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ArrayDeque&amp;lt;E&amp;gt; extends AbstractCollection&amp;lt;E&amp;gt;
                           implements Deque&amp;lt;E&amp;gt;, Cloneable, Serializable
{
    transient Object[] elements; 

    transient int head;

    transient int tail;

    public ArrayDeque() {
        elements = new Object[16];
    }

    private void doubleCapacity() {
        assert head == tail;
        int p = head;
        int n = elements.length;
        int r = n - p; // number of elements to the right of p
        int newCapacity = n &amp;lt;&amp;lt; 1;
        if (newCapacity &amp;lt; 0)
            throw new IllegalStateException(&quot;Sorry, deque too big&quot;);
        Object[] a = new Object[newCapacity];
        System.arraycopy(elements, p, a, 0, r);
        System.arraycopy(elements, 0, a, r, p);
        elements = a;
        head = 0;
        tail = n;
    }  
}&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;위의 코드는 ArrayDeque의 내부 코드로, 생성자를 통해 기본 용량을 16으로 설정한 뒤 용량이 초과된 경우 doubleCapacity() 메서드가 호출되어 기존 크기에 2배만큼 큰 새로운 배열로 확장하는 것을 볼수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;box-sizing: border-box; border-right-width: 0px; border-top-width: 0px; border-left: #BDCEFF 12px solid; border-bottom: #BDCEFF 2px solid; line-height: 1.7; margin-right: 0px; padding: 3px 5px 3px 10px;&quot; 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;Map 인터페이스&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Map 인터페이스는 키와 값의 쌍으로 이루어진 데이터 집합으로 순서를 보장하지 않고 키의 중복을 허용하지 않는다.&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;201&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CyF8Y/btsDzvoC528/S7pz51ZsgTG2cJiU7y4ukk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CyF8Y/btsDzvoC528/S7pz51ZsgTG2cJiU7y4ukk/img.png&quot; data-alt=&quot;https://reakwon.tistory.com/151&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CyF8Y/btsDzvoC528/S7pz51ZsgTG2cJiU7y4ukk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCyF8Y%2FbtsDzvoC528%2FS7pz51ZsgTG2cJiU7y4ukk%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;201&quot; height=&quot;236&quot; data-origin-width=&quot;201&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://reakwon.tistory.com/151&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;주요 구현 클래스로는 HashMap, TreeMap, LinkedHashMap, HashTable 등이 있고 주요 메서드는 다음과 같다.&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;1144&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhfrlA/btsDAiCxZIK/4qFZNoBKSUqfyIePMmkiPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhfrlA/btsDAiCxZIK/4qFZNoBKSUqfyIePMmkiPk/img.png&quot; data-alt=&quot;https://ssdragon.tistory.com/70&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhfrlA/btsDAiCxZIK/4qFZNoBKSUqfyIePMmkiPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhfrlA%2FbtsDAiCxZIK%2F4qFZNoBKSUqfyIePMmkiPk%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;1144&quot; height=&quot;810&quot; data-origin-width=&quot;1144&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://ssdragon.tistory.com/70&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 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;HashMap&amp;lt;K, V&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;HashMap은 Map 인터페이스의 대표적인 구현 클래스로 해시 테이블 자료구조를 사용하는 클래스이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;키와 값의 쌍(Entry 객체)으로 저장되고 키는 중복될 수 없다는 특징을 가진다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;삽입 / 삭제 / 조회 연산 시 O(1) 시간복잡도를 보장하며 매우 빠르다는 장점이 있지만, 순서를 보장하지 않고 멀티스레드 환경에서 Thread-Safe 하지 않다는 문제가 있다.&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;989&quot; data-origin-height=&quot;379&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cj6Ig7/btsDAibtwGr/NqjiAtaZc9ykUCsZHzGGg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cj6Ig7/btsDAibtwGr/NqjiAtaZc9ykUCsZHzGGg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cj6Ig7/btsDAibtwGr/NqjiAtaZc9ykUCsZHzGGg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcj6Ig7%2FbtsDAibtwGr%2FNqjiAtaZc9ykUCsZHzGGg1%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;989&quot; height=&quot;379&quot; data-origin-width=&quot;989&quot; data-origin-height=&quot;379&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;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;TreeMap&amp;lt;K, V&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;TreeMap은 Map 인터페이스의 구현 클래스 중 하나로, 이진 검색 트리를 기반으로 구현되어있고 &lt;u&gt;키를 기준으로 정렬해서 저장&lt;/u&gt;하는 특징을 가진다. (Comparable 인터페이스 또는 Comparator 클래스를 통해 정렬 기준을 지정할 수 있다)&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;TreeMap은 삽입,삭제, 조회 시 매번 내부적으로 정렬하는 과정이 수행되기 때문에 HashMap 보다 느리다는 단점이 있다. (O(logN) 시간 복잡도를 가진다.)&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;size18&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;LinkedHashMap&amp;lt;K, V&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;LinkedHashMap은 HashMap을 상속받는 클래스로 HashMap과 LinkedList의 결합체 구조로 되어있다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;LinkedList와 동일하게 이중 연결 리스트(Doubly Linked List) 자료구조로 되어 있어서, Entry 내부에 이전 / 이후 Entry 참조를 저장해서 &lt;u&gt;데이터의 순서를 보장&lt;/u&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;805&quot; data-origin-height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NZJlu/btsDBtpMaKf/N0QbxFG4RUKJI4kv4OeYD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NZJlu/btsDBtpMaKf/N0QbxFG4RUKJI4kv4OeYD0/img.png&quot; data-alt=&quot;https://velog.io/@sweet_sumin/LinkedHashMap-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EC%82%B4%ED%8E%B4%EB%B4%A4%EC%96%B4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NZJlu/btsDBtpMaKf/N0QbxFG4RUKJI4kv4OeYD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNZJlu%2FbtsDBtpMaKf%2FN0QbxFG4RUKJI4kv4OeYD0%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;805&quot; height=&quot;327&quot; data-origin-width=&quot;805&quot; data-origin-height=&quot;327&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://velog.io/@sweet_sumin/LinkedHashMap-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EC%82%B4%ED%8E%B4%EB%B4%A4%EC%96%B4&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 style=&quot;padding: 0.3em 0.5em 0.3em 0.5em; margin: 0.5em 0em; border-left: 10px solid #BDCEFF; font-weight: bold;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;HashTable&amp;lt;K, V&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;HashTable은 Map 인터페이스를 구현한 클래스 중 하나로, HashMap과 거의 기능이 동일한 컬렉션이다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;차이점으로는 HashTable은 동기화가 걸려있어서 Thread-Safe 하다는 점인데, 멀티스레드 환경에서 안전하게 컬렉션을 다룰 수 있다는 장점이 있지만 HashMap보다는 느리다는 단점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&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: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&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;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: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://soft.plusblog.co.kr/24&quot;&gt;https://soft.plusblog.co.kr/24&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=uPSkCKB4Kuo&amp;amp;list=PLlTylS8uB2fA5PevGI6ARN6v-VQWmqaix&amp;amp;index=16&amp;amp;ab_channel=%EC%96%B4%EB%9D%BC%EC%9A%B4%EB%93%9C%ED%97%88%EB%B8%8C%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4-AroundHubStudio&quot;&gt;https://www.youtube.com/watch?v=uPSkCKB4Kuo&amp;amp;list=PLlTylS8uB2fA5PevGI6ARN6v-VQWmqaix&amp;amp;index=16&amp;amp;ab_channel=%EC%96%B4%EB%9D%BC%EC%9A%B4%EB%93%9C%ED%97%88%EB%B8%8C%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4-AroundHubStudio&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://coding-factory.tistory.com/555&quot;&gt;https://coding-factory.tistory.com/555&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://st-lab.tistory.com/185&quot;&gt;https://st-lab.tistory.com/185&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://devlog-wjdrbs96.tistory.com/245&quot;&gt;https://devlog-wjdrbs96.tistory.com/245&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Study/Java</category>
      <category>Collection Framework</category>
      <category>Java</category>
      <category>컬렉션프레임워크</category>
      <author>iwannarest</author>
      <guid isPermaLink="true">https://jonghne.tistory.com/103</guid>
      <comments>https://jonghne.tistory.com/103#entry103comment</comments>
      <pubDate>Wed, 17 Jan 2024 22:10:49 +0900</pubDate>
    </item>
  </channel>
</rss>