<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>조이리</title>
    <link>https://joeylee.tistory.com/</link>
    <description>백엔드 개발자의 블로그 
깃헙에서 넘어오는중
</description>
    <language>ko</language>
    <pubDate>Sat, 11 Apr 2026 14:30:51 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>joeylee</managingEditor>
    <image>
      <title>조이리</title>
      <url>https://tistory1.daumcdn.net/tistory/2260121/attach/5b9e665c9b4f46678df3ae61bb8701a0</url>
      <link>https://joeylee.tistory.com</link>
    </image>
    <item>
      <title>애즈락 B650M PG 립타이트 리뷰</title>
      <link>https://joeylee.tistory.com/58</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;디자인 작업용 컴퓨터를 새로 맞추게 되었습니다&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-sheets-root=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;램&amp;quot;}&quot;&gt;램&lt;/td&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;SK하이닉스 DDR5 16G PC5-44800 CL46 5600MHz&amp;quot;}&quot;&gt;SK하이닉스 DDR5 16G PC5-44800 CL46 5600MHz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;그래픽카드&amp;quot;}&quot;&gt;그래픽카드&lt;/td&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;GALAX 지포스 RTX 4070 Super 2X OC D6X 12GB&amp;quot;}&quot;&gt;GALAX 지포스 RTX 4070 Super 2X OC D6X 12GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;CPU&amp;quot;}&quot;&gt;CPU&lt;/td&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;AMD 라이젠9-5세대 7900&amp;quot;}&quot;&gt;AMD 라이젠9-5세대 7900&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;케이스&amp;quot;}&quot;&gt;케이스&lt;/td&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;3RSYS S406 Quiet 리버스 블랙&amp;quot;}&quot;&gt;3RSYS S406 Quiet 리버스 블랙&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;파워&amp;quot;}&quot;&gt;파워&lt;/td&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;MSI MPG A850G 80PLUS GOLD 풀모듈러 ATX 3.0 (PCIE5)&amp;quot;}&quot;&gt;MSI MPG A850G 80PLUS GOLD 풀모듈러 ATX 3.0 (PCIE5)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;쿨러&amp;quot;}&quot;&gt;쿨러&lt;/td&gt;
&lt;td style=&quot;background-color: #ffffff; color: #333333;&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;Thermalright Peerless Assassin 120 SE 서린&amp;quot;}&quot;&gt;Thermalright Peerless Assassin 120 SE 서린&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;SSD&amp;quot;}&quot;&gt;SSD&lt;/td&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;마이크론 Crucial T500 M.2 NVMe 대원씨티에스 1TB&amp;quot;}&quot;&gt;마이크론 Crucial T500 M.2 NVMe 대원씨티에스 1TB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;보드&amp;quot;}&quot;&gt;보드&lt;/td&gt;
&lt;td data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;ASRock B650M PG Riptide 대원씨티에스&amp;quot;}&quot;&gt;ASRock B650M PG Riptide 대원씨티에스&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;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;&lt;br /&gt;다양한 메인보드 중에서 애즈락의 B650M 라인에서 B650M PG 립타이트를 선택했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20240216_195723658.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;2268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ts1uY/btsEV7tjsNS/SH4enNfoPVNFT2UiXgmkx0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ts1uY/btsEV7tjsNS/SH4enNfoPVNFT2UiXgmkx0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ts1uY/btsEV7tjsNS/SH4enNfoPVNFT2UiXgmkx0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTs1uY%2FbtsEV7tjsNS%2FSH4enNfoPVNFT2UiXgmkx0%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;4032&quot; height=&quot;2268&quot; data-filename=&quot;KakaoTalk_20240216_195723658.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;2268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;패키지 및 구성: 박스샷을 보면 전체적으로 무난한 느낌이었습니다. 메인보드 내부 구성 사진을 살펴보면, SSD 방열판이 기본으로 제공되어 더욱 편리했습니다. 이전에 사용하던 SSD를 바로 장착할 수 있었고, 전원부 스펙이 괜찮다는 이유로 이 제품을 선택했습니다. 다른 메인보드에서 발생할 수 있는 이슈에 민감하여, 이 제품을 선택하게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20240217_211700958_03.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;2268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZcYuu/btsEYQc1CLg/uR0vz73MM3a3uJjXyZeM2K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZcYuu/btsEYQc1CLg/uR0vz73MM3a3uJjXyZeM2K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZcYuu/btsEYQc1CLg/uR0vz73MM3a3uJjXyZeM2K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZcYuu%2FbtsEYQc1CLg%2FuR0vz73MM3a3uJjXyZeM2K%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;4032&quot; height=&quot;2268&quot; data-filename=&quot;KakaoTalk_20240217_211700958_03.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;2268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0d0d0d;&quot; data-sheets-userformat=&quot;{&amp;quot;2&amp;quot;:14851,&amp;quot;3&amp;quot;:{&amp;quot;1&amp;quot;:0},&amp;quot;4&amp;quot;:{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:16777215},&amp;quot;12&amp;quot;:0,&amp;quot;14&amp;quot;:{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:855309},&amp;quot;15&amp;quot;:&amp;quot;S&amp;ouml;hne, ui-sans-serif, system-ui, -apple-system, \&amp;quot;Segoe UI\&amp;quot;, Roboto, Ubuntu, Cantarell, \&amp;quot;Noto Sans\&amp;quot;, sans-serif, \&amp;quot;Helvetica Neue\&amp;quot;, Arial, \&amp;quot;Apple Color Emoji\&amp;quot;, \&amp;quot;Segoe UI Emoji\&amp;quot;, \&amp;quot;Segoe UI Symbol\&amp;quot;, \&amp;quot;Noto Color Emoji\&amp;quot;&amp;quot;,&amp;quot;16&amp;quot;:12}&quot; data-sheets-value=&quot;{&amp;quot;1&amp;quot;:2,&amp;quot;2&amp;quot;:&amp;quot;장점: 전반적으로 무난한 제품이라고 생각됩니다. 그래픽카드와 파워 연결, CPU 및 RAM 장착 부분에서 크게 문제되거나 어려운 점은 없었습니다.&amp;quot;}&quot; data-sheets-root=&quot;1&quot;&gt;장점: 전반적으로 무난한 제품이라고 생각됩니다. 그래픽카드와 파워 연결, CPU 및 RAM 장착 부분에서 크게 문제되거나 어려운 점은 없었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20240217_211700958_01.jpg&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvCtIm/btsEXpG2arS/wwWFG4K2hAHvL6Wl9iuTk0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvCtIm/btsEXpG2arS/wwWFG4K2hAHvL6Wl9iuTk0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvCtIm/btsEXpG2arS/wwWFG4K2hAHvL6Wl9iuTk0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvCtIm%2FbtsEXpG2arS%2FwwWFG4K2hAHvL6Wl9iuTk0%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;2268&quot; height=&quot;4032&quot; data-filename=&quot;KakaoTalk_20240217_211700958_01.jpg&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&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;전원부 히트싱크가 눈에 들어오고 m.2 히트싱크도 있네요&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20240217_212031238.jpg&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bh1Ghq/btsEXrEN6nB/vFI6KkAXrovfHHntLOoSV1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bh1Ghq/btsEXrEN6nB/vFI6KkAXrovfHHntLOoSV1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bh1Ghq/btsEXrEN6nB/vFI6KkAXrovfHHntLOoSV1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbh1Ghq%2FbtsEXrEN6nB%2FvFI6KkAXrovfHHntLOoSV1%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;2268&quot; height=&quot;4032&quot; data-filename=&quot;KakaoTalk_20240217_212031238.jpg&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;사용후기 : 조립 완료 후 문제없이 잘 돌아가고 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;발열이나 파워 공급도 충분하여 메인보드와 관련하여 별다른 이슈 없이 잘 사용 중입니다. 기존에 사용하던 애즈락 메인보드도 문제없이 사용해왔기에, 이번에도 똑같이 잘 사용할 것으로 기대됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>조립PC</category>
      <category>메인보드#asrock b650m #조립pc #후기이벤트</category>
      <author>joeylee</author>
      <guid isPermaLink="true">https://joeylee.tistory.com/58</guid>
      <comments>https://joeylee.tistory.com/58#entry58comment</comments>
      <pubDate>Sat, 17 Feb 2024 21:27:50 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Java] 가능한 한 실패 원자적으로 만들라</title>
      <link>https://joeylee.tistory.com/57</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;실패 원자적&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반화 해서 말하자면 호출된 메서드가 실패 하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;메서드를 원자적으로 만드는 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;불변 객체&lt;/h3&gt;
&lt;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;메서드가 실패하면 새로운 객체가 만들어지지 않을 수 있으나, 기존 객체가 불안정한 상태에 빠질 일은 결코 없다.&lt;/li&gt;
&lt;li&gt;불변객체의 상태는 생성 시점에 고정되어 절대 변하지 않기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;매개변수 유효성 검사&lt;/h3&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;public Object pop() {
    if(size == 0){
        throw new EmptyStackException();
    }
    Object result = elements[--size];
    elements[size] = null // 다쓴 참조 해제
    return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;임시 복사본 사용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체의 임시 복사본에서 작업을 수행한 다음, 작업이 성공적으로 완료되면 원래 객체와 교체&lt;/li&gt;
&lt;li&gt;데이터를 임시 자료구조에 저장해 작업하는게 더 빠를 때 적용하기 좋은 방식이다&lt;/li&gt;
&lt;li&gt;예를 들어 정렬 메서드에서 정렬을 수행하기 전에 입력 리스트의 원소들을 배열로 옮겨 담는다. 배열을 사용하면 정렬 알고리즘의 반복문에서 원소들에 훨씬 빠르게 접근할 수 있기 때문이다.&lt;/li&gt;
&lt;li&gt;성능을 높여 줄 뿐만 아니라 , 혹시나 정렬에 실패하더라도 입력 리스트는 변하지 않는 효과를 얻을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;복구 코드 작성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업 도중 발생하는 실패를 가로채는 복구코드 작성하여 작업 전 상태로 되돌린다&lt;/li&gt;
&lt;li&gt;주로 디스크 기반의 내구성을 보장해야 하는 자료구조에 쓰이지만 자주 쓰이지는 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예외&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실패 원자성을 항상 만족시킬 수는 없다.&lt;/li&gt;
&lt;li&gt;예를 들어 두 스레드가 동기화 없이 같은 객체를 동시에 수정한다면 그 객체의 일관성이 깨질 수 있다.&lt;/li&gt;
&lt;li&gt;또한 Error는 복구할 수 없으므로 AssertionError에 대해서는 실패 원자적으로 만들려는 시도조차 할 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Java</category>
      <category>Effective JAVA</category>
      <category>exception</category>
      <category>Java</category>
      <author>joeylee</author>
      <guid isPermaLink="true">https://joeylee.tistory.com/57</guid>
      <comments>https://joeylee.tistory.com/57#entry57comment</comments>
      <pubDate>Thu, 9 Sep 2021 11:37:59 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Java] 예외의 상세 메시지에 실패 관련 정보를 담으라</title>
      <link>https://joeylee.tistory.com/56</link>
      <description>&lt;h3&gt;스택 추적&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;예외를 잡지 못해 프로그램이 실패하면 자바 시스템은 그 예외의 스택 추적(stack trace) 정보를 자동으로 출력한다.&lt;/li&gt;
&lt;li&gt;예외 객체의 &lt;strong&gt;toString&lt;/strong&gt; 메서드를 호출해 얻는 문자열이다&lt;/li&gt;
&lt;li&gt;예외의 클래스 이름 뒤에 상세 메시지가 붙는 형태이다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;실패 순간을 포착하려면 발생한 예외에 관여된 모든 매개변수와 필드의 값을 실패 메시지에 담아야 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public IndexOutOfBoundsException(int lowerBound, int upperBound, int index) {
    // 실패률 포착하는 상세 메시지를 생성한다.
    super(String.format(
    &amp;quot;최솟값: %d , 최댓값: %d, 인덱스: %d&amp;quot;, lowerBound, upperBound, index));

    // 프로그램에서 이용할 수 있도록 실패 정보를 저장해둔다.
    this.lowerBound = lowerBound;
    this.upperBound = upperBound;
  this.index = index;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Java</category>
      <category>Effective JAVA</category>
      <category>exception</category>
      <category>Java</category>
      <author>joeylee</author>
      <guid isPermaLink="true">https://joeylee.tistory.com/56</guid>
      <comments>https://joeylee.tistory.com/56#entry56comment</comments>
      <pubDate>Sat, 7 Aug 2021 14:23:03 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Java] 메서드가 던지는 모든 예외를 문서화하라</title>
      <link>https://joeylee.tistory.com/55</link>
      <description>&lt;h3&gt;검사 예외&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;검사 예외는 항상 따로따로 선언하고, 각 예외가 발생하는 상황을 javadoc의 @throw 태그를 사용하여 정확히 문서화 하자&lt;/li&gt;
&lt;li&gt;공통 상위 클래스 하나로 뭉뚱그려 선언하는 일은 삼가자&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;비검사 예외&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;비검사 예외도 검사 예외처럼 정성껏 문서화 해두면 좋다.&lt;/li&gt;
&lt;li&gt;비검사 예외는 일반적으로 프로그래밍 오류를 뜻하는데, 자신이 일으킬 수 있는 오류들을 알려주면 사용하는 입장에서 도움이 된다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;메서드가 던질 수 있는 예외를 각각 @throws 태그로 문서화하되, 비검사 예외는 메서드 선언의 throws 목록에 넣지 말자&lt;/em&gt;&lt;/strong&gt; 검사냐 비검사냐에 따라 사용자가 해야 할 일이 달라지므로 둘을 구분해주는것은 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;현실적으로 불가능할때&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;비검사 예외는 문서화하기 불가능할 때도 있다. 예컨대 다른 사람이 작성한 클래스를 사용하는 메서드가 있을때, 발생가능한 모든 비검사 예외를 문서화 했다고 하더라도, 다른 사람이 작성한 클래스쪽에 수정사항이 있다면 문서화 되지 않은 새로운 비검사 예외를 전파하게 될것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;핵심 정리&lt;/h3&gt;
&lt;p&gt;메서드가 던질 가능성이 있는 모든 예외를 문서화하라.검사 예외든 비검사 예외든,추상 메서드든 구체 메서드든 모두 마찬가지다.문서화에는 자바독의 @throws 태그를 사용 하면 된다.검사 예외만 메서드 선언의 throws 문에 일일이 선언하고，비검사 예외는 메서드 선언에는 기입하지 말자.발생 가능한 예외를 문서로 남기지 않으면 다른 사람이 그 클래스나 인터페이스를 효과적으로 사용하기 어렵거나 심지어 불가능할 수도 있다.&lt;/p&gt;</description>
      <category>Java</category>
      <category>Effective JAVA</category>
      <category>exception</category>
      <category>Java</category>
      <author>joeylee</author>
      <guid isPermaLink="true">https://joeylee.tistory.com/55</guid>
      <comments>https://joeylee.tistory.com/55#entry55comment</comments>
      <pubDate>Sat, 7 Aug 2021 14:22:06 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Java] 추상화 수준에 맞는 예외를 던지라</title>
      <link>https://joeylee.tistory.com/54</link>
      <description>&lt;h3&gt;문제상황&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;수행하려는 일과 관련 없어 보이는 예외가 튀어나오면 당황스럽다&lt;/li&gt;
&lt;li&gt;메서드가 저수준 예외를 처리하지 않고 바깥으로 전파해버릴 때 종종 일어나는 일이다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;해결방법&lt;/h3&gt;
&lt;h3&gt;예외번역(Exception translation)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;상위 계층에서는 저수준 예외를 잡아 자신의 추상화 수준에 맞는 예외로 바꿔 던져야 한다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;public E get(int index) {
    ListIterator&amp;lt;E&amp;gt; i = listIterator(index);
    try {
        return i.next();
    } catch (NoSuchElementException e) {
        throw new IndexOutOfBoundsException(&amp;quot;인덱스: &amp;quot; + index);
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;예외 연쇄(Exception chaning)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;예외를 번역 할때 저수준 예외가 디버깅에 도움이 된다면 예외 연쇄를 사용하는게 좋다&lt;/li&gt;
&lt;li&gt;문제의 근본 원인인 저수준 예외를 고수준 예외에 실어 보내는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;try {
    // 저수준 추상화를 사용
} catch (LowerLevelException cause) {
    // 저수준 예외를 고수준 예외에 실어 보낸다.
    throw new HigherLevelException(cause);
}

class HigherLevelException extends Exception { 
    HigherLevelException(Throwable cause) {
        super(cause); 
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;무턱대고 예외를 전파하기 보다는 가능하다면 저수준 메서드가 반드시 성공하도록 하여 아래 계층에서는 예외가 발생하지 않도록 하는 것이 최선이다.&lt;/li&gt;
&lt;li&gt;차선책도 알아보자. 아래 계층에서의 예외를 피할 수 없다면, 상위 계충에서 그 예외를 조용히 처리하여 문제를 API호출자에까지 전파하지 않는 방법이 있다. 로깅으로 남긴다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;핵심 정리&lt;/h3&gt;
&lt;p&gt;아래 계층의 예외를 예방하거나 스스로 처리할 수 없고, 그 예외를 상위 계층에 그대로 노출하기 곤란하다면 예외 번역을 사용하라. 이때 예외 연쇄를 이용하면 상위 계층에는 맥락에 어울리는 고수준 예외를 던지면서 근본 원인도 함께 알려주어 오류를 분석하기에 좋다&lt;/p&gt;</description>
      <category>Java</category>
      <category>Effective JAVA</category>
      <category>exception</category>
      <category>Java</category>
      <author>joeylee</author>
      <guid isPermaLink="true">https://joeylee.tistory.com/54</guid>
      <comments>https://joeylee.tistory.com/54#entry54comment</comments>
      <pubDate>Sat, 7 Aug 2021 14:21:14 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Java] 표준 예외를 사용하라</title>
      <link>https://joeylee.tistory.com/53</link>
      <description>&lt;h3&gt;표준 예외 재사용의 장점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;사용하기 쉽고 익숙하다&lt;/li&gt;
&lt;li&gt;읽기 쉽다&lt;/li&gt;
&lt;li&gt;메모리 사용량도 줄고 클래스를 적재하는 시간도 적다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;대표적인 예외&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;IllegalArgumentException&lt;ul&gt;
&lt;li&gt;가장 많이 재사용되는 예외로, 호출자가 인수로 부적절한 값을 넘길 때 던지는 예외다. (ex. 반복 횟수를 지정하는 매개변수에 음수가 할당될 때)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IllegalStateException&lt;ul&gt;
&lt;li&gt;이 예외는 대상 객체의 상태가 호출된 메서드를 수행하기에 적합하지 않을 때 주로 던진다. 제대로 초기화되지 않은 객체를 사용하려 할 때 던질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NullPointerException&lt;ul&gt;
&lt;li&gt;메서드가 던지는 모든 예외를 잘못된 인수나 상태라고 포괄적으로 생각할 수도 있어, IllegalArgument라고 볼 수도 있겠으나, 그 중 특수한 일부는 따로 구분해서 써야한다. &lt;strong&gt;null&lt;/strong&gt; 값을 허용하지 않는 메서드에 &lt;strong&gt;null&lt;/strong&gt;을 건네면 관례상 &lt;strong&gt;NullPointerException&lt;/strong&gt;을 던진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IndexOutOfBoundsException&lt;ul&gt;
&lt;li&gt;NullPointerException과 유사하게 특수한 예로, 어떤 시퀀스의 허용 범위를 넘는 값을 건넬 때, &lt;strong&gt;IndexOutOfBoundsException&lt;/strong&gt;을 던진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ConcurrentModificationException&lt;ul&gt;
&lt;li&gt;단일 스레드에서 사용하려고 설계한 객체를 여러 스레드가 동시에 수정하려 할 때 던진다. (사실 동시 수정을 확실히 검출할 수 있는 안정된 방법은 없어, 이 예외는 문제가 생길 가능성을 알려주는 정도의 역할로 쓰인다)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;UnsupportedOperationException&lt;ul&gt;
&lt;li&gt;이 예외는 클라이언트가 요청한 동작을 대상 객체가 지원하지 않을 때 던진다. 대부분 객체는 자신이 정의한 메서드를 모두 지원하니 흔히 쓰이는 예외는 아니다. 보통은 구현하려는 인터페이스의 메서드 일부를 구현할 수 없을 때 쓰는데, 예를 들어 원소를 넣을 수만 있는 List 구현체에 대고 누군가 &lt;strong&gt;remove&lt;/strong&gt; 메서드를 호출하면 이 예외를 던질 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Exception,RuntimeException,Throwable,Error는 직접 재사용하지 말자&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;이 클래스들은 추상 클래스라고 생각하길 바란다. 이 예외들은 다른 예외들의 상위 클래스이므로，즉 여러 성격의 예외들을 포괄하는 클래스이므로 안정적으로 테스트할 수 없다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Java</category>
      <category>Effective JAVA</category>
      <category>exception</category>
      <category>Java</category>
      <author>joeylee</author>
      <guid isPermaLink="true">https://joeylee.tistory.com/53</guid>
      <comments>https://joeylee.tistory.com/53#entry53comment</comments>
      <pubDate>Wed, 4 Aug 2021 17:18:29 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Java] 필요 없는 검사 예외 사용은 피하라</title>
      <link>https://joeylee.tistory.com/52</link>
      <description>&lt;h3&gt;검사 예외의 불편&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;검사 예외를 싫어하는 개발자가 많지만 제대로 활용하면 API와 프로그램의 질을 높일 수 있다. 반면 사용이 과해지면 불편하기만 할 수도 있다.&lt;/li&gt;
&lt;li&gt;검사 예외가 단 하나뿐이라면 오직 그 예외 때문에 API 사용자는 try 블록을 추가해야 하고 스트림에서 직접 사용하지 못하게 된다. 그러니 이런 상황이라면 검사 예외를 안 던지는 방법이 없는지 고민해볼 가치가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;검사 예외 회피 방법&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;비검사 예외&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;API를 제대로 사용해도 발생할 수 있는 예외이거나, 프로그래머가 의미 있는 조치를 취할 수 있는 경우라면 이 정도 부담쯤은 받아들일 수 있을 것이다. 하지만 이 경우들이 아니라면, 비검사 예외를 사용하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Optional&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;검사 예외를 회피하는 두 번째 방법은 적절한 결과 타입을 담은 옵셔널을 반환하는 것이다.&lt;/li&gt;
&lt;li&gt;검사 예외를 던지는 대신 단순히 빈 옵셔널을 반환하면 된다. 쉽다.&lt;/li&gt;
&lt;li&gt;하지만 이 방식은 단점이 있다.&lt;/li&gt;
&lt;li&gt;예외가 발생한 이유를 알려주는 부가 정보를 담을 수 없다는 점이다. (예외를 사용하면 구체적인 예외 타입과 그 타입이 제공하는 메서드들을 활용해 부가 정보를 제공할 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;메서드 쪼개기&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;검사 예외를 회피하는 세 번째 방법은 검사 예외를 던지는 메서드를 2개로 쪼개어 비검사 예외로 바꾸는 것이다. 쪼개진 첫 번째 메서드는 예외가 던져질지 여부를 boolean값으로 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;try { obj.action(args);
} catch (TheCheckedException e) {
...// 예외 상황에 대처한다. 
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;
if (obj.actionPermitted(args)) { 
    obj.action(args);
} else {
...// 예외 상황에 대처한다. 
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;이 리팩터 링을 모든 상황에 적용할 수는 없다. 그래도 적용할 수만 있다면 더 쓰 기 편한 API를 제공할 수 있다. 리팩터 링 후의 API가 딱히 더 아름답진 않지만, 더 유연한 것은 확실하다&lt;/li&gt;
&lt;li&gt;actionPermitted는 상태 검사 메서드에 해당하므로 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나 외부 요인에 의해 상태가 변할 수 있다면 이 리팩터링은 적절하지 않다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;핵심 정리&lt;/h3&gt;
&lt;p&gt;꼭 필요한 곳에만 사용한다면 검사 예외는 프로그램의 안전성을 높여주지만，남용하면 쓰기 고통스러운 API를 낳는다. API호출자가 예외 상황에서 복구할 방법이 없다면 비검사 예외를 던지자. 복구가 가능하고 호출자가 그 처리를 해주길 바란다면，우선 옵셔널을 반환해도 될지 고민하자. 옵셔널만으로는 상황을 처리하기에 충분한 정보를 제공할 수 없을 때만 검사 예외를 던지자.&lt;/p&gt;</description>
      <category>Java</category>
      <category>Effective JAVA</category>
      <category>exception</category>
      <category>Java</category>
      <author>joeylee</author>
      <guid isPermaLink="true">https://joeylee.tistory.com/52</guid>
      <comments>https://joeylee.tistory.com/52#entry52comment</comments>
      <pubDate>Wed, 4 Aug 2021 17:15:42 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Java] 복구할 수 있는 상황에는 검사 예외를, 프로그래밍 오류에는 런타임 예외를 사용하라</title>
      <link>https://joeylee.tistory.com/51</link>
      <description>&lt;h3&gt;검사 예외와 런타임 예외&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;자바는 문제 상황을 알리는 타입(Throwable)으로 검사 예외, 런타임 예외, 에러 이렇게 세 가지를 제공한다.&lt;/li&gt;
&lt;li&gt;하지만, 해당 타입을 언제 무엇을 사용해야하는 지 헷갈리는 경우가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;참고 지침&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;호출하는 쪽에서 복구하리라 여겨지는 상황이라면 검사 예외를 사용하라.&lt;ul&gt;
&lt;li&gt;검사 예외를 던지면 &lt;strong&gt;호출자가 그 예외를 catch로 잡아 처리하거나 더 바깥으로 전파하도록 강제하게 된다.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;따라서, 메소드 선언에 포함된 검사 예외 각각은 그 메소드를 호출했을 때 발생할 수 있는 유력한 결과임을 API 사용자에게 알려주는 것이다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;비검사 throwable은 두 가지로, 런타임 예외와 에러이다.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;이 둘은 프로그램에서 잡을 필요가 없거나 혹은 통상적으로 잡지 말아야 한다.&lt;/li&gt;
&lt;li&gt;프로그램에서 비검사 예외나 에러를 던졌다는 것은 복구가 불가능하거나 더 실행해봐야 득이 없다는 뜻이다.&lt;/li&gt;
&lt;li&gt;검사 예외 는 일반적으로 복구할 수 있는 조건일 때 발생한다. 따라서 호출자가 예외 상황에서 벗어나는데 필요한 정보를 알려주는 메소드를 함께 제공하는 것이 중요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로그래밍 오류를 나타낼 때는 런타임 예외를 사용하자&lt;ul&gt;
&lt;li&gt;런타임 예외의 대부분은 전제조건을 만족하지 못했을 때 발생한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;여기서 전제조건을 만족하지 못했다라는 것은, 단순히 클라이언트가 해당 API의 명세에 기록된 제약을 지키지 못했다라는 뜻이다.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;하지만 실제로 해당 상황이 복구가 가능한 상황인지 아닌지는 판단하기 어렵다. 사실상 &lt;strong&gt;API 설계자의 판단에 달렸다.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;그러므로, 복구가 가능하다고 판단되면 검사예외를, 그렇지 않다면 런타임 예외, 확신이 어렵다면 비검사 예외를 선택해라.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;에러는 보통 JVM이 자원부족, 불변식 깨짐 등 더 이상 수행을 계속할 수 없는 상황일 때 사용한다&lt;ul&gt;
&lt;li&gt;자바 언어의 널리 퍼진 규약으로 Error 클래스를 상속해 하위 클래스를 만드는 일을 자제하는 것이 좋다. 다시 말해서, &lt;strong&gt;우리가 구현하는 비검사 throwble은 모두 RuntimeException의 하위 클래스여야 한다.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Error는 상속하지 말아야할 뿐 아니라, throw 문을 직접 던지는 일도 없어야한다.(AssertionError는 예외)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exception, RuntimeException, Error를 상속하지 않은 throwble을 만들 수 있는데 이런, throwable은 이로울 게 없으니 절대 사용하지 말아라. 이런 throwable은 예외보다 나을 게 없으며 API 사용자를 헷갈리게 할 뿐이다.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;예외의 메소드&lt;/strong&gt;는 주로 그 &lt;strong&gt;예외를 일으킨 상황에 관한 정보를 코드 형태로 전달&lt;/strong&gt;하는데 쓰인다. 그러나 &lt;strong&gt;throwable 클래스들&lt;/strong&gt;은 대부분 &lt;strong&gt;오류 메시지 포맷을 상세히 기술하지 않는다.&lt;/strong&gt; 이것은, JVM이나 릴리스에 따라 포맷이 달라질 수 있다는 뜻이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;핵심 정리&lt;/h3&gt;
&lt;p&gt;복구할 수 있는 상황이면 검사 예외를，프로그래밍 오류라면 비검사 예외를 던지자.확실 하지 않다면 비검사 예외를 던지자.검사 예외도 아니고 런타임 예외도 아닌 throwable 은 정의하지도 말자.검사 예외라면 복구에 필요한 정보를 알려주는 메서드도 제공하자.&lt;/p&gt;</description>
      <category>Java</category>
      <category>Effective JAVA</category>
      <category>exception</category>
      <category>Java</category>
      <author>joeylee</author>
      <guid isPermaLink="true">https://joeylee.tistory.com/51</guid>
      <comments>https://joeylee.tistory.com/51#entry51comment</comments>
      <pubDate>Wed, 4 Aug 2021 17:12:32 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Java] 예외는 진짜 예외 상황에만 사용하라</title>
      <link>https://joeylee.tistory.com/50</link>
      <description>&lt;ul&gt;
&lt;li&gt;예외는 오직 예외 상황에서만 써야한다. 절대 일상적인 제어 흐름용으로 사용해선 안 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;try {
    int i = 0;
    while(true)
        range[i++].climb();
} catch (ArraylndexOutOfBoundsException e) {
}

//표준적인 관용구
for (Mountain m : range) 
    m.climb();&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;잘못된 추론&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;예외를 통한 명확한 검사가 빠를 것이다.&lt;/li&gt;
&lt;li&gt;코드를 try-catch 블록 안에 넣으면 JVM이 적용할 수 있는 최적화가 제한된다.&lt;ul&gt;
&lt;li&gt;JVM은 배열에 접근할 때마다 경계를 넘지않는지 매번 검사하므로. 이 부분을 제한한다는 추론으로 보인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;배열을 순회하는 &lt;strong&gt;표준 관용구&lt;/strong&gt; 는 JVM이 알아서 최적화해 중복 검사를 진행하지 않는다.&lt;ul&gt;
&lt;li&gt;여기서 말한 중복검사는 JVM에서의 배열 경계 검사와 반복문에서 배열 경계 검사를 말한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이런 추론으로 예외를 사용하지 않고 반복문을 사용하면 성능이 안 좋아 진다는 잘못된 추론이 발생한 것인데, 실제로는 &lt;strong&gt;예외를 사용한 쪽이 표준 관용구 보다 훨씬 느리다.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;예외를 사용한 반복문의 오류&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;예외를 사용한 반복문은 코드를 헷갈리게 하고 성능을 떨어뜨리는데서 끝나지 않는다.&lt;/li&gt;
&lt;li&gt;만약, &lt;strong&gt;반복문 안에 버그가 숨어 있다면 흐름 제어에 쓰인 예외가 이 버그를 숨겨 디버깅을 훨씬 어렵게 할 것이다.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Ex. 반복문의 몸체에서 호출한 메서드 내부에서 반복문과 관련 없는 배열을 사용하다가 ArrayInexOutOfBoundsException을 일으킬 시,&lt;ul&gt;
&lt;li&gt;표준 관용구였다면 이 버그는 예외를 잡지 않고 스택 추적 정보를 남긴 후 해당 스레드를 즉각 종료했을 것이다.&lt;/li&gt;
&lt;li&gt;그러나 예외를 통해 제어 흐름을 사용했다면, 버그 때문에 발생한 엉뚱한 예외를 &lt;strong&gt;정상적인 반복문에 의한 종료 상황&lt;/strong&gt;으로 오해하고 넘어갈 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;결과적으로, 예외는 오직 예외 상황에서만 사용해야하고, 절대로 일상적인 제어 흐름용으로는 사용해선 안 된다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;잘 설계된 API 원칙&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;잘설계된 api 라면 클라이언트가 정상적인 제어 흐름에서 예외를 사용할 일이 없게 해야 한다&lt;/li&gt;
&lt;li&gt;&amp;#39;상태 의존적&amp;#39; 메소드를 제공하는 클래스는 &amp;#39;상태 검사&amp;#39; 메소드도 함께 제공해야 한다.&lt;ul&gt;
&lt;li&gt;Iterator 인터페이스의 next(상태 의존적 메소드)와 hasNext(상태 검사 메소드)를 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;//Iterator 표준 관용구 사용
for(Iterator&amp;lt;Foo&amp;gt; i = collection.iterator(); i.hashNext();) {
  Foo foo = i.next();
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;hasNext 메소드가 없다면?&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;try {
    Iterator&amp;lt;Foo&amp;gt; i = collection.iterator(); 
    while(true) {
        Foo foo = i.next(); 
    }
} catch (NoSuchElementException e) {
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;반복문에 예외를 사용하면 장황하고 헷갈리며 속도도 느리고, 엉뚱한 곳에서 발생한 버그를 숨기기도 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;상태 검사 메서드 대신 사용 가능한 선택지&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;외부 동기화 없이 여러 스레드가 동시에 접근&lt;/strong&gt;할 수 있거나 &lt;strong&gt;외부 요인으로 상태가 변할 수 있다&lt;/strong&gt;면 &lt;strong&gt;옵셔널이나 특정 값을 사용&lt;/strong&gt;한다.&lt;ul&gt;
&lt;li&gt;상태 검사 메소드와 상태 의존적 메소드 호출 사이에 객체의 상태가 변할 수 있기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;성능이 중요한 상황에서 상태 검사 메서드가 상태 의존적 메소드의 작업 일부를 중복 수행&lt;/strong&gt;한다면 &lt;strong&gt;옵셔널이나 특정 값을 사용&lt;/strong&gt;한다.&lt;/li&gt;
&lt;li&gt;그 외 다른 경우에는 &lt;strong&gt;상태 검사 메소드&lt;/strong&gt; 를 사용하는 것이 낫다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;핵심 정리&lt;/h3&gt;
&lt;p&gt;예외는 예외 상황에서 쓸 의도로 설계되었다.정상적인 제어 흐름에서 사용해서는 안되며，이를 프로그래머에게 강요하는 API를 만들어서도 안 된다.&lt;/p&gt;</description>
      <category>Java</category>
      <category>Effective JAVA</category>
      <category>exception</category>
      <category>Java</category>
      <author>joeylee</author>
      <guid isPermaLink="true">https://joeylee.tistory.com/50</guid>
      <comments>https://joeylee.tistory.com/50#entry50comment</comments>
      <pubDate>Mon, 2 Aug 2021 01:09:19 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Java] 프로그램의 동작을 스레드 스케줄러에 기대지 말라</title>
      <link>https://joeylee.tistory.com/49</link>
      <description>&lt;h3&gt;스레드 스케줄러&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;여러 스레드가 실행중이면 운영체제의 스레드 스케줄러가 어떤 스레드를 얼마나 오래 실행할지 정한다.&lt;/li&gt;
&lt;li&gt;스레드 스케줄링 정책은 OS다를 수 있기 때문에, 프로그램은 이 정책에 좌지우지 되어서는 안된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;특징&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;이식성 좋은 프로그램은 실행 가능한 스레드의 평균적인 수를 프로세서 수보다 지나치게 많아지지 않도록 하는 것이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;스레드 스케줄러가 고민할 거리가 줄어든다.&lt;/li&gt;
&lt;li&gt;실행 가능한 스레드의 수는 전체 스레드 수와 다르다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;실행 준비가 된 스레드들은 맡은 작업을 완료할 때까지 계속 실행되도록 만든다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;실행 가능한 스레드 수를 적게 유지하는 방법은 각 스레드가 작업을 완료한 후 다음 일거리가 생길 때까지 대기하도록 하는 것이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;당장 처리해야 할 작업이 없다면 실행돼서는 안 된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;스레드 풀을 적절히 설정해야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;public class SlowCountDownLatch {
  private int count;

  public SlowCountDownLatch(int count) {
      if (count &amp;lt; 0)
          throw new IllegalArgumentException(count + &amp;quot; &amp;lt; 0&amp;quot;);
      this.count = count;
  }

  public void await() {
      while (true) {
          synchronized(this) {
              if (count == 0)
                  return;
          }
      }
  }
  public synchronized void countDown() {
      if (count != 0)
          count--;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;스레드는 공유 객체의 상태가 바뀔 때까지 쉬지 않고 검사하는 바쁜 대기 상태가 되면 안 된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;스케줄러의 변덕에 취약하며 프로세서에 부담을 주어 다른 작업이 실행될 기회를 박탈한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;yield&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;yield 스레드 실행 양보&lt;/li&gt;
&lt;li&gt;yield 지양해야하고 테스트 할 수단이 없고 jvm이나 os마다 결과가 천차만별일 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;핵심 정리&lt;/h3&gt;
&lt;p&gt;프로그램의 동작을 스레드 스케줄러에 기대지 말자.견고성과 이식성을 모두 해치는 행위다.&lt;br&gt;같은 이유로，Thread.yield와 스레드 우선순위에 의존해서도 안 된다.이 기능들 은 스레드 스케줄러에 제공하는 힌트일 뿐이다.스레드 우선순위는 이미 잘 동작하는 프 로그램의 서비스 품질을 높이기 위해 드물게 쓰일 수는 있지만，간신히 동작하는 프로그램을 ‘고치는 용도’로 사용해서는 절대 안 된다.&lt;/p&gt;</description>
      <category>Java</category>
      <category>concurrency</category>
      <category>Effective JAVA</category>
      <category>Java</category>
      <author>joeylee</author>
      <guid isPermaLink="true">https://joeylee.tistory.com/49</guid>
      <comments>https://joeylee.tistory.com/49#entry49comment</comments>
      <pubDate>Sun, 1 Aug 2021 03:39:09 +0900</pubDate>
    </item>
  </channel>
</rss>