<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>쿠쿠의 개발일지</title>
    <link>https://dding9code.tistory.com/</link>
    <description>바쁜 일정으로 인해 블로그 휴식기 입니다 ㅠ...
안정화 되면 꾸준히 글을 올려보겠습니다.</description>
    <language>ko</language>
    <pubDate>Fri, 8 May 2026 11:12:46 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>쿠쿠s</managingEditor>
    <image>
      <title>쿠쿠의 개발일지</title>
      <url>https://tistory1.daumcdn.net/tistory/5074503/attach/7dbb7d9f6a7f447690b340e9aa115596</url>
      <link>https://dding9code.tistory.com</link>
    </image>
    <item>
      <title>영한님 책에서 볼 수 없는 JPA (Hibernate) 내부 코드 살펴보기</title>
      <link>https://dding9code.tistory.com/132</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;몇 달 전 JPA를 공부를 하는데 책에서 말하는 &lt;b&gt;엔티티매니저&lt;/b&gt;, &lt;b&gt;쓰기지연저장소&lt;/b&gt; 등등 이런 용어들은 코드로 어떻게 되어있을까 &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;궁금해져 JPA 관련 검색을 해보니 대부분 글들이 영한님의 PDF 강의 자료로 이루어져 있었습니다. &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;하지만 저는 강의나&amp;nbsp;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;책에 있는 기본적인 개념, 예제 말고&lt;/span&gt; 실제로 어떻게&lt;b&gt; 코드로 구현되어 있고, 어떤 자료구조를 사용했을까 등등.. &lt;/b&gt;궁금했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그래서 제가 궁금해서&amp;nbsp;&lt;b&gt;왜? 라는 궁금증&lt;/b&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;size14&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;*현재 저는 실무자도 아니고 취준생이기 때문에 분석 실력은 살짝 감안하셔서 봐주시면 감사하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;뭔가 이상하거나 틀린 부분이 있다면 댓글 남겨주시면 확인 후 반영하도록 하겠습니다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JPA 그리고 Hibernate&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;앞서 들어가기 전에 &lt;b&gt;JPA&lt;/b&gt; 란 &lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;자바에서 객체-관계 매핑을 위한 사양 또는 &lt;b&gt;인터페이스&lt;/b&gt;이며, &lt;b&gt;Hibernate는 해당 사양의 구현체&lt;/b&gt;입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;즉, JPA는 일련의 규칙과 요구 사항을 정의하는 ORM용 표준 API인 반면, 하이버네이트는 JPA를 구현하고 추가 기능을 제공하는 ORM 프레임워크입니다. &lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd;&quot;&gt;따라서 하이버네이트는 JPA 사양을 구현하는 여러 ORM 프레임워크 중 하나이며 개발자는 특정 요구와 선호도에 따라 하이버네이트 또는 기타 JPA구현(DataNucleus, EclipseLink)을 선택할 수 있습니다.&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;무작정 코드 뜯어보기&lt;/b&gt;&lt;/h2&gt;
&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;버전 정보는 org.hibernate:hibrenate-core: 5.6.10.Final&amp;nbsp; 입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;가장 널리 사용되고, 인기 있는 구현체 Hibernate에 대해서 한번 파보도록 하겠습니다. &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;하이버네이트는 구현체니까 어떤 인터페이스를 구현하고 있는지 찾아봤습니다. 엔티티매니저를 통해 관리가 된다는 것을 토대로 검색을 해봤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p 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;스크린샷 2023-02-15 오후 6.26.03.png&quot; data-origin-width=&quot;1760&quot; data-origin-height=&quot;1220&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cq9yNU/btrZrUsK2Hs/JTpfUIjrQtA77ihXkOe5U1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cq9yNU/btrZrUsK2Hs/JTpfUIjrQtA77ihXkOe5U1/img.png&quot; data-alt=&quot;javax.persistence 패키지의 EntityManager interface&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cq9yNU/btrZrUsK2Hs/JTpfUIjrQtA77ihXkOe5U1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcq9yNU%2FbtrZrUsK2Hs%2FJTpfUIjrQtA77ihXkOe5U1%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;1760&quot; height=&quot;1220&quot; data-filename=&quot;스크린샷 2023-02-15 오후 6.26.03.png&quot; data-origin-width=&quot;1760&quot; data-origin-height=&quot;1220&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;javax.persistence 패키지의 EntityManager interface&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;persistence context와 상호 작용하는 데 사용되는 인터페이스입니다. EntityManager 인스턴스가 persistence context와 연결되어 있습니다. persistence context는 모든 persistent entity ID에 대해 고유한 엔티티 인스턴스가 있는 엔티티 인스턴스의 집합입니다. &lt;b&gt;persistence context 내에서 엔티티 인스턴스와 해당 라이프사이클이 관리&lt;/b&gt;됩니다. &lt;br /&gt;EntityManager API는 영구 엔터티 인스턴스를 생성 및 제거하고, 기본 키를 기준으로 엔터티를 찾고, 엔터티를 쿼리 하는 데 사용됩니다. 지정된 EntityManager 인스턴스에서 관리할 수 있는 엔티티 집합은 persistence unit에 의해 정의됩니다. persistence unit는 응용프로그램별로 관련되거나 그룹화된 모든 클래스 집합을 정의하며, 단일 데이터베이스에 대한 매핑에서 이 클래스 집합을 공동으로 배치해야 합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;익숙한 문구인 &lt;b&gt;persistenec context&lt;/b&gt; 가 나오는군요! 위의 정의한 대로 구현체들이 구현이 되었음을 수 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;추가로 인터페이스 왼쪽의 화살표(&amp;darr;)를 누르면 구현체들의 목록을 볼 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;구현체인 &amp;nbsp;SessionImpl 내부로 들어가 봅시다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-15 오후 8.26.01.png&quot; data-origin-width=&quot;1672&quot; data-origin-height=&quot;1300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B9qXk/btrZqAoIcuO/HNi3rUcXQF80266xZuQMbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B9qXk/btrZqAoIcuO/HNi3rUcXQF80266xZuQMbK/img.png&quot; data-alt=&quot;SessionImpl Class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B9qXk/btrZqAoIcuO/HNi3rUcXQF80266xZuQMbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB9qXk%2FbtrZqAoIcuO%2FHNi3rUcXQF80266xZuQMbK%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;890&quot; height=&quot;692&quot; data-filename=&quot;스크린샷 2023-02-15 오후 8.26.01.png&quot; data-origin-width=&quot;1672&quot; data-origin-height=&quot;1300&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SessionImpl Class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;들어와 보니 &lt;b&gt;Session의 구체적인 구현체&lt;/b&gt;라고 설명이 되어있고, &lt;b&gt;해당 클래스는 스레드에 안전하지 않다는&lt;/b&gt; 설명이 눈에 들어옵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;아래 필드에 선언된 변수를 보니 익숙한 이름 &quot;persistenceContext&quot; 도 보이고 익숙하지 않은 변수들도 많이 보입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;우선! Session의 구체적인 구현체라 하니 Session 은 무엇인지, 어떤 스펙인지 확인하러 가보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-16 오후 7.04.46.png&quot; data-origin-width=&quot;981&quot; data-origin-height=&quot;1186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQiCRA/btrZzaXCzip/njIRVIOVJ49F2J6mvzg4o1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQiCRA/btrZzaXCzip/njIRVIOVJ49F2J6mvzg4o1/img.png&quot; data-alt=&quot;Session Interface&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQiCRA/btrZzaXCzip/njIRVIOVJ49F2J6mvzg4o1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQiCRA%2FbtrZzaXCzip%2FnjIRVIOVJ49F2J6mvzg4o1%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;981&quot; height=&quot;1186&quot; data-filename=&quot;스크린샷 2023-02-16 오후 7.04.46.png&quot; data-origin-width=&quot;981&quot; data-origin-height=&quot;1186&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Session Interface&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Java 응용 프로그램과 Hibernate 간의 기본 런타임 인터페이스입니다. 이것은 지속성 서비스의 개념을 추상화하는 중앙 API 클래스입니다. &lt;b&gt;세션의 생명 주기는 논리적 트랜잭션의 시작과 끝에 의해 제한&lt;/b&gt;됩니다.(긴 트랜잭션은 여러 데이터베이스 트랜잭션에 걸쳐 있을 수 있습니다.)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;세션의 주요 기능&lt;/b&gt;은 &lt;b&gt;매핑된 엔티티 클래스의 인스턴스에 대한 생성, 읽기 및 삭제 작업을 제공&lt;/b&gt;하는 것입니다.&lt;br /&gt;인스턴스는 다음 세 가지 상태 중 하나로 존재할 수 있습니다:&lt;br /&gt;1. transient: 영속 상태가 아님, 어떤 세션과도 연결되지 않음&lt;br /&gt;2. persistent: 고유한 세션과 연결&lt;br /&gt;3. detached: 이전에는 persistent였으며 세션과 연결되지 않았습니다&lt;br /&gt;&lt;br /&gt;&lt;b&gt;save(), persist()&lt;/b&gt; 또는 saveOrUpdate()를 호출하여 Transient instances를 &lt;b&gt;persistent(영속화)&amp;nbsp;&lt;/b&gt;할 수 있습니다.&lt;br /&gt;delete를 호출하여 Persistent instances를 일시적으로 변경할 수 있습니다. &lt;b&gt;get() 또는 load()&lt;/b&gt; &lt;b&gt;메서드에서 반환되는 모든 인스턴스는 persistent&lt;/b&gt;입니다.&lt;br /&gt;&lt;br /&gt;update() saveOrUpdate(), lock() 또는 replicate(복제)를 호출하여 Detached를 persistent으로 만들 수 있습니다.&lt;br /&gt;&lt;br /&gt;transient 또는 detached 인스턴스의 상태는 SQL INSERT, DELETE, UPDATE에서 update, merge를 호출하여 새로운 영구 인스턴스로 영구화할 수도 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;persistent instances에 대한 변경 사항은 플러시 시간에 감지&lt;/b&gt;되며 &lt;b&gt;SQL UPDATE가 생성&lt;/b&gt;됩니다. saveOrUpdate() 및 replicate()는 INSERT 또는 UPDATE가 생성됩니다. 구현자가 스레드 세이프가 되도록 의도된 것은 아닙니다.&lt;br /&gt;&lt;br /&gt;대신 각 스레드/트랜잭션은 SessionFactory에서 자체 인스턴스를 가져와야 합니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;번역을 보니 익숙한 설명이 많이 있지 않나요? 책 또는 강의에서 설명된 내용들이 클래스에서 어떻게 이루어져 있고 정의되어 있는지 직접 눈으로 보는 건 또 다른 느낌입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;인터페이스를 확인했으니 다시 구현체인 SessionImpl로 돌아가보겠습니다. &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;SessionImpl.class로 다시 돌아가보니... 해당 클래스는 총 3897 라인으로 이렇게 긴 코드를 작성할 일도 거의 없고, 이 장황한 코드를 어디서 어떻게 봐야 할지 감도 안 와서 기준을 정해서 찾아보려 했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;책이나 강의를 보셨다면&amp;nbsp;&lt;b&gt;영속성 컨텍스트의 장점&lt;/b&gt;이라고 알고 계실 것 같습니다. &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;1차 캐시, 동일성 보장, 트랜잭션을 지원하는 쓰기지연, 변경 감지, 지연 로딩 &lt;/b&gt;이런 장점이 있는 것을 생각하면서 &lt;b&gt;저의&lt;/b&gt; &lt;b&gt;관심사를 기준으로 6가지를 선정&lt;/b&gt;하여 조사를 하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 쓰기지연저장소&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. PersistContext&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Save&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Find&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. Clear&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. Flush&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드가 장황하고 지루할 수 있지만 한번 보시는 것도 나쁘지 않을 것 같다고 생각을 합니다!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 쓰기지연저장소는 어떻게 구현되어 있을까?&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;엔티티 매니저는 트랜잭션을 커밋하기 직전까지 DB에 엔티티를 저장하지 않고 &lt;b&gt;내부 쿼리 저장소&lt;/b&gt;에 INSERT SQL을 차곡차곡 모아두고, 트랜잭션을 커밋할 때 모아둔 쿼리를 DB에 보내는데 이것을 트랜잭션을 지원하는 &lt;b&gt;쓰기지연(transactional-write-behind)&lt;/b&gt; 이라 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-영한님 JPA책 100P-&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;어떻게 쿼리를 모아두고 커밋직전에 모은 쿼리를 DB에 보낼 수 있을까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;순서도 Insert, update, delete로 보내야 할 텐데 어떻게 이게 가능하도록 만들었을까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;어떤 자료구조로 이루어져 있을까?&amp;nbsp; 등등&amp;nbsp; 책, 강의에 담기지 않은 내부 구현이 궁금했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;하지만 구현체의 이름조차 모르니 처음에는 막연하게 SessionImpl에 선언된 필드를 살펴봤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-16 오후 8.32.59.png&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvrmNf/btrZuGQkxVb/TH0WbB0Wyfq2JdWYaI8ST1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvrmNf/btrZuGQkxVb/TH0WbB0Wyfq2JdWYaI8ST1/img.png&quot; data-alt=&quot;SessionImpl Class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvrmNf/btrZuGQkxVb/TH0WbB0Wyfq2JdWYaI8ST1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdvrmNf%2FbtrZuGQkxVb%2FTH0WbB0Wyfq2JdWYaI8ST1%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;840&quot; height=&quot;216&quot; data-filename=&quot;스크린샷 2023-02-16 오후 8.32.59.png&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SessionImpl Class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;프로퍼티는 Map으로 설정된 설정값일 것 같고, persistenceContext 위에 선언된 &lt;b&gt;ActionQueue&lt;/b&gt; 가 있어 우선 해당 클래스에 들어가 봤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-16 오후 8.35.10.png&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;934&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blz1qV/btrZAFPXX7X/o1PW6JwKgTEu3FUQPj4be1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blz1qV/btrZAFPXX7X/o1PW6JwKgTEu3FUQPj4be1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blz1qV/btrZAFPXX7X/o1PW6JwKgTEu3FUQPj4be1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fblz1qV%2FbtrZAFPXX7X%2Fo1PW6JwKgTEu3FUQPj4be1%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;926&quot; height=&quot;934&quot; data-filename=&quot;스크린샷 2023-02-16 오후 8.35.10.png&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;934&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이벤트와 관련된 작업 대기열을 유지 관리합니다. &lt;br /&gt;작업 대기열은 세션&lt;b&gt; transactional-write-behind&lt;/b&gt; semantics의 일부로 대기 중인&lt;b&gt; DML 작업을 보관&lt;/b&gt;합니다.&lt;br /&gt;&lt;b&gt;DML 작업은&lt;/b&gt; &lt;b&gt;플러시가 데이터베이스에 대해 강제로 실행될 때까지 여기서 대기열에 저장&lt;/b&gt;됩니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;아까 본 transactional-write-behind&lt;span style=&quot;background-color: #fcfcfc;&quot;&gt; (쓰기지연) 그리고 DML 작업을 보관한다는 내용, 아래의 필드에 선언된 insert, delete, update를 보아 &lt;b&gt;해당 클래스(ActionQueue)가 쓰기지연저장소&lt;/b&gt;임을 알았습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-16 오후 8.45.02.png&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgtSwm/btrZAFPYsCY/OdLucYbzrLAup6ECbPZBrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgtSwm/btrZAFPYsCY/OdLucYbzrLAup6ECbPZBrk/img.png&quot; data-alt=&quot;ActionQueue 의 인스턴스 변수 중&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgtSwm/btrZAFPYsCY/OdLucYbzrLAup6ECbPZBrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgtSwm%2FbtrZAFPYsCY%2FOdLucYbzrLAup6ECbPZBrk%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;602&quot; height=&quot;135&quot; data-filename=&quot;스크린샷 2023-02-16 오후 8.45.02.png&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ActionQueue 의 인스턴스 변수 중&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #333333;&quot;&gt;쿼리랑 직접적으로 관련된 필드가 눈에 들어오는데 &lt;b&gt;ExecutableList 타입으로&lt;/b&gt;&amp;nbsp;선언이 되어있습니다. 또 위의 설명을 보니 insert, update, delete 가 올바른 순서대로 수행돼야 한다고 적혀있습니다. 어떻게 이를 보장해 줄까요? 아직 그 의문은 사라지지 않았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-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: #fcfcfc; color: #333333;&quot;&gt;&lt;b&gt;ExecutableList &lt;/b&gt;객체로 들어가 보겠습니다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-16 오후 8.47.04.png&quot; data-origin-width=&quot;1077&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mqkEh/btrZuB2DJut/nSsNGCCYBWV5tNz18kkS1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mqkEh/btrZuB2DJut/nSsNGCCYBWV5tNz18kkS1k/img.png&quot; data-alt=&quot;ExecutableList Class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mqkEh/btrZuB2DJut/nSsNGCCYBWV5tNz18kkS1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmqkEh%2FbtrZuB2DJut%2FnSsNGCCYBWV5tNz18kkS1k%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;1077&quot; height=&quot;578&quot; data-filename=&quot;스크린샷 2023-02-16 오후 8.47.04.png&quot; data-origin-width=&quot;1077&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ExecutableList Class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;각 Executable list와 관련된 상태의 특수 캡슐화.&lt;br /&gt;executalbes 정렬 관리 (lazily)&lt;br /&gt;list에서 executables의 영향을 받는 querySpaces를 관리하고 이를 캐시 합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;ExecutableList는 내부에 ArrayList를 선언하여 insert, update, delete를 리스트의 형태로 관리를 하는 객체&lt;/b&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다시 ActionQueue 클래스로 돌아가서 조금만 휠을 내려보면 &lt;b&gt;LinkedHashMap으로&lt;/b&gt; 선언된 &lt;b&gt;EXECUTABLE_LISTS_MAP&lt;/b&gt; 이 보입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-16 오후 9.25.30.png&quot; data-origin-width=&quot;921&quot; data-origin-height=&quot;116&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D95RU/btrZBr43heZ/Dn5lk34h4h9YT5C0vEFyl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D95RU/btrZBr43heZ/Dn5lk34h4h9YT5C0vEFyl1/img.png&quot; data-alt=&quot;ActionQueue Class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D95RU/btrZBr43heZ/Dn5lk34h4h9YT5C0vEFyl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD95RU%2FbtrZBr43heZ%2FDn5lk34h4h9YT5C0vEFyl1%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;921&quot; height=&quot;116&quot; data-filename=&quot;스크린샷 2023-02-16 오후 9.25.30.png&quot; data-origin-width=&quot;921&quot; data-origin-height=&quot;116&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ActionQueue Class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;실행 순서에 삽입된 모든 ExecutableLists에 대한 providers가 포함된 LinkedHashMap&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;특이하게 LinkedHashMap으로 구현&lt;/b&gt;이 되어있습니다. &lt;b&gt;왜 LinkedHashMap 일까?&lt;/b&gt; 생각하면서 휠을 내려보니 금방 그 이유를 알았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-16 오후 9.26.41.png&quot; data-origin-width=&quot;786&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2fWI4/btrZBsv7gT8/wEIcutK1zsyxZscfcYJYBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2fWI4/btrZBsv7gT8/wEIcutK1zsyxZscfcYJYBk/img.png&quot; data-alt=&quot;ActionQueue - insert&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2fWI4/btrZBsv7gT8/wEIcutK1zsyxZscfcYJYBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2fWI4%2FbtrZBsv7gT8%2FwEIcutK1zsyxZscfcYJYBk%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;786&quot; height=&quot;439&quot; data-filename=&quot;스크린샷 2023-02-16 오후 9.26.41.png&quot; data-origin-width=&quot;786&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ActionQueue - insert&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-16 오후 9.26.53.png&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;244&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GWltj/btrZAgCXapX/prXyF6lfew2m3WK2NBd521/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GWltj/btrZAgCXapX/prXyF6lfew2m3WK2NBd521/img.png&quot; data-alt=&quot;ActionQueue - update&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GWltj/btrZAgCXapX/prXyF6lfew2m3WK2NBd521/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGWltj%2FbtrZAgCXapX%2FprXyF6lfew2m3WK2NBd521%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;789&quot; height=&quot;232&quot; data-filename=&quot;스크린샷 2023-02-16 오후 9.26.53.png&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;244&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ActionQueue - update&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-16 오후 9.27.09.png&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blEoaZ/btrZAta7wIx/1U2KHkiecpvdfnrZd5Ro7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blEoaZ/btrZAta7wIx/1U2KHkiecpvdfnrZd5Ro7k/img.png&quot; data-alt=&quot;delete&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blEoaZ/btrZAta7wIx/1U2KHkiecpvdfnrZd5Ro7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblEoaZ%2FbtrZAta7wIx%2F1U2KHkiecpvdfnrZd5Ro7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;792&quot; height=&quot;207&quot; data-filename=&quot;스크린샷 2023-02-16 오후 9.27.09.png&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;delete&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Insert , Update, Delete 순서대로 LinkedHashMap에 put을 해줍니다. 입력된 순서대로 Key의 순서가 보장되는 자료구조이기 때문에 &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;쿼리의 순서가 보장이 될 수 있었습니다. 그래서 &lt;span style=&quot;background-color: #fcfcfc;&quot;&gt;insert, update, delete 가 올바른 순서대로 수행될 수 있었습니다!&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그리고 JPA를 사용하다 보면 쿼리의 로그를 보신 적이 있을텐데 해당 쿼리가 PK 순서대로 나가는 로그를 보신 적이 있지 않았나요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-16 오후 9.38.52.png&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXout8/btrZznCH6jU/A4WUOhrIUNl4uR4XKKw1J0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXout8/btrZznCH6jU/A4WUOhrIUNl4uR4XKKw1J0/img.png&quot; data-alt=&quot;ActionQueue Class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXout8/btrZznCH6jU/A4WUOhrIUNl4uR4XKKw1J0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXout8%2FbtrZznCH6jU%2FA4WUOhrIUNl4uR4XKKw1J0%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;857&quot; height=&quot;200&quot; data-filename=&quot;스크린샷 2023-02-16 오후 9.38.52.png&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ActionQueue Class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;ActionQueue(쓰기지연저장소)에서 정렬을 제공&lt;/b&gt;하기 때문에 작업을 하면서 따로 쿼리의 순서를 정렬하지 않아도 내부에서 이미 정렬을 해주는 사실을 알 수 있었습니다.&amp;nbsp; 그렇다면 실제로 해당 메서드가 어디에 쓰이는지 사용되는 곳을 확인해 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-16 오후 9.40.10.png&quot; data-origin-width=&quot;1001&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHKP5i/btrZzLi2xcy/c5swa19v8cnLbBnfk4DsR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHKP5i/btrZzLi2xcy/c5swa19v8cnLbBnfk4DsR0/img.png&quot; data-alt=&quot;AbstractFlushingEventListener Class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHKP5i/btrZzLi2xcy/c5swa19v8cnLbBnfk4DsR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHKP5i%2FbtrZzLi2xcy%2Fc5swa19v8cnLbBnfk4DsR0%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;1001&quot; height=&quot;66&quot; data-filename=&quot;스크린샷 2023-02-16 오후 9.40.10.png&quot; data-origin-width=&quot;1001&quot; data-origin-height=&quot;66&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AbstractFlushingEventListener Class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;엔티티를 Flush 할 때 사용이 되는 사실을 알 수 있고, 메서드 위의 설명을 보니 더티체킹이라는 문구도 보이네요. 뭔가 하나씩 연결되는 느낌입니다. 이 부분은 Flush를 조사할 때 다시 알아보도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이렇게 살펴보니 쓰기지연저장소가 어떻게 구현되어 있고 어떤 기능을 제공하는지 어느 정도 파악할 수 있었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다른 기능이 궁금하면 저와 같은 방법으로 제일 궁금한 부분부터 찾아보시면 좋을 것 같습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;ActionQueue(쓰기지연저장소)는 이 정도로 살펴보고 나머지 궁금한 부분들을 또 찾아보러 가겠습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. PersistenceContext (영속성 컨텍스트) 내부구조 살펴보기&lt;/b&gt;&lt;/h2&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;span style=&quot;color: #333333;&quot;&gt;들어가기 전 개념 다시 보기&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Persistence Context는 엔티티 인스턴스에 대한 변경 사항을 추적하고 필요한 경우 해당 변경 사항을 데이터베이스에 다시 전파하는 역할을 합니다. 엔티티 인스턴스가 Persistence Context 내에서 수정되면 EntityManager는 적절한 SQL 문을 자동으로 생성하여 데이터베이스의 해당 행을 업데이트합니다.&lt;br /&gt;Persistence Context는 응용 프로그램이 모든 작업에 대해 데이터베이스와 직접 상호 작용할 필요 없이 관리 엔티티 인스턴스의 캐시로 작업할 수 있도록 해주기 때문에 JPA에서 중요한 개념입니다. 이렇게 하면 성능이 향상되고 응용프로그램의 비즈니스 로직을 실행하는 데 필요한 데이터베이스 쿼리 수가 줄어듭니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-17 오후 5.01.16.png&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZhzTs/btrZGinWFq0/bGLghkqzs7k8RmEvaWRMW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZhzTs/btrZGinWFq0/bGLghkqzs7k8RmEvaWRMW1/img.png&quot; data-alt=&quot;SessionImpl.class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZhzTs/btrZGinWFq0/bGLghkqzs7k8RmEvaWRMW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZhzTs%2FbtrZGinWFq0%2FbGLghkqzs7k8RmEvaWRMW1%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;595&quot; height=&quot;59&quot; data-filename=&quot;스크린샷 2023-02-17 오후 5.01.16.png&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SessionImpl.class&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;이전 SessionImpl 클래스에서 ActionQueue 밑에 선언되어 있던 &lt;b&gt;persistenceContext&lt;/b&gt; 내부는 어떻게 구현이 되어있는지 확인해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-17 오후 5.21.24.png&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;1206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m3CaC/btrZIgiDvrC/NY5yCpSIVEIDwJxAqzfk8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m3CaC/btrZIgiDvrC/NY5yCpSIVEIDwJxAqzfk8k/img.png&quot; data-alt=&quot;StatefulPersistenceContext.class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m3CaC/btrZIgiDvrC/NY5yCpSIVEIDwJxAqzfk8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm3CaC%2FbtrZIgiDvrC%2FNY5yCpSIVEIDwJxAqzfk8k%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;1206&quot; data-filename=&quot;스크린샷 2023-02-17 오후 5.21.24.png&quot; data-origin-width=&quot;985&quot; data-origin-height=&quot;1206&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;StatefulPersistenceContext.class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-17 오후 5.56.27.png&quot; data-origin-width=&quot;529&quot; data-origin-height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kYy8p/btrZGWesLkx/XO7DbbWli11yW6PNWFLcGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kYy8p/btrZGWesLkx/XO7DbbWli11yW6PNWFLcGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kYy8p/btrZGWesLkx/XO7DbbWli11yW6PNWFLcGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkYy8p%2FbtrZGWesLkx%2FXO7DbbWli11yW6PNWFLcGK%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;529&quot; height=&quot;327&quot; data-filename=&quot;스크린샷 2023-02-17 오후 5.56.27.png&quot; data-origin-width=&quot;529&quot; data-origin-height=&quot;327&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;영속성콘텍스트의 1차 캐시, 다들 아시겠지만 위의 그림처럼 Key, Value의 형태로 데이터가 저장이 되어있다고 보셨을 텐데 실제로 확인해 보니 HashMap으로 구현되어 있는 것을 볼 수 있습니다. Key값이 EntityKey라는 객체인데 알고 있는 배운 지식을 토대로 접근하면, 해당 객체는 Entity의 아이디를 저장을 해야 할 텐데 내부도 그렇게 이루어져 있을 것이라 추측을 해볼 수 있을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 그렇게 구현이 되어있는지 확인해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-17 오후 6.04.56.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;706&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnpkBL/btrZGg43eql/NHKW2VLytajKLPcGEUDegk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnpkBL/btrZGg43eql/NHKW2VLytajKLPcGEUDegk/img.png&quot; data-alt=&quot;EntityKey.class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnpkBL/btrZGg43eql/NHKW2VLytajKLPcGEUDegk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnpkBL%2FbtrZGg43eql%2FNHKW2VLytajKLPcGEUDegk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;755&quot; height=&quot;706&quot; data-filename=&quot;스크린샷 2023-02-17 오후 6.04.56.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;706&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;EntityKey.class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;식별자로 특정 세션에서 엔티티 인스턴스를 고유하게 식별합니다.&lt;/b&gt;&lt;br /&gt;세션 범위 내에서만 안전하게 사용할 수 있습니다: 예를 들어 테넌트 ID는 동일성 정의의 일부로 고려되지 않습니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;고유성을 결정하는 데 사용되는 정보는 엔티티 이름과 식별자 값으로 구성됩니다.&lt;/b&gt; (see equals)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스의 설명과 더불어 생성자의 설명을 보면 &quot;Construct a unique identifier for an entity class instance&quot; 즉 &lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;엔티티 클래스 인스턴스의 고유 식별자를 생성한다고 적혀있습니다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다시 StatefulPersistenceContext 클래스로 돌아가서...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-18 오전 1.11.07.png&quot; data-origin-width=&quot;505&quot; data-origin-height=&quot;235&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cshwC8/btrZJDZjFCp/1BjCjnR3t5tSQ8V4Ncim1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cshwC8/btrZJDZjFCp/1BjCjnR3t5tSQ8V4Ncim1K/img.png&quot; data-alt=&quot;StatefulPersistenceContext.class 의 인스턴스 변수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cshwC8/btrZJDZjFCp/1BjCjnR3t5tSQ8V4Ncim1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcshwC8%2FbtrZJDZjFCp%2F1BjCjnR3t5tSQ8V4Ncim1K%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;509&quot; height=&quot;237&quot; data-filename=&quot;스크린샷 2023-02-18 오전 1.11.07.png&quot; data-origin-width=&quot;505&quot; data-origin-height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;StatefulPersistenceContext.class 의 인스턴스 변수&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;위에서 확인한 정보를 토대로 1차 캐시, 프록시, 스냅샷에 사용되는 키는 엔티티의 고유 식별자를 가지며, 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;color: #333333;&quot;&gt;위 사진에 선언된 Key들의 역할을 조금 더 구체적으로 설명하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1. &lt;b&gt;entityByKey:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기본 키로 엔터티를 추적하는 데 사용됩니다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Entity의 primary key로 키가 지정되며 해당 Entity 인스턴스를 포함합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. &lt;b&gt;entityByUniqueKey:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;entitiesByKey와 유사하지만 unique&amp;nbsp;key(있는 경우)로 엔티티를 추적하는 데 사용됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;unique&amp;nbsp;key는 column의 각 값이 테이블의 모든 행에서 고유하도록 하는 제약 조건입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;entitiesByUniqueKey 맵은 고유 키 값으로 키가 지정되며 해당 엔티티 인스턴스를 포함합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3. &lt;b&gt;proxiesByKey:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기본 키로 엔티티 프록시(또는 지연 로드된 엔티티 참조)를 추적하는 데 사용됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Entity의 primary key로 키가 지정되며&amp;nbsp;해당 프록시 인스턴스를 포함합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;프록시는 실제로 필요할 때까지 엔터티 데이터의 로드를 지연하는 데 사용됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;4. &lt;b&gt;entitySnapshotsByKey:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 맵은 엔티티가 persistence context에 처음 로드될 때 엔티티의 원래 상태를 추적하는 데 사용됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Entity의 primary key로 키가 지정되며 Entity 상태의 스냅샷을 포함합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Entity&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;에&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;어떤&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;변경&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;사항이&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;적용되었는지&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;확인하고&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;필요한&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;경우&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;변경&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;사항을&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;롤백하는&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;데&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;유용합니다&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 어떻게 동작하고, 이루어져 있는지는 알겠는데 그래서 1차 캐시에는 언제, 어떻게 저장이 되는 것일까 궁금 해집니다. StatefulPersistenceContext 클래스를 탐색하다보면 아래와 같은 메서드를 발견할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-18 오전 1.15.46.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;243&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs2RCt/btrZIlE6Mdn/L3lpL4ZTdh6Y0GIRWxTbGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs2RCt/btrZIlE6Mdn/L3lpL4ZTdh6Y0GIRWxTbGK/img.png&quot; data-alt=&quot;StatefulPersistenceContext.class 에서 제공하는 메서드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs2RCt/btrZIlE6Mdn/L3lpL4ZTdh6Y0GIRWxTbGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs2RCt%2FbtrZIlE6Mdn%2FL3lpL4ZTdh6Y0GIRWxTbGK%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;510&quot; height=&quot;248&quot; data-filename=&quot;스크린샷 2023-02-18 오전 1.15.46.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;243&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;StatefulPersistenceContext.class 에서 제공하는 메서드&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;PersistenceContext에서는 addEntity라는 메서드를 제공해 주는데 말 그대로 해당 메서드는 1차 캐시에 엔티티를 저장하는 메서드입니다. 이 메서드를 통해서 알 수 있는 사실이 있습니다. &lt;b&gt;&lt;u&gt;1차 캐시에는 엔티티의 고유 식별자가 Key로 등록&lt;/u&gt;이 됩니다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티를 식별자로 조회하거나, 엔티티의 특정 필드값으로 조회를 해도 결국 1차캐시에는 엔티티의 고유 식별자가 Key 로 등록이 되는 것입니다.&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;스크린샷 2023-03-11 오후 6.22.13.png&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;567&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkCua8/btr3cCXjOo8/lhsj3d91m8PpKRmi36tMg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkCua8/btr3cCXjOo8/lhsj3d91m8PpKRmi36tMg1/img.png&quot; data-alt=&quot;TwoPhaseLoad Class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkCua8/btr3cCXjOo8/lhsj3d91m8PpKRmi36tMg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkCua8%2Fbtr3cCXjOo8%2Flhsj3d91m8PpKRmi36tMg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;943&quot; height=&quot;567&quot; data-filename=&quot;스크린샷 2023-03-11 오후 6.22.13.png&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;567&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TwoPhaseLoad Class&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;아래에서 추후 설명드리겠지만 짧게 설명을 드리면, 조회의 과정에서 1차 캐시에 없을 경우 결국 DB에서 조회를 하게 되는데 해당 row를 읽어오면, 위의 메서드가 실행되어 1차 캐시에 등록을 하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 알게 된 사실로 영속성 컨텍스트의 이점 중 하나인 동일성 보장을 설명할 수 있을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-18 오전 1.12.59.png&quot; data-origin-width=&quot;1460&quot; data-origin-height=&quot;238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s1R1k/btrZLTUkY4w/pUUQX8QmkdfWbHYnGhuhlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s1R1k/btrZLTUkY4w/pUUQX8QmkdfWbHYnGhuhlk/img.png&quot; data-alt=&quot;영속 엔티티의 동일성 보장 - 영한님 PDF 중&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s1R1k/btrZLTUkY4w/pUUQX8QmkdfWbHYnGhuhlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs1R1k%2FbtrZLTUkY4w%2FpUUQX8QmkdfWbHYnGhuhlk%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;1460&quot; height=&quot;238&quot; data-filename=&quot;스크린샷 2023-02-18 오전 1.12.59.png&quot; data-origin-width=&quot;1460&quot; data-origin-height=&quot;238&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;영속 엔티티의 동일성 보장 - 영한님 PDF 중&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많이 보셨을 내용일 것 같습니다. 동일성 보장이 왜 가능하게 되는지 직접 코드를 파헤쳐봤기 때문에 더 선명하게 그림이 그려질 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리를 하면 첫 번째 조회에서는 1차 캐시에서 가져올 대상이 없어 Entity의 고유 식별자가 1차 캐시에 Key로 등록이 되고 Value로는 해당 Entity가 들어가게 됩니다.&amp;nbsp; &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;두 번째 조회에서는 해당 엔티티의 고유식별자(Key)를 사용해서 1차 캐시(Map)에서 가져오기 때문에 같은 Entity(Value)를 반환하게 되어 동일성이 보장됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;제가 정리한 내용 외에 PersistenceContext 클래스에서 제공하는 더 많은 필드와 메서드가 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;마음 같아서 다 정리하고 싶지만 다음 파트도 있으니 우선 여기까지 하고 넘어가 보도록 하겠습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;간단하게(?) 스프링 데이터 JPA&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;스프링 데이터 JPA는 JPA를 정말 편리하게 사용하도록 도와주는 기술입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저도 프로젝트를 진행할 때 스프링 데이터 JPA를 사용을 했습니다. 많은 분들도 사용을 했을 것이라 생각을 하여 Save, Find 등등 이 어떻게 동작하는지 들어가기 전에 보면 도움이 되지 않을까 해서 적어보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 2.06.18.png&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;69&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JIher/btr3ezkY9OZ/h3oVaw4biaTOOKHyg9Ohk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JIher/btr3ezkY9OZ/h3oVaw4biaTOOKHyg9Ohk1/img.png&quot; data-alt=&quot;Example&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JIher/btr3ezkY9OZ/h3oVaw4biaTOOKHyg9Ohk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJIher%2Fbtr3ezkY9OZ%2Fh3oVaw4biaTOOKHyg9Ohk1%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;572&quot; height=&quot;69&quot; data-filename=&quot;스크린샷 2023-03-11 오후 2.06.18.png&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;69&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Example&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 2.08.55.png&quot; data-origin-width=&quot;873&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfI4Jg/btr3c29bMUB/EbTos4J3JIoXzw2basIoQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfI4Jg/btr3c29bMUB/EbTos4J3JIoXzw2basIoQk/img.png&quot; data-alt=&quot;Example&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfI4Jg/btr3c29bMUB/EbTos4J3JIoXzw2basIoQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfI4Jg%2Fbtr3c29bMUB%2FEbTos4J3JIoXzw2basIoQk%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;873&quot; height=&quot;280&quot; data-filename=&quot;스크린샷 2023-03-11 오후 2.08.55.png&quot; data-origin-width=&quot;873&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Example&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;스프링 데이터 JPA 를 사용했다면 위와 같이 JpaRepository 인터페이스를 extends 하여 사용해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Save, Find, Delete... 등등 동작을 따로 정의하지는 않았지만 사용이 가능했습니다. 실제 내부에서는 어떻게 구현되어 있고 동작하는지 알아보겠습니다.&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;우선 JpaRepository 인터페이스의 상속관계를 다이어 그램을 보면 아래와 같습니다.&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;스크린샷 2023-03-11 오후 2.25.38.png&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;382&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4aShy/btr3gOa0hv4/G3NrSXbmaKV2sO5LF1H9A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4aShy/btr3gOa0hv4/G3NrSXbmaKV2sO5LF1H9A0/img.png&quot; data-alt=&quot;JpaRepository 상속관계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4aShy/btr3gOa0hv4/G3NrSXbmaKV2sO5LF1H9A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4aShy%2Fbtr3gOa0hv4%2FG3NrSXbmaKV2sO5LF1H9A0%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;860&quot; height=&quot;382&quot; data-filename=&quot;스크린샷 2023-03-11 오후 2.25.38.png&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;382&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JpaRepository 상속관계&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;JpaRepository는 다양한 인터페이스를 확장하여 사용하고 있습니다.&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-filename=&quot;스크린샷 2023-03-11 오후 2.28.39.png&quot; data-origin-width=&quot;671&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCgzMZ/btr3eB4ciS7/eWmjhhBLKHh1jWwzJZ91WK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCgzMZ/btr3eB4ciS7/eWmjhhBLKHh1jWwzJZ91WK/img.png&quot; data-alt=&quot;Repository Interface&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCgzMZ/btr3eB4ciS7/eWmjhhBLKHh1jWwzJZ91WK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCgzMZ%2Fbtr3eB4ciS7%2FeWmjhhBLKHh1jWwzJZ91WK%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;671&quot; height=&quot;282&quot; data-filename=&quot;스크린샷 2023-03-11 오후 2.28.39.png&quot; data-origin-width=&quot;671&quot; data-origin-height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Repository Interface&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;중앙 리포지토리 마커 인터페이스입니다. 관리할 도메인 유형과 도메인 유형의 ID 유형을 캡처합니다. 일반적인 목적은 유형 정보를 보유하고 클래스 경로 검색 중에 이 정보를 확장하는 인터페이스를 검색하여 스프링 빈을 쉽게 만드는 것입니다.&lt;br /&gt;&lt;br /&gt;이 인터페이스를 확장하는 도메인 리포지토리는 단순히 CrudRepository에서 선언된 것과 동일한 서명의 메서드를 선언함으로써 CRUD 메서드를 선택적으로 노출할 수 있습니다.&lt;br /&gt;&lt;br /&gt;Type parameters: &amp;lt;T&amp;gt;&amp;nbsp; -&amp;nbsp; 리포지토리가 관리하는 도메인 유형&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;ID&amp;gt; -&amp;nbsp; 리포지토리가 관리하는 엔티티의 ID 유형&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JpaRepository를 사용할 때 제네릭 타입을 설정하는 규칙이 해당 인터페이스에 지정되어 있는 것도 확인이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&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;Central Repository Marker Inferface(CRMI)&lt;/b&gt; 라고 표현이 되어있어 여러분들도 궁금해하실 것 같아 제가 미리 찾아왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;CRMI(Central Repository Marker Interface)&lt;/b&gt;는 특정 클래스가 중앙 저장소임을 나타내기 위해 Java 개발에 사용되는 마커 인터페이스입니다. CRMI 인터페이스는 표준 자바 API의 일부는 아니지만 데이터를 관리하고 저장하기 위해 중앙 저장소에 의존하는 엔터프라이즈 자바 애플리케이션에서 종종 사용됩니다.&lt;br /&gt;&lt;br /&gt;CRMI 인터페이스의 목적은 모든 중앙 저장소 클래스가 구현해야 하는 공통 메서드 집합을 정의하는 것입니다. 이러한 방법에는 저장소의 데이터를 추가, 제거 및 쿼리 하는 작업이 포함될 수 있습니다.&lt;br /&gt;&lt;br /&gt;CRMI 인터페이스를 구현하면 클래스를 중앙 저장소로 쉽게 식별할 수 있으므로 다른 클래스와 구성 요소가 쉽게 상호 작용할 수 있습니다. 또한 마커 인터페이스를 사용하면 중앙 저장소를 사용하는 응용 프로그램의 여러 부분에 걸쳐 일관성과 표준화를 보장할 수 있습니다.&lt;br /&gt;&lt;br /&gt;CRMI 인터페이스는 엔터프라이즈 Java 애플리케이션에서 데이터를 구성하고 관리하는 데 유용한 도구이지만 Java 개발에 필수적이거나 필수적인 구성 요소는 아닙니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 CrudRepository 인터페이스 입니다.&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-filename=&quot;스크린샷 2023-03-11 오후 2.46.14.png&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pEAr1/btr3cIC1kTb/nywlYdetMERF8Dt3qsV20k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pEAr1/btr3cIC1kTb/nywlYdetMERF8Dt3qsV20k/img.png&quot; data-alt=&quot;CrudRepository Interface&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pEAr1/btr3cIC1kTb/nywlYdetMERF8Dt3qsV20k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpEAr1%2Fbtr3cIC1kTb%2FnywlYdetMERF8Dt3qsV20k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;697&quot; height=&quot;810&quot; data-filename=&quot;스크린샷 2023-03-11 오후 2.46.14.png&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CrudRepository Interface&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;특정 유형의 리포지토리에서 일반 CRUD 작업을 위한 인터페이스입니다.&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;크게 설명이 필요 없는 인터페이스인 것 같습니다. 편하게 사용했던 CRUD에 관한 기능들이 정의되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 궁금한 점은 @NoRepositoryBean 은 왜 붙어있을까? 궁금하여 마찬가지로 검색을 해봤습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 어노테이션은 Spring Data 프로젝트에서 특정 인터페이스가 저장소 빈으로 인스턴스화되지 않아야 함을 나타내기 위해 사용됩니다.&lt;br /&gt;&lt;br /&gt;Spring Data 프로젝트는 저장소 인터페이스를 검색할 때 일반적으로 기본 저장소 인터페이스를 확장하는 각 인터페이스에 대해 빈을 생성합니다. 이 기능은 여러 리포지토리에서 공유하려는 공통 메서드 또는 기능 집합이 있는 경우 유용합니다.&lt;br /&gt;&lt;br /&gt;그러나 빈으로 인스턴스화되지 않는 중간 인터페이스가 있는 경우 @NoRepositoryBean으로 주석을 달 수 있습니다. 이렇게 하면 Spring Data가 해당 인터페이스에 빈을 생성하는 것을 방지할 수 있으며, 해당 메서드는 해당 인터페이스를 확장하는 구체적인 리포지토리 인터페이스에서만 사용할 수 있습니다.&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;한마디로 실제 사용되는 Repository 가 아니고 기능을 정의하기 위한 Repository 임을 나타내는 어노테이션입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 2.54.57.png&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;469&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GBYWF/btr3cJIIRof/vtNjJ1dE2gg13lTPKMl1pK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GBYWF/btr3cJIIRof/vtNjJ1dE2gg13lTPKMl1pK/img.png&quot; data-alt=&quot;PagingAndSortingRepository Interface&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GBYWF/btr3cJIIRof/vtNjJ1dE2gg13lTPKMl1pK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGBYWF%2Fbtr3cJIIRof%2FvtNjJ1dE2gg13lTPKMl1pK%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;679&quot; height=&quot;469&quot; data-filename=&quot;스크린샷 2023-03-11 오후 2.54.57.png&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;469&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;PagingAndSortingRepository Interface&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;페이지 분할 및 정렬 추상화를 사용하여 엔티티를 검색하는 추가 메서드를 제공하는 CrudRepository의 확장입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 3.00.57.png&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;411&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ej7Lp/btr3cJ23OWd/ku6Ou7E6HqPHBZwqfQ5YvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ej7Lp/btr3cJ23OWd/ku6Ou7E6HqPHBZwqfQ5YvK/img.png&quot; data-alt=&quot;QueryByExampleExecutor Interface&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ej7Lp/btr3cJ23OWd/ku6Ou7E6HqPHBZwqfQ5YvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEj7Lp%2Fbtr3cJ23OWd%2Fku6Ou7E6HqPHBZwqfQ5YvK%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;666&quot; height=&quot;411&quot; data-filename=&quot;스크린샷 2023-03-11 오후 3.00.57.png&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;411&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;QueryByExampleExecutor Interface&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 인터페이스는 Exmaple 인스턴스를 기반으로 쿼리를 실행할 수 있는 메서드를 정의합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 JpaRepository를 상속하여 사용하기만 해도 Save, Find 등등 모든 기능들이 사용이 가능했던 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외 사용방법은 책, 강의를 통해 배우면 더 쉽고 빠르게 배울 수 있기에 여기서는 정리하지 않았습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 본격적으로 제가 궁금했던 Save, Find.. 등등 메서드의 동작이 어떻게 되는지 확인해 보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Entity를 Save 할 때 내부에서는 어떻게 동작을 할까?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;(*해당파트는 스프링데이터 JPA을 사용한다는 전제로 설명드리겠습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA는 엔티티를 저장할 때 데이터베이스에 해당 엔티티가 있는지 없는지 어떻게 알고 insert와 update를 할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부에 어떻게 코드로 구현되어 있길래 궁금해서 찾아보게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 설명한 대로 JpaRepository는 다양한 인터페이스를 확장한 인터페이스입니다.&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-filename=&quot;스크린샷 2023-03-11 오후 4.51.17.png&quot; data-origin-width=&quot;553&quot; data-origin-height=&quot;31&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zvhSF/btr3bevOSxH/vrdGBGINjiyQIIfsSAk4o1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zvhSF/btr3bevOSxH/vrdGBGINjiyQIIfsSAk4o1/img.png&quot; data-alt=&quot;example&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zvhSF/btr3bevOSxH/vrdGBGINjiyQIIfsSAk4o1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzvhSF%2Fbtr3bevOSxH%2FvrdGBGINjiyQIIfsSAk4o1%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;553&quot; height=&quot;31&quot; data-filename=&quot;스크린샷 2023-03-11 오후 4.51.17.png&quot; data-origin-width=&quot;553&quot; data-origin-height=&quot;31&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;example&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 6.19.53.png&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA0jAx/btr3ezZIXAk/TlgxmKoeh47fkgquRQoPy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA0jAx/btr3ezZIXAk/TlgxmKoeh47fkgquRQoPy0/img.png&quot; data-alt=&quot;example&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA0jAx/btr3ezZIXAk/TlgxmKoeh47fkgquRQoPy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA0jAx%2Fbtr3ezZIXAk%2FTlgxmKoeh47fkgquRQoPy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;943&quot; height=&quot;316&quot; data-filename=&quot;스크린샷 2023-03-11 오후 6.19.53.png&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;example&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;JpaRepository를 확장하여 사용하면 구현 클래스 없이 인터페이스만 작성해도 쉽게 개발이 가능해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 구현체는 스프링 데이터 JPA 가 생성을 해서 주입을 해주게 된다고 하는데 그 구현체가 무엇인지 확인해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 4.57.18.png&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsmR58/btr3cbMkj94/ekEQ3Ov7jh1ejeoJgNGJYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsmR58/btr3cbMkj94/ekEQ3Ov7jh1ejeoJgNGJYK/img.png&quot; data-alt=&quot;CrudRepository Interface&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsmR58/btr3cbMkj94/ekEQ3Ov7jh1ejeoJgNGJYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsmR58%2Fbtr3cbMkj94%2FekEQ3Ov7jh1ejeoJgNGJYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;657&quot; height=&quot;206&quot; data-filename=&quot;스크린샷 2023-03-11 오후 4.57.18.png&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;206&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CrudRepository Interface&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;제가 만든 repository의 save 메서드를 들어가 보니 전에 설명한 CrudRepository 인터페이스가 보입니다 왼쪽 화살표를 눌러 구현체를 확인해 보면 아래와 같이 두 가지가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 4.58.36.png&quot; data-origin-width=&quot;1467&quot; data-origin-height=&quot;67&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YvKkK/btr3kx7VedK/VURPaLIb156Ct2OxRKWBKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YvKkK/btr3kx7VedK/VURPaLIb156Ct2OxRKWBKK/img.png&quot; data-alt=&quot;CrudRepository Interface - save 구현체 목록&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YvKkK/btr3kx7VedK/VURPaLIb156Ct2OxRKWBKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYvKkK%2Fbtr3kx7VedK%2FVURPaLIb156Ct2OxRKWBKK%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;1467&quot; height=&quot;67&quot; data-filename=&quot;스크린샷 2023-03-11 오후 4.58.36.png&quot; data-origin-width=&quot;1467&quot; data-origin-height=&quot;67&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CrudRepository Interface - save 구현체 목록&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.01.09.png&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;82&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btFi0e/btr3dTKT98R/ee75qDQBbG7DIyscWhWEV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btFi0e/btr3dTKT98R/ee75qDQBbG7DIyscWhWEV0/img.png&quot; data-alt=&quot;Debugger 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btFi0e/btr3dTKT98R/ee75qDQBbG7DIyscWhWEV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtFi0e%2Fbtr3dTKT98R%2Fee75qDQBbG7DIyscWhWEV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;770&quot; height=&quot;82&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.01.09.png&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;82&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Debugger 화면&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;실제 User를 Save 할 때 디버깅을 화면의 스택을 보면 SimpleJpaRepository를 사용하고 있습니다. 따라서 해당 클래스로 가서 확인해 보겠습니다.&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-filename=&quot;스크린샷 2023-03-11 오후 5.03.16.png&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brizdn/btr3cCwdvO3/HcXnPKDKQWWVkJgV7ZKAvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brizdn/btr3cCwdvO3/HcXnPKDKQWWVkJgV7ZKAvk/img.png&quot; data-alt=&quot;SimpleJpaRepository class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brizdn/btr3cCwdvO3/HcXnPKDKQWWVkJgV7ZKAvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbrizdn%2Fbtr3cCwdvO3%2FHcXnPKDKQWWVkJgV7ZKAvk%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;708&quot; height=&quot;385&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.03.16.png&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SimpleJpaRepository class&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;JPA가 Entity에 대하여 insert와 update를 알아서 해주는 답이 여기에 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;isNew 메서드를 통해 Entity가&amp;nbsp; 존재하는지 안 하는지 체크하여 persist를 할지 merge 구현되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 isNew 메서드는 어떻게 Entity를 체크할까요? 계속해서 디버깅을 해보았습니다.&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-filename=&quot;스크린샷 2023-03-11 오후 5.09.54.png&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;337&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/so53L/btr3dE1mKKd/0CczzHAfbk4wrzI5x8gskK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/so53L/btr3dE1mKKd/0CczzHAfbk4wrzI5x8gskK/img.png&quot; data-alt=&quot;AbstractEntityInformation class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/so53L/btr3dE1mKKd/0CczzHAfbk4wrzI5x8gskK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fso53L%2Fbtr3dE1mKKd%2F0CczzHAfbk4wrzI5x8gskK%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;791&quot; height=&quot;337&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.09.54.png&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;337&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AbstractEntityInformation class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;isNew의 메서드는&lt;/b&gt; &lt;b&gt;Entity의 Id를 확인하여 Null or 0 인지 판단&lt;/b&gt;합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Entity의 ID가 Null 또는 0이라면 새로 만들어진 엔티티 이기 때문에 em.persist를 하게 되는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 조회를 하여 변경을 했다면 해당 엔티티에는 getID를 했을 때 ID 가 있으니까 merge를 하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;persist가 된다면 내부 이벤트를 발행하여 JPA의 구현체 Hibernate 가 처리하게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 어떻게 처리되는지 보여드리겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.17.31.png&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;113&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cG1JeP/btr3gOa5rfr/8TjJNqSuUbt4REIGN2tUDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cG1JeP/btr3gOa5rfr/8TjJNqSuUbt4REIGN2tUDk/img.png&quot; data-alt=&quot;SessionImpl class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cG1JeP/btr3gOa5rfr/8TjJNqSuUbt4REIGN2tUDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcG1JeP%2Fbtr3gOa5rfr%2F8TjJNqSuUbt4REIGN2tUDk%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;654&quot; height=&quot;113&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.17.31.png&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;113&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SessionImpl class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.19.21.png&quot; data-origin-width=&quot;981&quot; data-origin-height=&quot;161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbzKwS/btr3ee2q3xx/PWIEJYIewQjh2lfpn7xgSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbzKwS/btr3ee2q3xx/PWIEJYIewQjh2lfpn7xgSk/img.png&quot; data-alt=&quot;SessionImpl class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbzKwS/btr3ee2q3xx/PWIEJYIewQjh2lfpn7xgSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbzKwS%2Fbtr3ee2q3xx%2FPWIEJYIewQjh2lfpn7xgSk%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;981&quot; height=&quot;161&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.19.21.png&quot; data-origin-width=&quot;981&quot; data-origin-height=&quot;161&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SessionImpl class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트를 수신하는 측에서는 아래와 같이 엔티티의 상태를 체크하여 각각의 상태에 맞는 메서드를 호출하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;새로운 엔티티니까 상태는 TRANSIENT&lt;/b&gt; 입니다. ( &lt;span style=&quot;background-color: #fcfcfc; color: #333333; text-align: left;&quot;&gt;영속 상태가 아님, 어떤 세션과도 연결되지 않음 )&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.23.35.png&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;676&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o00RC/btr3kxfOQx4/jkILKFkj5YMQsq1kdBd830/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o00RC/btr3kxfOQx4/jkILKFkj5YMQsq1kdBd830/img.png&quot; data-alt=&quot;DefaultPersistEventListener class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o00RC/btr3kxfOQx4/jkILKFkj5YMQsq1kdBd830/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo00RC%2Fbtr3kxfOQx4%2FjkILKFkj5YMQsq1kdBd830%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;847&quot; height=&quot;676&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.23.35.png&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;676&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DefaultPersistEventListener class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.26.58.png&quot; data-origin-width=&quot;911&quot; data-origin-height=&quot;318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSkr7G/btr3ex8D3En/gO9LdKZ5KV5T5g8r5cZtQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSkr7G/btr3ex8D3En/gO9LdKZ5KV5T5g8r5cZtQK/img.png&quot; data-alt=&quot;DefaultPersistEventListener class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSkr7G/btr3ex8D3En/gO9LdKZ5KV5T5g8r5cZtQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSkr7G%2Fbtr3ex8D3En%2FgO9LdKZ5KV5T5g8r5cZtQK%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;911&quot; height=&quot;318&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.26.58.png&quot; data-origin-width=&quot;911&quot; data-origin-height=&quot;318&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DefaultPersistEventListener class&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;엔티티의 ID를 생성하여 저장합니다. 그 후에 이제 ActionQueue(쓰기지연저장소)에 쿼리를 저장을 하고 PersistContext에 엔티티를 등록합니다.&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-filename=&quot;스크린샷 2023-03-11 오후 5.31.41.png&quot; data-origin-width=&quot;896&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDUCJT/btr3eA5oxgP/s4suO3NH37KyTFBPjFsDs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDUCJT/btr3eA5oxgP/s4suO3NH37KyTFBPjFsDs0/img.png&quot; data-alt=&quot;AbstractSaveEventListener class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDUCJT/btr3eA5oxgP/s4suO3NH37KyTFBPjFsDs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDUCJT%2Fbtr3eA5oxgP%2Fs4suO3NH37KyTFBPjFsDs0%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;896&quot; height=&quot;532&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.31.41.png&quot; data-origin-width=&quot;896&quot; data-origin-height=&quot;532&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AbstractSaveEventListener class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.32.22.png&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckqGNy/btr3c2IcWZ4/ZMRGgtKN7aN5cEEP4Ri7T1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckqGNy/btr3c2IcWZ4/ZMRGgtKN7aN5cEEP4Ri7T1/img.png&quot; data-alt=&quot;ActionQueue class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckqGNy/btr3c2IcWZ4/ZMRGgtKN7aN5cEEP4Ri7T1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckqGNy%2Fbtr3c2IcWZ4%2FZMRGgtKN7aN5cEEP4Ri7T1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;854&quot; height=&quot;152&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.32.22.png&quot; data-origin-width=&quot;854&quot; data-origin-height=&quot;152&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ActionQueue class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.33.30.png&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;274&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SLKlr/btr3dTYrQfL/fSvMFIUFwgGvN2cUUECvTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SLKlr/btr3dTYrQfL/fSvMFIUFwgGvN2cUUECvTK/img.png&quot; data-alt=&quot;ActionQueue class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SLKlr/btr3dTYrQfL/fSvMFIUFwgGvN2cUUECvTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSLKlr%2Fbtr3dTYrQfL%2FfSvMFIUFwgGvN2cUUECvTK%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;1036&quot; height=&quot;274&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.33.30.png&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;274&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ActionQueue class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.33.55.png&quot; data-origin-width=&quot;767&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1C3a9/btr3cKucrbF/F2ruUmrZxakV8Bu4MLJwlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1C3a9/btr3cKucrbF/F2ruUmrZxakV8Bu4MLJwlK/img.png&quot; data-alt=&quot;ActionQueue Class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1C3a9/btr3cKucrbF/F2ruUmrZxakV8Bu4MLJwlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1C3a9%2Fbtr3cKucrbF%2FF2ruUmrZxakV8Bu4MLJwlK%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;767&quot; height=&quot;297&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.33.55.png&quot; data-origin-width=&quot;767&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ActionQueue Class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.34.42.png&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UK45B/btr3ftrpuKD/qZiBcpPWxdw7jpKhyEKnmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UK45B/btr3ftrpuKD/qZiBcpPWxdw7jpKhyEKnmk/img.png&quot; data-alt=&quot;AbstractEntityInsertAction class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UK45B/btr3ftrpuKD/qZiBcpPWxdw7jpKhyEKnmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUK45B%2Fbtr3ftrpuKD%2FqZiBcpPWxdw7jpKhyEKnmk%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;683&quot; height=&quot;374&quot; data-filename=&quot;스크린샷 2023-03-11 오후 5.34.42.png&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AbstractEntityInsertAction class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 6.17.03.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bk4mB5/btr3ef1mAyr/RK0BL7ERbN6bxkKIs8iufk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bk4mB5/btr3ef1mAyr/RK0BL7ERbN6bxkKIs8iufk/img.png&quot; data-alt=&quot;StatefulPersistenceContext class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bk4mB5/btr3ef1mAyr/RK0BL7ERbN6bxkKIs8iufk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbk4mB5%2Fbtr3ef1mAyr%2FRK0BL7ERbN6bxkKIs8iufk%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;263&quot; data-filename=&quot;스크린샷 2023-03-11 오후 6.17.03.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;StatefulPersistenceContext class&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-11 오후 6.16.36.png&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buNkvn/btr3bnTOGvq/9Hn2vQmVv9fa3Efc9JaXpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buNkvn/btr3bnTOGvq/9Hn2vQmVv9fa3Efc9JaXpk/img.png&quot; data-alt=&quot;StatefulPersistenceContext class&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buNkvn/btr3bnTOGvq/9Hn2vQmVv9fa3Efc9JaXpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuNkvn%2Fbtr3bnTOGvq%2F9Hn2vQmVv9fa3Efc9JaXpk%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;811&quot; height=&quot;135&quot; data-filename=&quot;스크린샷 2023-03-11 오후 6.16.36.png&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;StatefulPersistenceContext class&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;이렇게 해서 save를 호출하면 PersistContext에 Entity가 등록되는 하나의 과정을 보았습니다.&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; flush 가 일어나게 되면 쿼리를 데이터베이스로 날리게 되는데 이 과정은 따로 flush 파트에서 설명하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1편을 마치며&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무래도 내부코드의 동작과정을 보여드리다 보니 설명이 부족한 점이 있었는데 내용을 좀 더 보충하도록 하겠습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분량이 많아서 나머지 파트는 Find, Clear, Flush 할 때 내부에서 어떻게 동작하는지는 2편을 제작하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부족하고, 정말 긴 글 읽어주셔서 감사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;댓글로 편하게 피드백을 주신다면 빠르게 반영하도록 하겠습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Contact : audrn6689@gmail.com&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[참고]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;자바 ORM 표준 JPA 프로그래밍 - 김영한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; 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>스프링</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/132</guid>
      <comments>https://dding9code.tistory.com/132#entry132comment</comments>
      <pubDate>Tue, 14 Mar 2023 16:24:47 +0900</pubDate>
    </item>
    <item>
      <title>코딩테스트 공부를 막 준비, 시작하시는 분 들에게..</title>
      <link>https://dding9code.tistory.com/130</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;*매우 주관적인 견해임을 밝힙니다. 정답은 없으니까...&lt;/b&gt;&lt;/u&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;안녕하세요. F-lab에서 오프라인으로 코딩테스트 스터디를 진행하면서 다른 분들보다 조금이라도 문제를 많이 푼 경험이 있어, 삽질을 한 경험을 공유드려 이제 막 &lt;b&gt;코테, 언어, 자료구조 공부를 시작하시는 분들에게&lt;/b&gt; 조금이나마 저와 같은 실수를 하지 않기를 바라는 마음에 글을 작성하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/puMOo/btrYSpT3h0o/muigYm58LSDI4EF5wpKLDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/puMOo/btrYSpT3h0o/muigYm58LSDI4EF5wpKLDK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1145&quot; data-origin-height=&quot;368&quot; data-filename=&quot;스크린샷 2023-02-10 오후 3.08.37.png&quot; width=&quot;788&quot; height=&quot;253&quot; style=&quot;width: 60.0852%; margin-right: 10px;&quot; data-widthpercent=&quot;60.79&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/puMOo/btrYSpT3h0o/muigYm58LSDI4EF5wpKLDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpuMOo%2FbtrYSpT3h0o%2FmuigYm58LSDI4EF5wpKLDK%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;1145&quot; height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/loQEs/btrYRgDFqpK/lviIgElDgZt7Eo5VyGp2Z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/loQEs/btrYRgDFqpK/lviIgElDgZt7Eo5VyGp2Z1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;299&quot; data-origin-height=&quot;149&quot; data-filename=&quot;스크린샷 2023-02-10 오후 3.16.00.png&quot; style=&quot;width: 38.752%;&quot; data-widthpercent=&quot;39.21&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/loQEs/btrYRgDFqpK/lviIgElDgZt7Eo5VyGp2Z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FloQEs%2FbtrYRgDFqpK%2FlviIgElDgZt7Eo5VyGp2Z1%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;299&quot; height=&quot;149&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;백준 // 프로그래머스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준과 프로그래머스 문제를 합쳐 700문제 가까이 풀었습니다. 정말 많이 푼 것 같지만 저는 작년에 카카오 공채, 소마 2 차코테, 이베이 등등 수많은 코테에 떨어진 경험이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q) 왜 떨어졌을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A) 문제만 많이 풀면 될 줄 알았고, &lt;b&gt;알고리즘의 원리&lt;/b&gt;나 &lt;b&gt;자료구조&lt;/b&gt;에 대해 정확히 파악을 하지 못하고 &lt;b&gt;무작정 생각과 동시에 코드를 작성&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;그러면 코테 공부 어떻게 해야 하면 좋을까?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 하나를 예시로 들면서 설명을 해드리겠습니다. 문제를 읽어보고 어떻게 풀지 잠깐 생각을 해보시면 좋을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-10 오후 3.27.42.png&quot; data-origin-width=&quot;1159&quot; data-origin-height=&quot;172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FaKC4/btrYRQqUExK/q33Lto7FSUfzb5blUHkqqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FaKC4/btrYRQqUExK/q33Lto7FSUfzb5blUHkqqk/img.png&quot; data-alt=&quot;백준 1697 - 숨바꼭질&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FaKC4/btrYRQqUExK/q33Lto7FSUfzb5blUHkqqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFaKC4%2FbtrYRQqUExK%2Fq33Lto7FSUfzb5blUHkqqk%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;988&quot; height=&quot;147&quot; data-filename=&quot;스크린샷 2023-02-10 오후 3.27.42.png&quot; data-origin-width=&quot;1159&quot; data-origin-height=&quot;172&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;백준 1697 - 숨바꼭질&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각을 해보셨을테니까 여러분들은 이 문제를 어떻게 풀려고 하셨나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글을 읽고 계시니까 머릿속으로만 생각을 하셨을 것 같습니다. 그 생각들을 노트에 적으면서 풀려고 많이 노력하셨나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 하지 않으셨다면 코드작성보다 먼저 노트에 본인의 생각을 정리하면서 &lt;b&gt;1. 논리적인 흐름을 완성하려고&lt;/b&gt; 시도해 보세요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 같으면 노트에 아래와 같이 표현을 했을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 전에 제한사항으로 &lt;b&gt;N, K 가 최대 10만&lt;/b&gt;으로 주어졌으니 &lt;b&gt;2중&amp;nbsp;for 문으로 접근하는 논리는 배제&lt;/b&gt;하고 생각을 해볼 수 있겠네요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(10만 * 10만) = O(100억) 이 되므로 10초가 걸리는 연산이 되어버리겠네요.&amp;nbsp; O(1억) = 1초 라고 생각하면 될 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-10 오후 3.44.20.png&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;639&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D254C/btrYSrj8ad9/EpVKhVMmPQ9eent9RfVh20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D254C/btrYSrj8ad9/EpVKhVMmPQ9eent9RfVh20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D254C/btrYSrj8ad9/EpVKhVMmPQ9eent9RfVh20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD254C%2FbtrYSrj8ad9%2FEpVKhVMmPQ9eent9RfVh20%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;605&quot; height=&quot;530&quot; data-filename=&quot;스크린샷 2023-02-10 오후 3.44.20.png&quot; data-origin-width=&quot;730&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;그림을 보면 &lt;b&gt;그래프의 모양&lt;/b&gt;이 그려졌습니다. 그렇다면 여기서 어떤 알고리즘을 써야 할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동생의 위치를 탐색해야 하니까 &quot;&lt;b&gt;그래프 탐색을 위한&quot; 알고리즘 BFS/ DFS를&lt;/b&gt; 생각해 볼 수 있을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 DFS로 탐색을 해본다고 가정을 하면 맨 위 3초에서 동생의 위치를 찾겠지만 해당 지점이 최단임을 보장하지는 못할 것 같습니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 BFS로 탐색을 한다면 2초에 동생의 위치를 찾게 되고 해당 지점이 가장 빨리 찾는 지점이 될 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리적 흐름이 완성되었으니 &lt;b&gt;2. 어떤 자료구조가 필요할까요?&lt;/b&gt; &lt;b&gt;BFS는 보통&lt;/b&gt; &lt;b&gt;선입선출 방식인 Queue 자료구조를 사용&lt;/b&gt;하니까 해당 방법으로 구현하게 되면 자연스럽게 먼저 들어온 것이 먼저 나가게 되니까, 가까운 지점부터 탐색을 하게 되겠네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 시간복잡도를 계산&lt;/b&gt;을 하면 문제에 주어진 제한시간 2초라서&amp;nbsp; O(N * 3 [방향])으로&amp;nbsp; O(30만)이라서 안정적으로 풀 수 있을 것 같습니다. 이제 &lt;b&gt;4. 코드를 작성&lt;/b&gt;하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리해 보면&lt;b&gt; &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 논리적 흐름 완성하기 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 필요한 알고리즘, 자료구조 선택 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 시간복잡도 계산 (검증)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흐름이 완성되지 않고 잘못된 방법으로 코드를 먼저 구현을 한다면, 그 코드가 제대로 통과되지 못할 경우에 잘못된 방법으로 짠 코드만 바라보게 되어 시야가 좁아져 다른 방법을 떠올리기 되게 어려울 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 BFS/DFS 의 예시로 들었는데 모든 문제에 해당 방법을 적용 시킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 알고리즘의 이론을 처음 공부할때 해당 &lt;b&gt;알고리즘의 원리&lt;/b&gt;가 무엇인지, &lt;b&gt;어떤상황에 쓰이는지&lt;/b&gt; 정확히 숙지를 한다면 논리적흐름을 완성하는데 정말 많은 도움이 될 것입니다. 이론이 지루하다면 먼저 해당 알고리즘의 기본문제 3개정도 풀어보면 감을 숙지하기 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 이 방법대로 연습을 하게되면 코드작성을 늦게해서 문제를 풀지 못하는게 아닌가? 라고 생각이 들수있습니다. 사실 논리적 흐름이 완성되고 검증되면 코드 구현은 얼마 걸리지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 위의 흐름대로 연습을 해보는 것을 적극 권장 드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;자료구조 공부, 언어 공부는 코테 공부하면서 같이 할 수 없을까?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 말하는 공부방법은 처음에는 &lt;b&gt;정말 시간이 오래 걸리는 공부방법&lt;/b&gt;이지만 &lt;b&gt;기억 속에 많이 남게 되는 공부방법&lt;/b&gt;이라 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시를 하나 가져오겠습니다. 코딩테스트를 풀다 보면 정렬을 정말 많이 사용합니다.&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;Arrays.sort();
Collections.sort();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 두 정렬방법의 차이를 알고 계신가요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 생각하면 배열과 컬렉션의 차이라고 생각할 수 있을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;틀린 대답은 아니지만, 어떤 방법으로 구현되어 정렬이 되고 시간복잡도는 얼마나 나오는지 궁금하지는 않으셨나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 많이 푸는 것도 좋지만, 더 나아가서 꼬리를 무는 생각을 하는 과정도 중요하다고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-10 오후 4.16.02.png&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;193&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XGtPF/btrYPAXaxMp/rKgdJJ5Z0TDl2PkDatsx10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XGtPF/btrYPAXaxMp/rKgdJJ5Z0TDl2PkDatsx10/img.png&quot; data-alt=&quot;Arrays클래스의 sort 메서드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XGtPF/btrYPAXaxMp/rKgdJJ5Z0TDl2PkDatsx10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXGtPF%2FbtrYPAXaxMp%2FrKgdJJ5Z0TDl2PkDatsx10%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;643&quot; height=&quot;193&quot; data-filename=&quot;스크린샷 2023-02-10 오후 4.16.02.png&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;193&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Arrays클래스의 sort 메서드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부를 보면 Dual-Pivot Quicksort 를 사용한다고 적혀있습니다. 모든 데이터 셋에서 O(n log(n)) 을 보장하기 때문이라고 적혀있습니다.&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;[꼬리] 그렇다면 왜 Quicksort 를 사용하지 않은 이유는 무엇일까? &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; Quicksort 는 최악에 상황에서 O(n^2)의 성능을 내기 때문에 Dual-Pivot Quciksort 보다 좋지 못합니다.&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;[꼬리] 그럼 Collection.sort() 도 내부적으로 QuickSort 를 사용할까?&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 직접 확인을 하러 가겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-10 오후 4.32.31.png&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;69&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbgElN/btrYRSbsniq/JvoRMLK0G5x0uaOhYhz9IK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbgElN/btrYRSbsniq/JvoRMLK0G5x0uaOhYhz9IK/img.png&quot; data-alt=&quot;Collection.sort()&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbgElN/btrYRSbsniq/JvoRMLK0G5x0uaOhYhz9IK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbgElN%2FbtrYRSbsniq%2FJvoRMLK0G5x0uaOhYhz9IK%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;703&quot; height=&quot;69&quot; data-filename=&quot;스크린샷 2023-02-10 오후 4.32.31.png&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;69&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Collection.sort()&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 내부적으로 list.sort를 사용하여 구현하고 있습니다. 들어가 보겠습니다.&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;스크린샷 2023-02-10 오후 4.34.05.png&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;741&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WBADZ/btrYMXE9bXo/H95VBFIs6rgZoDYEXS3Es0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WBADZ/btrYMXE9bXo/H95VBFIs6rgZoDYEXS3Es0/img.png&quot; data-alt=&quot;List 인터페이스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WBADZ/btrYMXE9bXo/H95VBFIs6rgZoDYEXS3Es0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWBADZ%2FbtrYMXE9bXo%2FH95VBFIs6rgZoDYEXS3Es0%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;702&quot; height=&quot;741&quot; data-filename=&quot;스크린샷 2023-02-10 오후 4.34.05.png&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;741&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;List 인터페이스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; List에서 제공하는 default 메서드 sort를 보니 TimSort를 사용한다고 적혀있습니다.&lt;/p&gt;
&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;[꼬리] 그렇다면 왜 Collection 은 Dual-pivot quick sort 를 사용하지 않았을까? TimSort는 무엇일까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; Dual-pivot quick sort는 primitive data types(int, doulbe) 에 적합하고 효율적이기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;반면 Timsort는 Merge sort와 insertion sort를 합친 정렬 알고리즘으로 &lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;정렬되는 데이터의 특성에 맞게 조정하여 최적의 성능을 제공할 수 있습니다. 최악의 경우 O(n log(n)) 을 보장하는 알고리즘입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;[꼬리] Timsort는 어떤 점이 좋을까?&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;-&amp;gt; &lt;a href=&quot;https://d2.naver.com/helloworld/0315536&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;네이버 D2 발표자료를&lt;/a&gt; 참고하면 CPU의 참조지역성(&lt;span style=&quot;color: #555555;&quot;&gt;Locality of reference)&lt;/span&gt; 원리를 잘 만족하도록 구현이 되어 있음을 알 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt; 땅굴을 파면서 오다보니 운영체제 까지 도달했습니다. 평소 CS에 흥미를 느끼지 못했다면 이런 부분에서 흥미를 느낄 수 있지 않을까요.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;[꼬리] 돌아와서 Sort 메서드를 보니 Comparator를 매개변수로 받는데 Comparator는 뭘까?&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-10 오후 4.46.44.png&quot; data-origin-width=&quot;275&quot; data-origin-height=&quot;48&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doD5Mh/btrYRkl2Ggg/Fh4WGXxk8kBpqjn36234Z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doD5Mh/btrYRkl2Ggg/Fh4WGXxk8kBpqjn36234Z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doD5Mh/btrYRkl2Ggg/Fh4WGXxk8kBpqjn36234Z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoD5Mh%2FbtrYRkl2Ggg%2FFh4WGXxk8kBpqjn36234Z1%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;275&quot; height=&quot;48&quot; data-filename=&quot;스크린샷 2023-02-10 오후 4.46.44.png&quot; data-origin-width=&quot;275&quot; data-origin-height=&quot;48&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;-&amp;gt; 함수형 인터페이스로 &lt;b&gt;1개의 추상메서드&lt;/b&gt;를 갖는 인터페이스를 지칭합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[꼬리] 1개의 추상메서드를 갖는다고 했는데 스크롤을 내려보니 3개의 메서드가 있습니다. 왜일까요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-10 오후 4.48.07.png&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IpvHU/btrYPDzLHC6/KWBWwGdksQ40agqvheK47k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IpvHU/btrYPDzLHC6/KWBWwGdksQ40agqvheK47k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IpvHU/btrYPDzLHC6/KWBWwGdksQ40agqvheK47k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIpvHU%2FbtrYPDzLHC6%2FKWBWwGdksQ40agqvheK47k%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;561&quot; height=&quot;371&quot; data-filename=&quot;스크린샷 2023-02-10 오후 4.48.07.png&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 해당답을 모르신다면 이 부분 부터는 직접 찾아보시면 좋을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코테를 공부&lt;/b&gt;하다 정렬에 대해서 알아보려 했는데 &lt;b&gt;스스로에게 왜? 라는 질문&lt;/b&gt;을 던져보니&lt;b&gt; CS 레벨까지 공부&lt;/b&gt; 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여태 눈으로만 공부하던것이 실제로 이렇게 활용되어 구현이 되었구나 더 흥미도 느낄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 땅굴을 파는 학습을 한다면 특정 자료구조를 선택했을 때 &lt;b&gt;어떻게 구현되어 있는지&lt;/b&gt;, &lt;b&gt;어떻게 동작하는지&lt;/b&gt; 잘 알고 있기 때문에 선택의 근거가 더 명확해질 것입니다. 코테뿐만 아니라 실제 작업할 때도 이와 같은 사고가 큰 도움이 될 거라 저는 생각을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간은 오래 걸리지만 이렇게 공부를 하면 다시 돌아와도 빠르게 익힐 수 있기 때문에, 점점 더 가속도가 붙으면서 공부를 할 수 있을 거라고 생각을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법의 단점이 있다면 정말 많은 땅굴을 파다가 적당히 끊어내기 어려울 때가 있습니다. 시간과 비용이 많이 들어가는 작업이기에 스스로 적절하게 끊는 판단하는것도 중요합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 처음 말한 것처럼 공부방법에는 답이 없다고 생각을 하며, 제가 많은 삽질과 배움을 통해 터득한 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 점들만 가져가셔서 저보다 더 좋은 학습방법을 만들어 초반에 올바른 방향으로 나아가도록 하셨으면 하는 생각에서 이 글을 작성하게 되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;긴 글을 읽어주셔서 감사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Contact : audrn6689@gmail.com&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>끄적끄적</category>
      <category>알고리즘</category>
      <category>코테공부</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/130</guid>
      <comments>https://dding9code.tistory.com/130#entry130comment</comments>
      <pubDate>Fri, 10 Feb 2023 17:07:22 +0900</pubDate>
    </item>
    <item>
      <title>[소소한 팁] 인텔리제이 Commit 창 분리 되었을때 해결 방법</title>
      <link>https://dding9code.tistory.com/123</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인텔리제이를 사용하다가 실수로 Show Diff in Separate 를 눌러서 commit change 창 이 아래와 같이 분리되었을 때&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;스크린샷 2022-11-28 오후 8.57.12.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMg3xQ/btrSm1L8dxU/eGnJE5yHorj1F5fGW9nX6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMg3xQ/btrSm1L8dxU/eGnJE5yHorj1F5fGW9nX6k/img.png&quot; data-alt=&quot;창 분리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMg3xQ/btrSm1L8dxU/eGnJE5yHorj1F5fGW9nX6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMg3xQ%2FbtrSm1L8dxU%2FeGnJE5yHorj1F5fGW9nX6k%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;245&quot; height=&quot;339&quot; data-filename=&quot;스크린샷 2022-11-28 오후 8.57.12.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;창 분리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-11-28 오후 8.57.43.png&quot; data-origin-width=&quot;1598&quot; data-origin-height=&quot;333&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byNcZj/btrSf3SItex/2tskFLlvl819nxwjb4POgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byNcZj/btrSf3SItex/2tskFLlvl819nxwjb4POgk/img.png&quot; data-alt=&quot;커밋 창과 분리가 되어 버렸다..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byNcZj/btrSf3SItex/2tskFLlvl819nxwjb4POgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyNcZj%2FbtrSf3SItex%2F2tskFLlvl819nxwjb4POgk%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;1598&quot; height=&quot;333&quot; data-filename=&quot;스크린샷 2022-11-28 오후 8.57.43.png&quot; data-origin-width=&quot;1598&quot; data-origin-height=&quot;333&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;커밋 창과 분리가 되어 버렸다..&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 인텔리제이 설정창(맥 기준 command + , )에 들어가서 Advanced Settings 에 가서 show diff 를 검색하여 해당 옵션을 키고 적용해서 다시 commit 창을 띄우면 원상복귀가 됩니다!&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;스크린샷 2022-11-28 오후 8.57.58.png&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqD2Ke/btrSmYu9M0i/k8pLdMYsOQL5ofZLZU35tK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqD2Ke/btrSmYu9M0i/k8pLdMYsOQL5ofZLZU35tK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqD2Ke/btrSmYu9M0i/k8pLdMYsOQL5ofZLZU35tK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqD2Ke%2FbtrSmYu9M0i%2Fk8pLdMYsOQL5ofZLZU35tK%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;632&quot; height=&quot;294&quot; data-filename=&quot;스크린샷 2022-11-28 오후 8.57.58.png&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;294&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상 끝!&lt;/p&gt;</description>
      <category>끄적끄적</category>
      <category>인텔리제이</category>
      <category>커밋 창 분리</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/123</guid>
      <comments>https://dding9code.tistory.com/123#entry123comment</comments>
      <pubDate>Mon, 28 Nov 2022 21:01:57 +0900</pubDate>
    </item>
    <item>
      <title>MyBatis 를 사용한 1:N 관계 조회하기</title>
      <link>https://dding9code.tistory.com/122</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;MyBatis 사용법 대부분은 공식문서에서 자세하게 설명되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 제가 프로젝트를 진행 하면서 1:N 관계 테이블에서 값을 가져오는데 발생한 문제점과 해결방법을 써보려고 합니다.&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;복잡한 연관관계 매핑&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;스크린샷 2022-10-19 오후 4.17.36.png&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;662&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCtuUH/btrO32uaUL9/HTDHqpKwu59aAQOXe8Cws0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCtuUH/btrO32uaUL9/HTDHqpKwu59aAQOXe8Cws0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCtuUH/btrO32uaUL9/HTDHqpKwu59aAQOXe8Cws0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCtuUH%2FbtrO32uaUL9%2FHTDHqpKwu59aAQOXe8Cws0%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;695&quot; height=&quot;662&quot; data-filename=&quot;스크린샷 2022-10-19 오후 4.17.36.png&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;662&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 진행하고있는 주문 도메인을 조회하는 쿼리인데 연관관계가 나름 복잡한 구문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(order - orderLineItem - orderItemOptionGroup - orderItemOption )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 결과를 가져오기 위해 어떻게 매핑을 해야할까를 공식문서와 블로그 등등 많이 찾아봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 문서에서는 내포된(Nested) Results: 조인된 결과물을 반복적으로 사용하여 내포된 결과 매핑을 사용하는 방법으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ResultMap 을 사용하도록 권장&lt;/b&gt;하고 있다. 단순히 Select 여러개 만드는 방법을 사용하게 된다면 불필요한 쿼리가 날라가게 됩니다.&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;스크린샷 2022-10-19 오후 4.21.34.png&quot; data-origin-width=&quot;1073&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OXnbu/btrO4f8bLEE/VSbXwqGY1Djd6nfizBTpl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OXnbu/btrO4f8bLEE/VSbXwqGY1Djd6nfizBTpl0/img.png&quot; data-alt=&quot;- 공식문서에 적힌 예시 -&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OXnbu/btrO4f8bLEE/VSbXwqGY1Djd6nfizBTpl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOXnbu%2FbtrO4f8bLEE%2FVSbXwqGY1Djd6nfizBTpl0%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;1073&quot; height=&quot;277&quot; data-filename=&quot;스크린샷 2022-10-19 오후 4.21.34.png&quot; data-origin-width=&quot;1073&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;- 공식문서에 적힌 예시 -&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-10-19 오후 4.24.18.png&quot; data-origin-width=&quot;1071&quot; data-origin-height=&quot;343&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wux2p/btrO4s7ksOQ/YVeLnCn2qK89TJtRjnewOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wux2p/btrO4s7ksOQ/YVeLnCn2qK89TJtRjnewOk/img.png&quot; data-alt=&quot;- 공식문서 -&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wux2p/btrO4s7ksOQ/YVeLnCn2qK89TJtRjnewOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwux2p%2FbtrO4s7ksOQ%2FYVeLnCn2qK89TJtRjnewOk%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;1071&quot; height=&quot;343&quot; data-filename=&quot;스크린샷 2022-10-19 오후 4.24.18.png&quot; data-origin-width=&quot;1071&quot; data-origin-height=&quot;343&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;- 공식문서 -&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;resultMap을 사용해야한다는 것을 인지했는데 제 프로젝트에서는 어떻게 사용했는지 보여드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두가지 방법을 사용할 수 있다는 사실을 알았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&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/bTG4lm/btrO3VJdfcf/R4YiiKBWJCwjdkpRPhh8H0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTG4lm/btrO3VJdfcf/R4YiiKBWJCwjdkpRPhh8H0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;753&quot; data-origin-height=&quot;798&quot; data-filename=&quot;스크린샷 2022-10-19 오후 4.26.36.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTG4lm/btrO3VJdfcf/R4YiiKBWJCwjdkpRPhh8H0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTG4lm%2FbtrO3VJdfcf%2FR4YiiKBWJCwjdkpRPhh8H0%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;753&quot; height=&quot;798&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rHNtw/btrO0Y1qnbi/aN4yfmya8DbaTlJK5ZgyQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rHNtw/btrO0Y1qnbi/aN4yfmya8DbaTlJK5ZgyQ0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;753&quot; data-origin-height=&quot;798&quot; data-filename=&quot;스크린샷 2022-10-19 오후 4.27.48.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rHNtw/btrO0Y1qnbi/aN4yfmya8DbaTlJK5ZgyQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrHNtw%2FbtrO0Y1qnbi%2FaN4yfmya8DbaTlJK5ZgyQ0%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;753&quot; height=&quot;798&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재사용을 위해 collection 별로 resultMap을 분리시키는 경우도 있지만 제가 진행하는 프로젝트에서 조회는 Order(Root)를 통해 이루어지므로 구현을 해서 재사용이 될 부분이 없다 생각하여 현재는 위와같은 방법으로 작성했습니다.&lt;/p&gt;
&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;&amp;lt;id/&amp;gt; 의 유무&lt;/b&gt;입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-10-19 오후 4.29.58.png&quot; data-origin-width=&quot;1044&quot; data-origin-height=&quot;45&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F5KWM/btrOFkvTKN0/MEi3OSUOZ5wqZK8DRbuEuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F5KWM/btrOFkvTKN0/MEi3OSUOZ5wqZK8DRbuEuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F5KWM/btrOFkvTKN0/MEi3OSUOZ5wqZK8DRbuEuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF5KWM%2FbtrOFkvTKN0%2FMEi3OSUOZ5wqZK8DRbuEuK%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;1044&quot; height=&quot;45&quot; data-filename=&quot;스크린샷 2022-10-19 오후 4.29.58.png&quot; data-origin-width=&quot;1044&quot; data-origin-height=&quot;45&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;공식문서에는 보통 pk 를 지정하라고 써져있습니다. 하지만 이렇게 사용하지 않고도 위의 두가지 방법 모두 매핑이 이루어져 중복된 column은 MyBatis가 처리를 해줘 하나의 객체로 반환할 수 있게 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&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 class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;id property=&quot;id&quot; column=&quot;o_id&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 구문처럼 id 를 지정하게 된다면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;select o.id AS o_id,&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;select 구문에서는 설정한 프로퍼티가 반드시 명시되어야 합니다. 그렇지 않으면 MyBatis는 중복되는 컬럼을 거르지 못하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;Toomanyresultsexception&quot;을 반환&lt;/b&gt;하게 될 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*id를 지정하지 않고 사용을 한다면 해당 구문이 빠져도 상관이 없습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트를 진행하면서 Id를 매핑하고 select 시에 id 값은 굳이 가져올 필요가 없다 생각하여 구문을 뺐는데 계속 List의 결과를 반환하여 원인을 파악하지 못했습니다.&amp;nbsp; 공식 문서와 다른 블로그를 참고해봤지만 저와 비슷한 문제에 대해 쓴 곳은 없어 직접 정리하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저와 같은 상황에 처하신 분들이 도움을 받으셨으면 좋겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;</description>
      <category>프로젝트 정리</category>
      <category>1:n select</category>
      <category>mybatis</category>
      <category>one to many</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/122</guid>
      <comments>https://dding9code.tistory.com/122#entry122comment</comments>
      <pubDate>Wed, 19 Oct 2022 16:41:21 +0900</pubDate>
    </item>
    <item>
      <title>Flyway 버전업데이트로 발생한 문제 해결</title>
      <link>https://dding9code.tistory.com/121</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Flyway 가 무엇인지, 왜&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;도입하려 했는지&lt;/span&gt;&amp;nbsp;간단하게 설명드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결 방법을 보기 원하시면 스크롤을 쭉쭉 내려주시면 됩니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Flyway 란?&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;Flyway는 데이터베이스 스키마에 대한 버전 제어를 가능하게 하는 오픈 소스 데이터베이스 마이그레이션 도구입니다. 데이터베이스 스키마는 시간이 지남에 따라 변경사항을 관리하고 데이터베이스 스키마에 적용하여 개발, 테스트 및 프로덕션과 같은 다양한 환경에서 스키마가 동기화되도록 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Flyway 의 장점&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;Flyway를 사용하면 다음과 같은 주요 이점이 있습니다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;b&gt;1. 버전 제어&lt;/b&gt;: Flyway를 사용하면 데이터베이스 스키마의 버전을 변경하고 시간 경과에 따른 변경사항을 추적할 수 있습니다. 이렇게 하면 이전 버전으로 되돌리거나 스키마가 변경된 내용을 쉽게 이해할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;b&gt;2. 반복 가능한 마이그레이션&lt;/b&gt;: Flyway는 동일한 마이그레이션 스크립트가 서로 다른 환경에서 일관되게 적용되도록 보장합니다. 이렇게 하면 불일치를 방지하고 오류 위험을 줄일 수 있습니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;b&gt;3. 자동화된 배포&lt;/b&gt;: Flyway를 빌드 및 배포 프로세스와 통합하여 데이터베이스 변경사항의 배포를 자동화할 수 있습니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;b&gt;4. 호환성&lt;/b&gt;: Flyway는 MySQL, Postgre와 같은 널리 사용되는 데이터베이스를 포함하여 광범위한 데이터베이스 관리 시스템을 지원합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-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: #fdfdfd; color: #000000;&quot;&gt;간단히 말해서 Flyway는 데이터베이스 스키마의 변경사항을 관리하는 체계적인 방법을 제공하여 시간이 지남에 따라 데이터베이스를 더 쉽게 유지관리하고 발전시킬 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-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: #fdfdfd; color: #000000;&quot;&gt;위와같은&lt;/span&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;장점 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;변경된 내역을 쉽게 파악&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;협업에 유리&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;유지보수에 좋다&lt;/b&gt;고 생각을 하여 도입을 하게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BeanCreationException 발생!?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;flyway 를 적용시키고자 자연스럽게 구글에 검색하여 블로그 글을 보며 적용을 시키고 있었습니다.&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;스크린샷 2023-02-13 오후 9.18.06.png&quot; data-origin-width=&quot;611&quot; data-origin-height=&quot;77&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tKXtL/btrZa6gFi1T/P1bSc1Ax88QAWyJEenOqHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tKXtL/btrZa6gFi1T/P1bSc1Ax88QAWyJEenOqHk/img.png&quot; data-alt=&quot;구글 검색결과로 얻은 방법&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tKXtL/btrZa6gFi1T/P1bSc1Ax88QAWyJEenOqHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtKXtL%2FbtrZa6gFi1T%2FP1bSc1Ax88QAWyJEenOqHk%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;611&quot; height=&quot;77&quot; data-filename=&quot;스크린샷 2023-02-13 오후 9.18.06.png&quot; data-origin-width=&quot;611&quot; data-origin-height=&quot;77&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;구글 검색결과로 얻은 방법&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블로그에 설명 된 대로 이렇게 의존성을 추가하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfB9bA/btrZckZuVqa/UL7wwWuLV59Pryx0n8V2k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfB9bA/btrZckZuVqa/UL7wwWuLV59Pryx0n8V2k1/img.png&quot; style=&quot;width: 49.12215022152223%;&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;59&quot; data-filename=&quot;스크린샷 2023-02-13 오후 9.18.51.png&quot; data-widthpercent=&quot;49.7&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfB9bA/btrZckZuVqa/UL7wwWuLV59Pryx0n8V2k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfB9bA%2FbtrZckZuVqa%2FUL7wwWuLV59Pryx0n8V2k1%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;363&quot; height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWeqVL/btrZc76HzEO/qYPWXoT7Lr2cYwTplcIL40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWeqVL/btrZc76HzEO/qYPWXoT7Lr2cYwTplcIL40/img.png&quot; style=&quot;width: 49.71505908080334%;&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;97&quot; data-filename=&quot;스크린샷 2023-02-13 오후 9.19.57.png&quot; data-widthpercent=&quot;50.3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWeqVL/btrZc76HzEO/qYPWXoT7Lr2cYwTplcIL40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWeqVL%2FbtrZc76HzEO%2FqYPWXoT7Lr2cYwTplcIL40%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;604&quot; height=&quot;97&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;resources 셋팅 그리고 yml 파일 작성까지하고 실행을 시켜봤습니다.&amp;nbsp; 그런데..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-13 오후 9.15.04.png&quot; data-origin-width=&quot;2437&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0i2Kp/btrY1m5X0Pz/Ly6Qxj8jt4pbK7OLDb89b1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0i2Kp/btrY1m5X0Pz/Ly6Qxj8jt4pbK7OLDb89b1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0i2Kp/btrY1m5X0Pz/Ly6Qxj8jt4pbK7OLDb89b1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0i2Kp%2FbtrY1m5X0Pz%2FLy6Qxj8jt4pbK7OLDb89b1%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;2437&quot; height=&quot;444&quot; data-filename=&quot;스크린샷 2023-02-13 오후 9.15.04.png&quot; data-origin-width=&quot;2437&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;BeanCreationException&amp;nbsp;&lt;/b&gt;이 발생을 하게 되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜일까 생각을 하다 우선 해당 에러로 검색을 해봤지만 주로 스키마 변경에 대한 에러라고 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경없이 새로 만들었는데 왜 이런 에러가 나왔을까 다시 꼼꼼히 에러코드를&amp;nbsp; 살펴보니..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-13 오후 9.25.27.png&quot; data-origin-width=&quot;1016&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0SHeu/btrZa4XrlJI/q7IeHeFkQNWzvAGnyUmcQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0SHeu/btrZa4XrlJI/q7IeHeFkQNWzvAGnyUmcQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0SHeu/btrZa4XrlJI/q7IeHeFkQNWzvAGnyUmcQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0SHeu%2FbtrZa4XrlJI%2Fq7IeHeFkQNWzvAGnyUmcQ1%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;1016&quot; height=&quot;44&quot; data-filename=&quot;스크린샷 2023-02-13 오후 9.25.27.png&quot; data-origin-width=&quot;1016&quot; data-origin-height=&quot;44&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: #fdfdfd; color: #000000;&quot;&gt;&lt;b&gt;Unsupported Database&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;즉, Mysql 8.0 에는 지원이 되지 않는다고 에러가 나옵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;하지만 공식문서에 분명 지원한다고 적혀있었는데..!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-14 오후 2.57.57.png&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;618&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xKNFV/btrZc770sx2/46zHhlKwiWwDDKIBjniNIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xKNFV/btrZc770sx2/46zHhlKwiWwDDKIBjniNIK/img.png&quot; data-alt=&quot;flyway 공식문서&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xKNFV/btrZc770sx2/46zHhlKwiWwDDKIBjniNIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxKNFV%2FbtrZc770sx2%2F46zHhlKwiWwDDKIBjniNIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;754&quot; height=&quot;618&quot; data-filename=&quot;스크린샷 2023-02-14 오후 2.57.57.png&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;618&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;flyway 공식문서&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 또 뭐가 잘못됐을까 찾아보다 버전이 업데이트 되면서 달라진 부분이 있다고 들었습니다.&lt;/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;스크린샷 2023-02-14 오후 3.01.39.png&quot; data-origin-width=&quot;753&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Tiff9/btrZc771cPt/WfJSDTpJ4WRkQCNNZqszt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Tiff9/btrZc771cPt/WfJSDTpJ4WRkQCNNZqszt0/img.png&quot; data-alt=&quot;flyway 업데이트 내역&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Tiff9/btrZc771cPt/WfJSDTpJ4WRkQCNNZqszt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTiff9%2FbtrZc771cPt%2FWfJSDTpJ4WRkQCNNZqszt0%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;753&quot; height=&quot;263&quot; data-filename=&quot;스크린샷 2023-02-14 오후 3.01.39.png&quot; data-origin-width=&quot;753&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;flyway 업데이트 내역&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 종속성이 필요하다고 설명되면서 MySQL 문서를 안내해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://flywaydb.org/documentation/database/mysql#java-usage&quot;&gt;https://flywaydb.org/documentation/database/mysql#java-usage&lt;/a&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;간단하게 정리하면 Flyway 8.2.1에서 MySQL과 MariaDB 데이터베이스 지원은 모두 별도의 집중적인 설정을 해야 합니다.&lt;br /&gt;그래서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;gradle에 의존성 부분을 'org.flywaydb:flyway-core'가 아니라 'org.flywaydb:flyway-mysql'로 설정해야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성을 바꾸니 Flyway가 정상적으로 작동을 합니다! 앞으로는 블로그 글을 믿기보다는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;공식문서 위주로 꼼꼼하게 체크&lt;/b&gt;해야 겠다는 생각이 들었습니다. 아무래도 블로그는 예전에 써져있을 경우도 있고, 업데이트를 즉각 반영하지 않으니 이런 문제가 생겨버린 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 또 직접 문제를 해결하니 앞으로도 다른 문제가 생겨도 잘 해결할 수 있을 것 같은 자신감이 듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 읽으시는 분들도 저와 같은 경험이 있으시다면 공식문서도 같이 보며 크로스체크를 하면 좋을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;[출처]&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;&amp;nbsp;&lt;a href=&quot;https://flywaydb.org/documentation/&quot;&gt;https://flywaydb.org/documentation/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>프로젝트 정리</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/121</guid>
      <comments>https://dding9code.tistory.com/121#entry121comment</comments>
      <pubDate>Thu, 1 Sep 2022 22:10:39 +0900</pubDate>
    </item>
    <item>
      <title>[HTTP] 로그아웃은 &amp;quot;GET&amp;quot; or &amp;quot;POST&amp;quot; ??</title>
      <link>https://dding9code.tistory.com/118</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트를 진행하다가 사용자의 로그아웃을 구현할 일이 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 로그아웃은 Rest 관점에서 사용자의 상태를 변경시키니까 Post가 아닌가? 라고 생각을 할 수 있지만 Rest 관점 외에서 이유를 생각해보고 찾아보니 아래와 같은 브라우저의 기능이 있습니다.&lt;/p&gt;
&lt;p data-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: #fdfdfd; color: #000000;&quot;&gt;사용자를 위해 GET 링크를 미리 가져오는 웹 가속기(&lt;/span&gt;Web Acceleration&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;)와 같은 일부 프로세스가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;- &lt;b&gt;웹 가속화&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 캐싱 및 압축과 같은 다양한 기술을 사용하여 웹 서버와 클라이언트 브라우저 간의 콘텐츠 전송 속도를 높이는 것을 말합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이러한 프리페치의 목적은 사용자가 링크를 따라가면 즉시 콘텐츠를 제공하여 페이지 로딩 시간을 단축하는 것입니다. 따라서 프로세스는 &lt;b&gt;GET 요청의 링크&lt;/b&gt;가 콘텐츠를 반환하기 위한 것이며 &lt;b&gt;상태를 변경하기 위한 것이 아니라고 가정&lt;/b&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;b&gt;만약 로그아웃을 GET 요청으로 구현하고 링크로 표시 하도록 구현을 했다면 Web Accelerators 프로세스가 페이지에서 링크를 미리 가져오려고 시도하는 동안 해당 프로세스가 사용자를 로그아웃할 시킬 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 많은 내용을 알고 싶으시다면 아래의 출처 링크를 따라가서 보시면 더 도움이 되실 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;[출처]&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.baeldung.com/logout-get-vs-post&quot;&gt;https://www.baeldung.com/logout-get-vs-post&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;a href=&quot;https://www.nginx.com/resources/glossary/web-acceleration/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.nginx.com/resources/glossary/web-acceleration/&lt;/a&gt;&lt;/p&gt;</description>
      <category>스프링</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/118</guid>
      <comments>https://dding9code.tistory.com/118#entry118comment</comments>
      <pubDate>Tue, 12 Jul 2022 01:07:32 +0900</pubDate>
    </item>
    <item>
      <title>assertJ - 공식문서 기반 간단 정리</title>
      <link>https://dding9code.tistory.com/117</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;AssertJ란??&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AssertJ는 풍부한 assertions 세트와 유용한 오류 메시지를 제공하고 테스트 코드 가독성을 향상시키며, IDE내에서 매우 쉽게 사용할 수 있도록 설계된 Java 라이브러리 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Junit5 에서 해당 라이브러리를 많이 사용합니다. 실제 Junit5 공식문서에 가면 이런 글이 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;JUnit Jupiter에서 제공하는 어설션 기능은 많은 테스트 시나리오에 충분하지만 더 많은 성능과&amp;nbsp;매처&amp;nbsp;와 같은 추가 기능 이 필요하거나 필요한 경우가 있습니다.&amp;nbsp;이러한 경우 JUnit 팀은 &lt;a href=&quot;https://joel-costigliola.github.io/assertj/&quot;&gt;AssertJ&lt;/a&gt;&amp;nbsp;,&amp;nbsp;&lt;a href=&quot;https://hamcrest.org/JavaHamcrest/&quot;&gt;Hamcrest&lt;/a&gt;&amp;nbsp;,&amp;nbsp;&lt;a href=&quot;https://truth.dev/&quot;&gt;Truth&lt;/a&gt;&amp;nbsp;등과 같은 타사 주장 라이브러리의 사용을 권장합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;지원되는 자바 버전&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AssertJ Core 3.x 에는 Java 8 이상이 필요&lt;/li&gt;
&lt;li&gt;AssertJ Core 2.x 에는 Java 7 이상이 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Maven&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657183448774&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
  &amp;lt;groupId&amp;gt;org.assertj&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;assertj-core&amp;lt;/artifactId&amp;gt;
  &amp;lt;!-- use 2.9.1 for Java 7 projects --&amp;gt;
  &amp;lt;version&amp;gt;3.23.1&amp;lt;/version&amp;gt;
  &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Gradle&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657183574966&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;testImplementation(&quot;org.assertj:assertj-core:3.23.1&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Spring을 사용하는 경우&lt;/b&gt;는 해당 의존성을 추가하면 AssertJ 가 포함되어 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1657183608566&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;testImplementation 'org.springframework.boot:spring-boot-starter-test'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Assertions 클래스 진입점 사용(Use Assertions class entry point)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657183748292&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import static org.assertj.core.api.Assertions.*;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Assertions 클래스는 AssertJ 사용을 시작하는데 필요한 유일한 클래스이며 필요한 모든 메서드를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;바로 예제를 보겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657184225268&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.*;

public class SimpleAssertionsExample {

    @Test
    void simple_assertions() {
        assertThat(&quot;Hello, Assertions! good Test&quot;) //확인할 대상
                .isNotNull() // 널이아닌가?
                .startsWith(&quot;Hello&quot;) //&quot;Hello&quot; 로 시작하는가?
                .contains(&quot;good&quot;)  // &quot;good&quot;을 포함하는가?
                .doesNotContain(&quot;Junit5&quot;) //&quot;Junit5&quot;를 포함하지않는가?
                .endsWith(&quot;Test&quot;) //&quot;Test&quot;로 끝나는가?
                .isInstanceOf(String.class); //&quot;String class&quot; 타입인가?
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AssertJ는 메서드 체이닝을 사용하여 필요한 만큼 aseertion을 연결할 수 있어 코드가 깔끔하고 하나의 문장처럼 쉽게 읽을 수 있습니다.&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;스크린샷 2022-07-07 오후 6.48.29.png&quot; data-origin-width=&quot;1854&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1p5C6/btrGKRVjMH8/8sKJTTQznbgnNZ2qoGgWSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1p5C6/btrGKRVjMH8/8sKJTTQznbgnNZ2qoGgWSk/img.png&quot; data-alt=&quot;테스트 성공&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1p5C6/btrGKRVjMH8/8sKJTTQznbgnNZ2qoGgWSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1p5C6%2FbtrGKRVjMH8%2F8sKJTTQznbgnNZ2qoGgWSk%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;780&quot; height=&quot;107&quot; data-filename=&quot;스크린샷 2022-07-07 오후 6.48.29.png&quot; data-origin-width=&quot;1854&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;테스트 성공&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 조건을 만족하여 테스트를 성공하게 되면 위와같이 아름다운 초록불이 들어오게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 실패를 하게 되면 어떻게 될까요?&lt;/p&gt;
&lt;pre id=&quot;code_1657188079866&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SimpleAssertionsExample {

    @Test
    void simple_assertions() {
        assertThat(&quot;Hello, Assertions! good Junit5 Test&quot;) // &quot;Junit5&quot; 추가
                .isNotNull()
                .startsWith(&quot;Hello&quot;)
                .contains(&quot;good&quot;)
                .doesNotContain(&quot;Junit5&quot;)
                .endsWith(&quot;Test&quot;)
                .isEqualTo(&quot;Hello, Assertions! good&quot;) //비교 문장 수정
                .isInstanceOf(String.class);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검증하려고 하는 문장에 &quot;Junit5&quot; 를 추가하였습니다.&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;스크린샷 2022-07-07 오후 7.02.03.png&quot; data-origin-width=&quot;1854&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btvZwG/btrGIJ42uP2/dbya5k1CkXLtXJaL2ckra0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btvZwG/btrGIJ42uP2/dbya5k1CkXLtXJaL2ckra0/img.png&quot; data-alt=&quot;테스트 실패&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btvZwG/btrGIJ42uP2/dbya5k1CkXLtXJaL2ckra0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtvZwG%2FbtrGIJ42uP2%2Fdbya5k1CkXLtXJaL2ckra0%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;797&quot; height=&quot;138&quot; data-filename=&quot;스크린샷 2022-07-07 오후 7.02.03.png&quot; data-origin-width=&quot;1854&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;테스트 실패&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Junit5 는 포함되지 않아야 하는데 포함되었다고 에러가 납니다! 그런데 코드를 가만 보면 &lt;b&gt;isEqualTo&lt;/b&gt; 에 적힌 문장과 본문 내용이 일치하지 않는데 위의 에러에 대한 정보는 출력하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이유는&lt;b&gt; 에러가 나게되면 그 즉시 종료&lt;/b&gt;를 하기 때문에 그 이후 검증메서드는 실행하지 않기때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예외 테스트&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1658382836211&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SimpleAssertionsExample {

    @Test
    void assertExceptionTest() {
        //exception assertion, 기본 스타일
        assertThatThrownBy(() -&amp;gt; {throw new Exception(&quot;에러&quot;);}).hasMessage(&quot;에러&quot;);

        // BDD 스타일
        Throwable thrown = catchThrowable(() -&amp;gt; {
            throw new Exception(&quot;에러!!!!!&quot;);
        });
        assertThat(thrown).hasMessageContaining(&quot;에러&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 많은 예시들이 존재하는데 간단하게만 정리를 하여 &lt;a href=&quot;https://assertj.github.io/doc/#overview-what-is-assertj&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공식문서&lt;/a&gt;를 참고하시면 더&amp;nbsp; 도움이 되실 겁니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;피해야할 AssertJ 사용법!&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&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_1657189533101&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// DON'T DO THIS ! It does not assert anything
assertThat(actual.equals(expected));&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;pre id=&quot;code_1657189557600&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// DO THIS:
assertThat(actual).isEqualTo(expected);

// OR THIS (less classy but ok):
assertThat(actual.equals(expected)).isTrue();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나쁜 사용 방법&lt;/p&gt;
&lt;pre id=&quot;code_1657189576365&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// DON'T DO THIS ! It does not assert anything and passes
assertThat(1 == 2);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 사용 방법&lt;/p&gt;
&lt;pre id=&quot;code_1657189592133&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// DO THIS: (fails as expected)
assertThat(1).isEqualTo(2);

// OR THIS (less classy but ok):
assertThat(1 == 2).isTrue();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;[참고]&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://assertj.github.io/doc/#overview-what-is-assertj&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://assertj.github.io/doc/#overview-what-is-assertj&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>스프링</category>
      <category>assertj</category>
      <category>테스트</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/117</guid>
      <comments>https://dding9code.tistory.com/117#entry117comment</comments>
      <pubDate>Fri, 8 Jul 2022 12:33:57 +0900</pubDate>
    </item>
    <item>
      <title>Builder Pattern (빌더 패턴)</title>
      <link>https://dding9code.tistory.com/116</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;빌더 패턴의 정의&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;빌더&amp;nbsp;패턴은&amp;nbsp;&quot;복잡한&amp;nbsp;객체의&amp;nbsp;구성을&amp;nbsp;해당&amp;nbsp;표현과&amp;nbsp;분리하여&amp;nbsp;동일한&amp;nbsp;구성&amp;nbsp;프로세스에서&amp;nbsp;여러&amp;nbsp;개의&amp;nbsp;다른&amp;nbsp;표현을&amp;nbsp;생성할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;하는&amp;nbsp;것&quot;을&amp;nbsp;목표로&amp;nbsp;합니다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌더 패턴은 &lt;a href=&quot;https://en.wikipedia.org/wiki/Fluent_interface&quot;&gt;fluent interface와&lt;/a&gt; 비슷해야 합니다.&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;span&gt; fluent interface는 일반적으로 람다식에서 볼 수 있듯이 method cascading(또는 method chaining)을 사용하여 구현됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*메서드 체인은 객체 지향 프로그래밍 언어에서 여러 메서드를 호출하기 위한 일반적인 구문입니다.&lt;/p&gt;
&lt;p data-ke-size=&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;method chainig example)&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656421338307&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class PersonMethodChaining {
    private String name;
    private int age;

    //해당 속성을 설정하는 부작용 외에도 setter 는 추가로 연결된 메서드 호출을 허용하기 위해 &quot;this&quot;(현재 Person 객체)를 반환
    public PersonMethodChaining setName(String name) {
        this.name = name;
        return this;
    }

    public PersonMethodChaining setAge(int age) {
        this.age = age;
        return this;
    }

    public void introduce() {
        System.out.println(&quot;내 이름은=&quot; + name + &quot;, 나이는 =&quot; + age);
    }

    public static void main(String[] args) {
        PersonMethodChaining person = new PersonMethodChaining();
        person.setName(&quot;띵구&quot;).setAge(29).introduce();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;No method chaining example )&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656422131198&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Person {
    private String name = &quot;&quot;; //필수
    private int age = 0;
    
    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void introduce() {
        System.out.println(&quot;내 이름은=&quot; + name + &quot;, 나이는 =&quot; + age);
    }

    public static void main(String[] args) {
        Person person = new Person();
        person.setName(&quot;띵구&quot;);
        person.setAge(29);
        person.introduce();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;그렇다면 빌더 패턴이 필요한 곳은 어디일까?&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 체이닝 메소드를 적용하지 않은 person 클래스를 보면 객체 하나를 만드려고 메서드를 여러 개 호출하고, 객체가 완전히 생성되기 전까지는 일관성(consistency)이 무너진 상태에 놓이게 된다. 생성자를 사용하여 미리 초기화할 값을 셋팅해도 이름만 입력하고 싶다던가 나이만 입력하고 싶을 수 있다. 또한 setter를 사용하기 때문에 final 키워드도 사용할 수 없어 불변으로 만들 수 없다.&lt;/p&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개의 값만 입력하면 되지만 셋팅해야할 값이 5개가 넘어간다면..? 그중에서도 몇 개는 사용할 때도 있고 사용 안 할 때도 있을 것이다. 이런 경우 모두 생성자를 만들게 된다면 코드 작성이 힘이 들고 가독성도 떨어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그래서 이럴 때 빌더패턴을 사용하면 된다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 클라이언트는 필요한 객체를 직접 만드는 대신, 필수 매개 변수만으로 생성자를 호출해 빌더 객체를 얻는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 빌더 객체가 제공하는 일종의 setter 메서드들로 원하는 선택 매개변수들을 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 매개변수가 없는 build 메서드를 호출하여 필요한 객체(보통은 불변)를 얻는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656424109144&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Person {
    private final String name;
    private final int age;
    private int phoneNum;
    private int height;
    private int weight;

    public static class Builder {
        //필수 매개변수
        private final String name;
        private final int age;

        //선택 매개변수
        private int phoneNum = 0;
        private int height = 0;
        private int weight = 0;

        public Builder(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public Builder phoneNum(int phoneNum) {
            this.phoneNum = phoneNum;
            return this;
        }

        public Builder height(int height) {
            this.height = height;
            return this;
        }

        public Builder weight(int weight) {
            this.weight = weight;
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }

    private Person(Builder builder) {
        name = builder.name;
        age = builder.age;
        phoneNum = builder.phoneNum;
        weight = builder.weight;
        height = builder.height;
    }


    public static void main(String[] args) {
        Person person = new Builder(&quot;띵구&quot;, 29)
		.phoneNum(010101010)
		.height(180)
                .weight(70)
                .build();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;위와 같이 만듬으로..&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1. 코드 라인의 수는 빌더 패턴에서 적어도 두 배로 증가하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;디자인 유연성과&lt;/b&gt; 훨씬 더&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;읽기 쉬운 코드&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;면에서 장점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2. 생성자에 대한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;매개변수가 줄어들고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;가독성이 높은 연결 메서드 호출로&lt;/b&gt; 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;3. build()를 사용해야 객체를 생성시키기 때문에 &lt;b&gt;완전한 상태로 인스턴스화&lt;/b&gt;가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점은&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 빌더부터 만들어야 하기 때문에 코드가 장황해진다는 단점이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&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;하지만&amp;nbsp; lombok의 @Builder라는 엄청난 어노테이션이 있습니다&lt;/b&gt;. @Builder라는 어노테이션을 사용하면 위에서 장황하게 만든 빌더를 대신 만들어 준다..!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656424763884&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import lombok.Builder;

@Builder
public class Person {
    private final String name;
    private final int age;
    private int phoneNum;
    private int height;
    private int weight;

    public static void main(String[] args) {
        Person person = Person.builder()
                .name(&quot;띵구&quot;)
                .age(29)
                .phoneNum(0121231)
                .height(180)
                .weight(70)
                .build();
                
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Builder 만 붙이면 끝!&lt;/p&gt;
&lt;p data-ke-size=&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;이펙티브 자바 중..&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 생성자나 정적 팩토리가 처리해야 할 매개변수가 많다면 빌더 패턴을 선택하는 게 더 낫다. 매개변수 중 다수가 필수가 아니거나 같은 타입이면 특히 더 그렇다. 빌더는 점층적 생성자보다 클라이언트 코드를 읽고 쓰기가 훨씬 간결하고, 자바빈즈보다 훨씬 안전하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://howtodoinjava.com/design-patterns/creational/builder-pattern-in-java/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://howtodoinjava.com/design-patterns/creational/builder-pattern-in-java/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/2872222/how-to-do-method-chaining-in-java-o-m1-m2-m3-m4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/2872222/how-to-do-method-chaining-in-java-o-m1-m2-m3-m4&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;이펙티브자바 3/E&lt;/p&gt;</description>
      <category>스프링</category>
      <category>method chaining</category>
      <category>메서드 체이닝</category>
      <category>빌더 패턴</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/116</guid>
      <comments>https://dding9code.tistory.com/116#entry116comment</comments>
      <pubDate>Tue, 28 Jun 2022 23:15:25 +0900</pubDate>
    </item>
    <item>
      <title>함수형 프로그래밍 + 람다(재정리) JAVA</title>
      <link>https://dding9code.tistory.com/115</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;함수형 프로그래밍?&lt;/b&gt;&lt;/u&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;0개 이상의 인수를 가지며, 한 개 이상의 결과를 반환해야하고, 부작용(no side effect)이 없어야 한다.&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;여기서 부작용(Side Effect)이란&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자료구조를 고치거나 필드에 값을 할당(setter 메서드 같은 생성자 이외의 초기화 동작)&lt;/li&gt;
&lt;li&gt;예외 발생&lt;/li&gt;
&lt;li&gt;파일에 쓰기 등의 I/O 동작 수행&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;u&gt;&lt;b&gt;함수형 프로그래밍의 주요 특성&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 불변(Immutable) 객체를 사용한다&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원본은 변하지 않기 때문에, 객체의 상태를 바꿀 수 없으므로 thread safe하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 참조 투명성(Referential Transparency) // Pure Function&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동시에 함수를 처리해도 사이드이펙트 없이 동일한 값 출력시킬 수 있어야한다&lt;/li&gt;
&lt;li&gt;외부의 값을 참조하지 않고 있어야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. lazy evaluation&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제로 필요로 해지는 경우에 연산을 시작&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 코드를 간결하게 해준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 불변과 에러가 없기 때문에 병렬처리하기가 좋다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;람다(lambda)&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;람다(lambda)라는 용어는 람다 미적분학 학계에서 개발한 시스템에서 유래했다.&lt;/li&gt;
&lt;li&gt;메서드를 하나의 &amp;lsquo;식(expression)&amp;rsquo;으로 표현한 것, 람다식은 함수를 간략하면서도 명확한 식으로 표현할 수 있게 해준다.&lt;/li&gt;
&lt;li&gt;익명 클래스처럼 이름이 없는 함수면서 메서드를 인수로 전달할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;한마디로 정리하는 사용하는 이유?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;익명클래스를 함수의 파라미터로 전달하게 되면 불필요한 클래스를 선언하게 되므로 함수형 인터페이스를 이용해서 구현하면 코드가 간결해지기 때문&lt;/li&gt;
&lt;/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;u&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;- 익명&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보통의 메서드와 달리 이름이 없으므로 익명이라 표현&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;- 함수&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 클래스에 종속되지 않으므로 함수라고 부른다. 하지만 메서드처럼 파라미터 리스트, 바디, 반환 형식, 가능한 예외 리스트를 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;- 전달&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;람다 표현식을 메서드 인수로 전달하거나 변수로 저장할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;- 간결성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;익명 클래스처럼 복잡하지 않고 간단하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;메서드와 함수의 차이?&lt;/b&gt;&lt;/u&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;샘플 예제 - Sample Car List&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;List&amp;lt;Car&amp;gt; carList = Arrays.asList(
                new Car(&quot;k3&quot;, 1800, GASOLINE, true),
                new Car(&quot;avante&quot;, 2300, GASOLINE, true),
                new Car(&quot;avanteN&quot;, 3100, GASOLINE, true),
                new Car(&quot;sonata&quot;, 2700, HYBRID, true),
                new Car(&quot;gv70&quot;, 6000, GASOLINE, true),
                new Car(&quot;gv70E&quot;, 6000, ELECTRIC, true),
                new Car(&quot;gv60&quot;, 7000, ELECTRIC, true),
                new Car(&quot;benzC&quot;, 6400, DIESEL, false),
                new Car(&quot;benzC&quot;, 6700, GASOLINE, false),
                new Car(&quot;g80&quot;, 8000, GASOLINE, true),
                new Car(&quot;benzE&quot;, 8700, GASOLINE, false)
        );
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;차량 정보를 담고있는 리스트가 있을 때 가격순으로 정렬을 한다면?&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 기존의 방법&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;Collections.sort(carList, new Comparator&amp;lt;Car&amp;gt;() {
            @Override
            public int compare(Car car1, Car car2) {
                return car1.getPrice() - car2.getPrice();
            }
        });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 람다식 사용&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;Collections.sort(carList, (car1, car2) -&amp;gt; car1.getPrice() - car2.getPrice());
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&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;u&gt;&lt;b&gt;람다의 구조&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 파라미터 리스트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Comparator의 compare 메서드 파라미터 (차량 두개)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 화살표&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;화살표 ( &amp;rarr; ) 는 람다의 파라미터 리스트와 바디를 구분&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 람다 바디&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 차량의 가격을 비교, 람다의 반환값에 해당하는 표현식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;람다의 장점!&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;zephir&quot;&gt;&lt;code&gt;@FunctionalInterface
public interface Predicate&amp;lt;T&amp;gt; {
    boolean test(T t);
}

public static &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; filter(List&amp;lt;T&amp;gt; list, Predicate&amp;lt;T&amp;gt; p) {
        List&amp;lt;T&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();
        for (T e : list) {
            if (p.test(e)) {
                result.add(e);
            }
        }
        return result;
	   }
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;람다와 동작 파라미터화로 &lt;b&gt;반복되는 코드를 추상화&lt;/b&gt;하고 &lt;b&gt;유연하고 간결한 코드를 구현&lt;/b&gt;할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;//차량 리스트에서 모델이 GV70 이면 리스트에 담음.
List&amp;lt;Car&amp;gt; carGV70 = filter(carList, car -&amp;gt; car.getModel() == Model.GV70);

//차량 리스트에서 모델이 avante 이면 리스트에 담음.
List&amp;lt;Car&amp;gt; carGV70 = filter(carList, car -&amp;gt; car.getModel() == Model.avante);

//차량 리스트에서 모델이 sonata 이면 리스트에 담음.
List&amp;lt;Car&amp;gt; carGV70 = filter(carList, car -&amp;gt; car.getModel() == Model.sonata);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스를 사용하지 않는다면 각각의 모델마다 filterGV70, filterAvante . . . 반복되는 메서드를 구현해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;주의사항&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 함수형 인터페이스라는 문맥에서 람다 표현식을 사용할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수형 인터페이스 라는 것은 단 하나의 추상 메서드만 존재해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- @FunctionalInterface&lt;/b&gt; 어노테이션을 사용하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수형 인터페이스 인지 컴파일 체크를 해준다.&lt;/li&gt;
&lt;li&gt;누군가 실수로 메서드를 추가하지 못하게 막아준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- **자유 변수를 사용(람다 캡쳐링)**할 때 final, 혹은 실질적으로 final로 선언된 변수와 똑같이 사용되어야 한다.&lt;/p&gt;
&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;pre class=&quot;sql&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;@FunctionalInterface
public interface Runnable {
			public abstract void run();
}

//문제 없는 코드
public class Example {

    public static void main(String[] args) {
        int num = 300; //지역변수
        Runnable r = () -&amp;gt; System.out.println(num);
        r.run();
    }
    
}

//에러 발생
public class Example {

    public static void main(String[] args) {
        int num = 300; //지역변수
        Runnable r = () -&amp;gt; System.out.println(num);
        r.run();

        num++; //&amp;lt;-- 지역변수가 바뀐다.
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-19 오후 8.29.45.png&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;106&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsLALd/btrFdfbV5gv/Usqrt49NPJp74GNdk4ob60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsLALd/btrFdfbV5gv/Usqrt49NPJp74GNdk4ob60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsLALd/btrFdfbV5gv/Usqrt49NPJp74GNdk4ob60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsLALd%2FbtrFdfbV5gv%2FUsqrt49NPJp74GNdk4ob60%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;601&quot; height=&quot;101&quot; data-filename=&quot;스크린샷 2022-06-19 오후 8.29.45.png&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;106&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;&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;&lt;u&gt;&lt;b&gt;자유 변수의 제약이 생긴 이유?&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인스턴스 변수(힙 영역)와 지역 변수(스택 영역)는 메모리에 저장되는 위치부터 다름&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다에서 지역 변수에 바로 접근할 수 있다는 가정하에 람다가 스레드에서 실행이 되면 변수를 할당한 스레드가 사라져서 변수 할당이 해제되었는데도 람다가 실행하는 스레드에서는 해당 변수에 접근하려 할 수 있습니다. 따라서 자바 구현에서는 원래 변수에 접근을 허용하는 것이 아니라 자유 지역 변수의 복사본을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;복사본의 값이 바뀌지 않아야 하므&lt;/b&gt;로 지역 변수에는 한 번만 값을 할당해야 한다는 제약이 생겼습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;람다는 이름이 없고 문서화도 못하기 때문에 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 람다를 쓰지 말아야 한다.&lt;/li&gt;
&lt;li&gt;람다식이 세 줄을 넘어가면 가독성이 심하게 나빠진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;[참고]&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;https://www.youtube.com/watch?v=V1u3aqV-qXg&amp;amp;ab_channel=SKplanetTacademy&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>자바 (ref. 자바의정석)</category>
      <category>람다</category>
      <category>함수형 프로그래밍</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/115</guid>
      <comments>https://dding9code.tistory.com/115#entry115comment</comments>
      <pubDate>Sun, 19 Jun 2022 20:31:48 +0900</pubDate>
    </item>
    <item>
      <title>L4, L7 Load Balancer</title>
      <link>https://dding9code.tistory.com/114</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;L4, L4 계층&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-12 오후 10.19.37.png&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;501&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rTLrf/btrEuqUKQlN/cqjWuFgfcfVtWYWEGQv8KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rTLrf/btrEuqUKQlN/cqjWuFgfcfVtWYWEGQv8KK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rTLrf/btrEuqUKQlN/cqjWuFgfcfVtWYWEGQv8KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrTLrf%2FbtrEuqUKQlN%2FcqjWuFgfcfVtWYWEGQv8KK%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;756&quot; height=&quot;501&quot; data-filename=&quot;스크린샷 2022-06-12 오후 10.19.37.png&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;501&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;b&gt;L7: 애플리케이션 계층&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최종 사용자에게 가장 가까운&lt;b&gt; L7은 사용자 데이터와 직접 상호 작용&lt;/b&gt;하는 유일한 계층입니다.&amp;nbsp;이메일 클라이언트, 웹 브라우저 및 기타 소프트웨어 애플리케이션은 모두 레이어 7에 의존하여 통신을 시작합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;L4: 전송 계층&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;L4는 장치, 최종 시스템 및 호스트 간의 데이터 전송 및 종단 간 통신을 처리&lt;/b&gt;합니다.&amp;nbsp;여기에는 데이터를 L3으로 보내기 전에 세션 계층에서 데이터를 분할하고 수신단에서 분할된 데이터를 세션 계층을 위한 소비 가능한 데이터로 재조립하는 작업이 포함, 오류 제어 및 흐름 제어를 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;L4 와 L7 Load balancer (스위칭 장비)&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-12 오후 10.26.37.png&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lXcJC/btrECzWFEni/xm0DndkWhy8Nhq140ckrQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lXcJC/btrECzWFEni/xm0DndkWhy8Nhq140ckrQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lXcJC/btrECzWFEni/xm0DndkWhy8Nhq140ckrQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlXcJC%2FbtrECzWFEni%2Fxm0DndkWhy8Nhq140ckrQ1%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;683&quot; height=&quot;559&quot; data-filename=&quot;스크린샷 2022-06-12 오후 10.26.37.png&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;714&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;로드밸런서&lt;/b&gt;는 트래픽을 받아서&amp;nbsp;&lt;b&gt;여러 대의 서버에 분산&lt;/b&gt;시키는 &lt;b&gt;&lt;u&gt;하드웨어&lt;/u&gt;&lt;/b&gt; 또는 &lt;u&gt;&lt;b&gt;소프트웨어&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;부하 분산에는 L4 Load Balancer와 L7 Load Balancer가 많이 사용됩니다. L4부터 Port를 다룰 수 있기 때문입니다.&lt;/li&gt;
&lt;li&gt;한 대의 서버의 각각의 포트에 여러개의 서비스들을 운영하기 위해서 L4 Layer 위에서 작동하는 Load Balancer가 필요해진 것입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;L4&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;L4 Load Balancer는&lt;b&gt;&amp;nbsp;&lt;u&gt;L4 위에서 동작&lt;/u&gt;&lt;/b&gt;하기 때문에&amp;nbsp; &lt;b&gt;&lt;u&gt;Port 를 기준&lt;/u&gt;으로&lt;/b&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;L4 Load Balancer는 단지 부하를 분산시키는 것이라면(다른 URL 이동 불가), L7 Load Balancer는 요청의 세부적인 사항을 두고 결제만 담당하는 서버, 회원가입만을 담당하는 서버 등으로 분리해서 가볍고 작은 단위로 여러 개의 서비스를 운영하고 요청을 각각의 서버에 분산할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;L7&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;L7 Load Balancer&lt;/b&gt;는 &lt;u&gt;&lt;b&gt;L7 위에서 동작&lt;/b&gt;&lt;/u&gt;하기 때문에 Port 이외에도&amp;nbsp;&lt;b&gt;URI, Payload, Http Header, Cookie&lt;/b&gt; 등의 내용을 기준으로 부하를 분산니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;즉 &lt;/span&gt;&lt;b&gt;애플리케이션레벨 자체를 컨트롤&lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt; 할 수 있습니다. 그래서 &lt;/span&gt;&lt;u style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;&lt;b&gt;콘텐츠 기반 스위칭&lt;/b&gt;&lt;/u&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;이라고도 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) user agent 로 식별하여 pc 면 pc 서버. 모바일이면 모바일 서버로 분산&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;L4, L7 비교표&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 108px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;L4&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;L7&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;계층&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Layer 4 (전송 계층)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Layer 7 (애플리케이션 계층)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;스위칭기준&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Port 번호&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Port 이외에도&amp;nbsp;&lt;/span&gt;URI, Http Header, Cookie 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 66.6666%; height: 18px; text-align: center;&quot; colspan=&quot;2&quot;&gt;스위칭, 로드밸런싱, 헬스체크&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;비용이 저렴하다.&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;더 작은 단위로 라우팅 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;섬세한 라우팅 불가(URL 파싱불가)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;패킷의 내용을 파싱하는데 비용 증가&lt;br /&gt;L4 보다 비용이 비싸다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;AWS-NLB(Network Load Balancer)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;AWS-ALB(Application Load Balancer)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;[참고]&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jaehoney.tistory.com/73&quot;&gt;https://jaehoney.tistory.com/73&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://avinetworks.com/glossary/layer-7/&quot;&gt;https://avinetworks.com/glossary/layer-7/&lt;/a&gt;&lt;/p&gt;</description>
      <category>CS</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/114</guid>
      <comments>https://dding9code.tistory.com/114#entry114comment</comments>
      <pubDate>Sun, 12 Jun 2022 22:46:42 +0900</pubDate>
    </item>
    <item>
      <title>GSLB(Global Server Load Balancing)</title>
      <link>https://dding9code.tistory.com/113</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;정의&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-11 오후 9.21.24.png&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAUe7d/btrEuxGsIRN/OkwxzPVenLKMC2q3KnpAA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAUe7d/btrEuxGsIRN/OkwxzPVenLKMC2q3KnpAA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAUe7d/btrEuxGsIRN/OkwxzPVenLKMC2q3KnpAA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAUe7d%2FbtrEuxGsIRN%2FOkwxzPVenLKMC2q3KnpAA0%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;768&quot; height=&quot;256&quot; data-filename=&quot;스크린샷 2022-06-11 오후 9.21.24.png&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;256&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;글로벌하게 분산된 서버간의 로드 밸런싱 작업으로 지리적으로 분산된 애플리케이션 서버 간에 트래픽을 효율적으로 분산&lt;/li&gt;
&lt;li&gt;즉 지리적으로 분산된 위치에 있는 서버 간 부하 분산&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;사용하는 이유?&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;성능&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 사용자 요청을 가장 가까운 서버로 전달하여 네트워크 지연 및 네트워크 문제를 최소화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;맞춤형 콘텐츠&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: GSLB를 사용하면 기업이 해당 지리적 위치 및 언어의 관련성을 위해 맞춤화된 로컬 서버에서 콘텐츠를 호스팅&lt;/li&gt;
&lt;li&gt;&lt;b&gt;재해복구&lt;/b&gt;(&lt;b&gt;D&lt;/b&gt;isater &lt;b&gt;R&lt;/b&gt;ecovery)용도로도 사용 (ex 지진으로 인한 서울서버 장애시 부산서버로 연결)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유지 관리&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 클라이언트 요청을 다른 서버로 간단히 리디렉션할 수 있으므로 데이터 센터 마이그레이션 및 업그레이드를 중단 없이 실행&lt;/li&gt;
&lt;li&gt;기존 DNS는 사용자에게 최적의 경로를 안내하지 못함, 기반 부하 분산 과 달리 L4/L7 스위치를 이용한 &amp;lsquo;&lt;b&gt;헬스체크&lt;/b&gt;&amp;rsquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-11 오후 9.21.53.png&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beZCxk/btrExHUQqXT/jUisH65fkhp1Bh3IEc6WmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beZCxk/btrExHUQqXT/jUisH65fkhp1Bh3IEc6WmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beZCxk/btrExHUQqXT/jUisH65fkhp1Bh3IEc6WmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeZCxk%2FbtrExHUQqXT%2FjUisH65fkhp1Bh3IEc6WmK%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;768&quot; height=&quot;256&quot; data-filename=&quot;스크린샷 2022-06-11 오후 9.21.53.png&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&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;국내는 땅덩어리가 좁아 RTT(Round Trip Time)가 짧기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;간단하게 알아보자 (&lt;b&gt;맥OS 기준)&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;nslookup&lt;/b&gt; 을 사용해보자&lt;/li&gt;
&lt;li&gt;-&amp;gt; 어떤 도메인을 주면 IP 주소를 반환해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-12 오후 11.00.02.png&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;844&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwRRWp/btrEDQjAryD/902PbzkVuw5ziTkRKA3Imk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwRRWp/btrEDQjAryD/902PbzkVuw5ziTkRKA3Imk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwRRWp/btrEDQjAryD/902PbzkVuw5ziTkRKA3Imk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwRRWp%2FbtrEDQjAryD%2F902PbzkVuw5ziTkRKA3Imk%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;967&quot; height=&quot;844&quot; data-filename=&quot;스크린샷 2022-06-12 오후 11.00.02.png&quot; data-origin-width=&quot;967&quot; data-origin-height=&quot;844&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네이버의 아이피를 물어보니 요청마다 다른 IP를 알려준다. 이게 GSLB의 역할이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GSLB 는 이 IP가 살아 있는지, 죽어 있는지 &lt;b&gt;실시간으로 상태를 확인하는&lt;/b&gt; &lt;b&gt;헬스 체크&lt;/b&gt;를 해서 서비스가 제공되기 어려운 상태라면 응답에서 제외시키고 정상적으로 작동하고 있는 다른 IP로 응답하게 해 &lt;b&gt;끊김 없는 서비스를 제공&lt;/b&gt;해주기 때문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다양한 로드밸런싱 기법을 수행할 수 있는 DNS&lt;/b&gt;라고 이해 하시면 될 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;[참고]&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://avinetworks.com/glossary/global-server-load-balancing-2/&quot;&gt;https://avinetworks.com/glossary/global-server-load-balancing-2/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://smashingpumpkins.tistory.com/entry/Global-server-load-balancing-GSLB-다-쓰는-이유가-있는-구성&quot;&gt;https://smashingpumpkins.tistory.com/entry/Global-server-load-balancing-GSLB-다-쓰는-이유가-있는-구성&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.naver.com/n_cloudplatform/221206343859&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://blog.naver.com/n_cloudplatform/221206343859&lt;/a&gt;&lt;/p&gt;</description>
      <category>CS</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/113</guid>
      <comments>https://dding9code.tistory.com/113#entry113comment</comments>
      <pubDate>Sat, 11 Jun 2022 21:30:05 +0900</pubDate>
    </item>
    <item>
      <title>XSS 와 CSRF</title>
      <link>https://dding9code.tistory.com/112</link>
      <description>&lt;h1&gt;&lt;b&gt;XSS&lt;/b&gt;(&lt;b&gt;Cross Site Scripting&lt;/b&gt;)&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Web Application에서 나타나는 취약점중 하나로 웹사이트 관리자가 아닌 이가 사이트에 악성 script를 삽입할 수 있는 취약점이다. 사용자의 쿠키, 세션 탈취, 비정상기능 수행등을 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;html이 &amp;lt;script&amp;gt; &amp;lt;/script&amp;gt; 를 자바스크립트라고 인식해서 실행한다.&lt;/li&gt;
&lt;li&gt;악성코드를 퍼트릴 때 많이 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다음과 같은 경우에 발생&lt;/b&gt;&lt;/p&gt;
&lt;ol 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;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;u&gt;1. Reflected XSS - non persistent&lt;/u&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;/li&gt;
&lt;li&gt;클라이언트 요청에서 전송된 악성 스크립트는 서버에 전송되고, 브라우저에서 실행되는 HTML 코드에 다시 표시, 쿼리 매개변수에 스크립트를 포함한다.&lt;/li&gt;
&lt;li&gt;반사형 XSS 공격은 피해자가 직접 스크립트를 실행하도록 유도하기 때문에 1회성 공격이라고도 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;2. Stored XSS - persistent&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공격자가 제공한 데이터가 &lt;b&gt;서버에 저장된 후 지속적&lt;/b&gt;으로 서비스를 제공하는 정상 페이지에서 다른 사용자에게 스크립트가 노출되는 기법&lt;/li&gt;
&lt;li&gt;사용자의 브라우저에서 서버에 데이터를 요청할 때마다 실행되어 지속적으로 피해 발생&lt;/li&gt;
&lt;li&gt;Stored XSS가 위험한 이유는 사용자가 링크를 클릭하도록 유인할 필요가 없다는 것&lt;/li&gt;
&lt;li&gt;더 많은 희생자를 목표로 삼지만 더 적은 리소스가 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다양한 공격 기법&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;a herf : 링크를 이용&lt;/li&gt;
&lt;li&gt;img src : 이미지 태그를 이용&lt;/li&gt;
&lt;li&gt;IFRAME 안에 스크립트를 담는 방법을 이용&lt;/li&gt;
&lt;li&gt;아스키 코드를 이용&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;u&gt;3. Dom XSS&lt;/u&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹페이지를 여는 즉시 생성되는 문서 객체 모델(Document Object Model, DOM)은 사용자가 서버와 상호 작용하지 않고도 페이지의 모든 콘텐츠에 액세스할 수 있도록 돕는 프로그래밍 인터페이스&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;피해자의 브라우저에 초점을 맞춘 것이 특징인 공격&lt;/li&gt;
&lt;li&gt;DOM 기반 XSS는 웹사이트의 코드를 조사하지 않고는 취약점을 발견할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;XSS 위험한 이유&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자의 세션 정보와 같은 민감한 데이터를 훔쳐 해커가 해당 사용자를 가장할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;관리자일 경우 웹 사이트 제어 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삽입된 스크립트를 사용하여 웹 사이트의 콘텐츠 변경이나, 브라우저를 다른 웹 페이지로 리디렉션 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;방지하려면?&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&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;User input value 제한&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;⭐&lt;b&gt;사용자의 입력은 믿을 수 없다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;유저 입력값이 한정적인 범주안에서 예측 가능하다면, 드롭다운 등을 사용하여 미리 입력될 데이터값을 통제할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;출력할 때 스크립트 제한&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;⭐사용자가 입력한 값을 그대로 출력하지 않는다.&lt;/li&gt;
&lt;li&gt;HTML ESCAPE&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Sanitize value - DB에 저장할 때&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;악성 HTML을 필터링해주는 라이브러리 사용도 가능하다.&lt;/li&gt;
&lt;li&gt;ex) lucy xss filter - naver&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스크립트 문자 필터링&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DOM 상의 텍스트를 읽을 때 html 태그를 읽는 innerHTML 사용을 지양하고, textContent 등으로 메소드를 대체한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쿠키 HttpOnly&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바스크립트에서 접근 불가(documet.cookie)&lt;/li&gt;
&lt;li&gt;HTTP 전송에만 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;CSRF&lt;/b&gt;(Cross Site Request Forgery)&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공격자가 작성해 놓은 악성스크립트 [&lt;b&gt;사이트에서 제공하는 기능을 피해자의 웹 브라우저에서 요청&lt;/b&gt;] 을 통해서 일어나는 악의 적인 공격 방식. 피해자는 공격자가 게시한 글을 읽었을 때 악성스크립트에 의한 요청이 서버로 보내지게 되고 서버는 피해자의 권한 내에서 해당 악성 스크립트 요청을 처리하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, ⭐&lt;b&gt;사용자의 의지와는 무관하게 공격자가 의도한 행위를 특정 웹사이트에 요청하게 하는 공격&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;XSS와 달리 자바스크립트를 사용할 수 없는 상황에서도 공격이 가능&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;u&gt;&lt;b&gt;공격을 위한 몇가지 조건 필요&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가 보안이 취약한 서버로부터 &lt;b&gt;이미 인증을 받은 상태&lt;/b&gt;여야 합니다.&lt;/li&gt;
&lt;li&gt;쿠키 기반으로 서버 세션 정보를 획득할 수 있어야 합니다.&lt;/li&gt;
&lt;li&gt;공격자는 서버를 공격하기 위한 요청 방법에 대해 미리 파악하고 있어야 합니다. 예상치 못한 파라미터가 있으면 불가능합니다.&lt;/li&gt;
&lt;/ol&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;u&gt;&lt;b&gt;방지하려면?&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;csrf는 다른 사이트에서 요청을 보내는 공격이기 때문에 다른 사이트에서 오는 요청을 막거나, 올바른 사이트에서 보내는지 확인하는 수단이 필요&lt;/li&gt;
&lt;li&gt;&quot;Referer&quot;등의 Header를 이용하여 경로를 검사&lt;/li&gt;
&lt;li&gt;요청 도메인과 쿠키에 설정된 도메인이 같은 경우에만 쿠키 전송 &amp;rarr; &lt;u&gt;&lt;b&gt;쿠키 값이 다른 곳으로 넘어가지 안게 한다.&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;단순한 세션 토큰만을 이용한 권한 부여 금지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;⭐&lt;u&gt;GET은 read 데이터의 변화가 없다, POST는 사용자의 명시적인 액션이 있어야 한다&lt;/u&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;u&gt;즉 GET 으로 데이터의 변화가 일어나게 설계를 하면 안된다.&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;CSRF 토큰 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&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;&lt;b&gt;!!시큐어 코딩을 잘 하자&amp;nbsp; -&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.mois.go.kr/frt/bbs/type001/commonSelectBoardArticle.do%3Bjsessionid=fr7QaTyG2gK5o02XJnYETp3havIQ1MGLKMYdWaaEe5me9IOk932SIy2BbP1AM08Z.mopwas54_servlet_engine1?bbsId=BBSMSTR_000000000012&amp;amp;nttId=42152&quot;&gt;행정안전부 시큐어코딩 가이드라는게 존재&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개발에 있어 그 누구도 믿지마라.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;철저하게 권한과 책임을 분리하자.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;[참고]&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=TDgy1LzOnIk&amp;amp;ab_channel=%EB%84%90%EB%84%90%ED%95%9C%EA%B0%9C%EB%B0%9C%EC%9E%90TV&quot;&gt;https://www.youtube.com/watch?v=TDgy1LzOnIk&amp;amp;ab_channel=%EB%84%90%EB%84%90%ED%95%9C%EA%B0%9C%EB%B0%9C%EC%9E%90TV&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://portswigger.net/web-security/cross-site-scripting&quot;&gt;https://portswigger.net/web-security/cross-site-scripting&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>스프링</category>
      <category>csrf</category>
      <category>XSS</category>
      <category>시큐어코딩</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/112</guid>
      <comments>https://dding9code.tistory.com/112#entry112comment</comments>
      <pubDate>Sun, 5 Jun 2022 20:05:11 +0900</pubDate>
    </item>
    <item>
      <title>서블릿(Servlet)</title>
      <link>https://dding9code.tistory.com/41</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서블릿(Servlet) 이란?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서블릿이란 동적인 페이지를 만들기 위해 사용되는 웹 애플리케이션 프로그램&lt;/li&gt;
&lt;li&gt;낮은 성능 및 낮은 수준의 확장성과 같은&amp;nbsp;&amp;nbsp;&lt;b&gt;CGI&lt;/b&gt;&amp;nbsp;의 한계를 해결&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;CGI (Common Gateway Interface)는 뭔가요?&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CGI 는 실제로&amp;nbsp;C&lt;/b&gt;&amp;nbsp;또는&amp;nbsp;&lt;b&gt;C++&lt;/b&gt;&amp;nbsp;와 같은 프로그래밍 언어를 사용하여 작성된 외부 응용 프로그램이며&amp;nbsp;클라이언트 요청을 처리하고 동적 콘텐츠를 생성하는 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-31 오후 10.16.56.png&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blK4EA/btrDAj3kvUI/Go1pzE4i3Vmq9yt2LoVBDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blK4EA/btrDAj3kvUI/Go1pzE4i3Vmq9yt2LoVBDK/img.png&quot; data-alt=&quot;CGI 동작 방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blK4EA/btrDAj3kvUI/Go1pzE4i3Vmq9yt2LoVBDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblK4EA%2FbtrDAj3kvUI%2FGo1pzE4i3Vmq9yt2LoVBDK%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;663&quot; height=&quot;288&quot; data-filename=&quot;스크린샷 2022-05-31 오후 10.16.56.png&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CGI 동작 방식&lt;/figcaption&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;CGI 는 이처럼 서버에서&lt;u&gt;&lt;b&gt; 모든 요청에 대한 프로세스를 만들기 때문&lt;/b&gt;&lt;/u&gt;에 많은 요청이 있을 경우 메모리에 적재하여 CPU할당을 받아 실행되는 프로세스는 서버에 부하가 많이 일어난다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이를 해결하고자 모든 새 요청에 대해 프로세스를 생성하지 않고, &lt;span data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;모든 요청을 동시에 처리하는 단일 인스턴스만 존재&lt;/span&gt;하는 &lt;span data-token-index=&quot;3&quot; data-reactroot=&quot;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-31 오후 10.17.02.png&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wgEtu/btrDERSpWi3/XcO6XpKrHWbpTcwQ3SCwuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wgEtu/btrDERSpWi3/XcO6XpKrHWbpTcwQ3SCwuk/img.png&quot; data-alt=&quot;서블릿 동작방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wgEtu/btrDERSpWi3/XcO6XpKrHWbpTcwQ3SCwuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwgEtu%2FbtrDERSpWi3%2FXcO6XpKrHWbpTcwQ3SCwuk%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;547&quot; height=&quot;283&quot; data-filename=&quot;스크린샷 2022-05-31 오후 10.17.02.png&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;283&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;서블릿 동작방식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CGI에 비해 서블릿에는 많은 장점이 있습니다&lt;/b&gt;.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 컨테이너는 서블릿에 대한 여러 요청을 처리하기 위한 스레드를 생성합니다.&lt;/li&gt;
&lt;li&gt;스레드는 공통 메모리 영역을 공유하고, 가벼우며, 스레드 간의 통신 비용이 낮다는 점에서 프로세스에 비해 많은 이점이 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;다시 돌아와 서블릿을 지원하는 WAS 를 사용하게 된다면 HTTP 요청과 응답을 직접 하나하나 파싱하여 처리를 하지 않고 의미있는 비즈니스 로직에만 집중하여 개발 할 수 있습니다.&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;제목 없음.png&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;181&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/epVVzo/btrrVotVso0/zyTyJWuwH9jvX12v9y1H60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/epVVzo/btrrVotVso0/zyTyJWuwH9jvX12v9y1H60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/epVVzo/btrrVotVso0/zyTyJWuwH9jvX12v9y1H60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FepVVzo%2FbtrrVotVso0%2FzyTyJWuwH9jvX12v9y1H60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;943&quot; height=&quot;181&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;181&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;urlPatterns(/hello) 의&amp;nbsp; URL이 호출되면 서블릿 코드가 실행됩니다.&lt;/li&gt;
&lt;li&gt;HTTP 요청 정보를 쉽게 사용할 수 있고,&amp;nbsp; 처리 결과를 쉽게 응답으로 반환 가능하다.&lt;/li&gt;
&lt;li&gt;개발자는 HTTP 스펙을 매우 편리하게 사용 할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서블릿 컨테이너와 서블릿 동작 방식&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서블릿 컨테이너는 톰캣처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d2ViDp/btrrXL9x87d/FtXOxOinrimPkPSIbSh9fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d2ViDp/btrrXL9x87d/FtXOxOinrimPkPSIbSh9fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d2ViDp/btrrXL9x87d/FtXOxOinrimPkPSIbSh9fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd2ViDp%2FbtrrXL9x87d%2FFtXOxOinrimPkPSIbSh9fk%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;745&quot; height=&quot;421&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;554&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;HTTP 요청이 들어오면 서블릿은 해당 요청과 매핑된 서블릿을 찾게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WAS는 HTTP 요청 메시지를 기반으로 Request, Response 객체를 새로 만들어서 서블릿 인스턴스가 컨테이너에 있는지 확인을 합니다. 없다면 생성을 하여 컨테이너에 스레드를 생성하고 HelloServelt을(애플리케이션 로직)을 실행하여 WAS는 Response 객체를 바탕으로 HTTP 응답 메세지를 만들어 웹 브라우저에 전달을 하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서블릿은 컨테이너는 서블릿 객체 생성, 초기화, 호출, 종료하는 &lt;u&gt;생명주기 관리&lt;/u&gt;&lt;/b&gt; 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청이 올때마다 계속 객체를 생성하는것은 비효율이기 때문에 &lt;b&gt;서블릿 객체는 &lt;u&gt;싱글톤&lt;/u&gt;으로&amp;nbsp;관리&lt;/b&gt;합니다. 최초 로딩 시점에 서블릿 객체를 미리 만들어 두고 재활용하며 &lt;b&gt;모든 요청은 동일한 서블릿 객체 인스턴스에 접근&lt;/b&gt;하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 한 요청을 처리하기전에 다른 요청이 들어오면 &lt;b&gt;동시 요청을 처리하기 위해 멀티스레드로 사용&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티 스레드는&lt;b&gt; 주의해야할 점&lt;/b&gt;이 많습니다. 요청마다 스레드를 생성하게 된다면 리소스가 허용할 때 까지 처리가 가능하지만 쓰레드의 생성 비용은 비싸고, 컨텍스트 스위칭 오버헤드가 발생하게 됩니다. 만약 제한을 두지않는다면 하드웨어의 임계점을 넘으면 서버가 죽을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYToZC/btrrUN18MIu/JwDZVN59KrvlXj1eiQuUy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYToZC/btrrUN18MIu/JwDZVN59KrvlXj1eiQuUy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYToZC/btrrUN18MIu/JwDZVN59KrvlXj1eiQuUy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYToZC%2FbtrrUN18MIu%2FJwDZVN59KrvlXj1eiQuUy0%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;643&quot; height=&quot;288&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 위와 같이 스레드를 미리 만들어 &lt;b&gt;스레드 풀에 보관하고 관리&lt;/b&gt;해야 합니다. 스레드가 필요하면 이미 생성되어 있는 스레드를 꺼내서 사용하고 종료하면 다시 스레드 풀에 반납하는 형태입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 돌아와 &lt;b&gt;요청당 서블릿을 생성하게 되면 비효율적인 부분이 있습니다.&lt;/b&gt; 멀티스레드의 관리도 어렵고, 공통 로직처리가 어렵습니다. 기능이 복잡해질수록 컨트롤러에서 공통으로 처리해야하는 부분이 점점 더 많아 질 것입니다. 그래서 먼저 &lt;b&gt;공통 기능을 처리하는 &lt;u&gt;프론트 컨트롤러 패턴&lt;/u&gt;&lt;/b&gt;을 도입하면 해결할 수 있습니다. &lt;b&gt;모든 요청을 받는 전면 컨트롤러 서블릿을 &lt;u&gt;Dispatcher Servlet&lt;/u&gt;&lt;/b&gt; 이라고 부릅니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;606&quot; data-origin-height=&quot;276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XhhnC/btrrVZnbeL0/JpmRdRcfZ7kM0ImyZHE4F1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XhhnC/btrrVZnbeL0/JpmRdRcfZ7kM0ImyZHE4F1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XhhnC/btrrVZnbeL0/JpmRdRcfZ7kM0ImyZHE4F1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXhhnC%2FbtrrVZnbeL0%2FJpmRdRcfZ7kM0ImyZHE4F1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;606&quot; height=&quot;276&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;606&quot; data-origin-height=&quot;276&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;스프링 MVC의 프론트 컨트롤러가 바로 디스패처 서블릿(DispatcherServlet)입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동작순서&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;핸들러 조회:&lt;/b&gt;&amp;nbsp;핸들러 매핑을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핸들러 어댑터 조회: &lt;/b&gt;&amp;nbsp;핸들러를 실행할 수 있는 핸들러 어댑터를 조회한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핸들러 어댑터 실행:&amp;nbsp;&lt;/b&gt;핸들러 어댑터를 실행한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핸들러 실행:&amp;nbsp;&lt;/b&gt;핸들러 어댑터가 실제 핸들러를 실행한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ModelAndView 반환:&amp;nbsp;&lt;/b&gt;핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView로 변환해서 반환한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;viewResolver 호출:&amp;nbsp;&lt;/b&gt;뷰 리졸버를 찾고 실행한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;View 반환:&amp;nbsp;&lt;/b&gt;뷰 리졸버는 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를 반환한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;뷰 렌더링:&amp;nbsp;&amp;nbsp;&lt;/b&gt;뷰를 통해서 뷰를 렌더링 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 MVC의 큰 강점은 디스패처 서블릿 코드의 변경없이, 원하는 기능을 변경하거나 확장할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조가 많이 복잡해 보이고 처리해야 할게 많아 보이지만 개발자가 실제로 처리해야하는 부분은 &lt;b&gt;핸들러(컨트롤러)에 집중&lt;/b&gt;하면 됩니다. 즉 &lt;b&gt;요청처리 로직들에게만 신경을 쓰면 됩니다.&lt;/b&gt; 나머지는 역할은 디스패처서블릿이 스프링 컨테이너로부터 주입을 받아 동작을 하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론은 개발자가 서블릿을 활용함으로서 복잡한 부분을 처리하지 않고 쉽게 요청,응답 처리를 할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;참고 - &lt;a href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;인프런 김영한 강사님&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;10분 테크톡 &lt;a href=&quot;https://www.youtube.com/watch?v=calGCwG_B4Y&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코키님&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.javatpoint.com/servlet-tutorial&quot;&gt;https://www.javatpoint.com/servlet-tutorial&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=2pBsXI01J6M&amp;amp;ab_channel=우아한Tech&quot;&gt;https://www.youtube.com/watch?v=2pBsXI01J6M&amp;amp;ab_channel=우아한Tech&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>스프링</category>
      <category>서블릿</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/41</guid>
      <comments>https://dding9code.tistory.com/41#entry41comment</comments>
      <pubDate>Tue, 31 May 2022 22:26:23 +0900</pubDate>
    </item>
    <item>
      <title>싱글톤 패턴(Singleton)</title>
      <link>https://dding9code.tistory.com/111</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정의&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체의 인스턴스가 오로지 한개만 생성되도록 설계하는 것&lt;/li&gt;
&lt;li&gt;클래스의 인스턴스화를 하나의 객체로 제한&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-26 오후 10.20.47.png&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;215&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vVTiD/btrDe95Tzej/ccBjJjHMdsSBEwKefm7hfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vVTiD/btrDe95Tzej/ccBjJjHMdsSBEwKefm7hfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vVTiD/btrDe95Tzej/ccBjJjHMdsSBEwKefm7hfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvVTiD%2FbtrDe95Tzej%2FccBjJjHMdsSBEwKefm7hfk%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;288&quot; height=&quot;215&quot; data-filename=&quot;스크린샷 2022-05-26 오후 10.20.47.png&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;215&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;왜 쓰는지??&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Singleton은 고유한 리소스를 캡슐화하여 애플리케이션 전체에서 쉽게 사용할 수 있도록 함&lt;/li&gt;
&lt;li&gt;캘린더, 로깅 등에 사용 됨 why? =&amp;gt; 오로지 한개만 필요하기 때문에&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div data-post-id=&quot;12901840&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;기타 장점&lt;/u&gt;&lt;u&gt;&lt;b&gt;&lt;/b&gt;&lt;/u&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;단점&lt;/u&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;전역 상태는 코드의 결합을 증가시키기 때문에 리팩토링하기가 어려워 진다.&lt;/b&gt; &lt;b&gt;클래스가 싱글톤의 구체적인 구현에 의존하게 된다.&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;rarr; IoC/ DI 컨테이너를 사용하여 객체를 요청하는 하는 것으로 바꿔야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단위 테스트가 어려워짐&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;rarr; 생성자를 통해 동적으로 객체를 주입할 수 없어 이런 경우는 필요한 객체를 직접 만들어서 사용해야 하기 때문에 테스트용 객체로 대체하기가 힘듬&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단일 책임의 원칙은 모든 클래스가 하나의 책임만을 가져야 한다는 원칙, 싱글톤 클래스는 클래스의 작업을 처리하는 역할 뿐 아니라 자신의 인스턴스에 대한 접근을 관리하는 역할에 대해서도 책임을 진다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;싱글톤 클래스는 생성자가 private으로 지정되기 때문에 상속이 불가능&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;생성자 문제 뿐만 아니라, 싱글톤 클래스는 static 변수를 바탕으로 하기 때문에 모든 서브클래스들이 그 변수를 공유하게 된다. 이를 해결하기 위해서는 '레지스트리'를 구현해두어야 한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;멀티 스레드를 적용하면 여러 스레드에서 한개의 싱글톤 클래스에 접근하게 된다. &lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;이는 동기화 문제를 발생시킬 수 있으니 volatile 키워드를 통해 Double Checking Locking을 적용하거나 getInstance() 메소드에 synchronized 키워드를 적용하여 동기화 해야한다. 그런데 synchronized 키워드를 적용하면 스레드에서 getInstance() 할 떄마다 속도가 느려지는 문제가 발생&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;왜 스프링은 싱글톤으로 빈을 만들까?&lt;/b&gt;&lt;/u&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;b&gt; 빈 객체&lt;/b&gt;를 새로 만들면? &amp;rarr; 서버의 부하가 생김&lt;/li&gt;
&lt;li&gt;서비스가&lt;b&gt; stateless 면 멀티 스레드로부터 안전&lt;/b&gt;하고 동시 요청 수에 관계없이 확장할 수 있으므로 하나의 객체만 있으면 된다.&lt;/li&gt;
&lt;li&gt;스프링이 직접 싱글톤을 생성하고, 관리하고, 공급하기 때문에 평범한 자바 클래스를 싱글톤으로 활용가능하게 한다. &amp;rarr; &lt;b&gt;싱글톤 레지스트리&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;엔터프라이즈 시스템&lt;/b&gt;: 서버에서 동작하며 기업과 조직의 업무를 처리해주는 시스템. 많은 사용자들의 요청을 동시 처리 해야하므로 서버지원을 효율적으로 공유하고 분배해서 사용할 수 있어야 한다. 또한 중요한 기업 핵심정보 다루기때문에 보안,안정성,확장성 이 요구된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;자바 싱글톤과 스프링 싱글톤의 차이?&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 싱글톤패턴은 미리 메모리에 올라가든, lazy하게 올라가든 결국 메모리에 올라가면 애플리케이션이 종료될 때 까지 메모리를 차지하기 때문에 메모리 낭비가 있고, 이것을 &lt;b&gt;스프링 컨테이너가 빈을 생성하고 의 &lt;u&gt;생명주기까지 관리&lt;/u&gt;&lt;/b&gt;하기 때문에 메모리에 계속 올라가있지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;*&lt;b&gt;주의&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 인스턴스를 하나만 생성해서 공유하는 싱글톤 방식은 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문에 &lt;b&gt;상태를 유지하게 설계하면 안된다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;특정 클라이언트에 의존적인 필드가 있으면 안된다.&lt;/li&gt;
&lt;li&gt;특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가급적 읽기만 가능해야 한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스프링빈은 항상 무상태로 설계하자&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.davidtanzer.net/david's%20blog/2016/03/14/6-reasons-why-you-should-avoid-singletons.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.davidtanzer.net/david's blog/2016/03/14/6-reasons-why-you-should-avoid-singletons.html&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/스프링-mvc-1/dashboard&quot;&gt;https://www.inflearn.com/course/스프링-mvc-1/dashboard&lt;/a&gt;&lt;/p&gt;</description>
      <category>스프링</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/111</guid>
      <comments>https://dding9code.tistory.com/111#entry111comment</comments>
      <pubDate>Thu, 26 May 2022 22:36:31 +0900</pubDate>
    </item>
    <item>
      <title>REST ? RESTful ? REST API?</title>
      <link>https://dding9code.tistory.com/110</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;자바 스프링을 공부하기에 카테고리는 마땅히 추가할 곳이 없어 스프링에 분류했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;F-lab 2주차 RESTful 에 대하여 한번 공부해보라는 과제가 주어져 한번 찾아보게 되었다. 자바 스프링 공부를 하면 자연스럽게 HTTP 도 공부를 하게 되는데 그 과정에서 REST라는 단어를 많은 사람들이 쓰는것을 보았고 RESTful 하다. RESTful 하지않다. REST API 를 만드려면 어떻게 해야하나요? 라는 글 같은 것을 많이 봤지만 아직 나랑은 먼 단계 라고 생각하여 자세하게 알아 볼 생각은 없었다.. 반성하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과제도 과제이지만 이미 많은 사람들이 언급하는 것으로 보아 중요할 것 같은데 왜 이런 말들이 많을까 한번 알아보고 정리해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜?&lt;/b&gt; 라는 이유에 집중을 해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;REST&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;REST&lt;/b&gt;(REpresentational State Transfer)?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Representational State =&amp;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;u&gt;&lt;b&gt;URL 로 리소스를 표현(=식별)하고 조작은 메서드를 통해 조작한다.&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;u&gt;&lt;b&gt;State: URI안의 상태(State) 를 포함해라&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;u&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot; data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;URL 자체는 정보의 완정성을 띄어야 한다.&lt;/span&gt;&lt;/b&gt;&lt;/u&gt;&lt;span style=&quot;color: #000000;&quot; data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt; =&amp;gt; HTTP 메서드를 바꿔도 하나의 컨텐츠를 조작할 수 있어야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;웹에서 컴퓨터 &lt;b&gt;시스템 간에&lt;/b&gt; &lt;b&gt;표준을 제공&lt;/b&gt;하여 시스템이 서로 더 쉽게 통신할 수 있도록 하는 아키텍처 스타일&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;아키텍쳐 스타일&lt;/b&gt; &amp;rArr; 제약조건의 집합&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;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;탄생하게 된 이유?&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;How do I improve HTTP without breaking in the web&lt;br /&gt;- roy Fielding -&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;b&gt; 웹을 깨뜨리지 않고 HTTP를 개선할 수 있을까?&lt;/b&gt;&amp;nbsp; 라는 고민에서 시작&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;REST API 란?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;b&gt; REST&lt;/b&gt; &lt;b&gt;아키텍쳐 스타일을 따르는 API&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 하이퍼텍스트를 포함한 &lt;b&gt;self-descriptive&lt;/b&gt;한 메시지의 &lt;b&gt;uniform interface&lt;/b&gt;를 통해 &lt;b&gt;리소스에 접근하는 API&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;제약 조건(아키텍쳐 스타일)&lt;/b&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;b&gt;1. client - server&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;클라이언트-서버의 각 파트가 독립적으로 개선될 수 있도록 해준다.&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. stateless&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;클라이언트의 context가 서버에 저장되어서 안됨&lt;/li&gt;
&lt;li&gt;요청만 처리하면 되기 때문에 서버에서 불필요한 정보를 관리 하지 않아 구현이 단순하여 확장성이 좋다&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;분리를 통해 구성 요소를 독립적으로 발전시켜 여러 조직 도메인의 인터넷 규모 요구 사항을 지원할 수 있다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. cache&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;캐시는 &lt;b&gt;클라이언트가&lt;/b&gt; &lt;b&gt;동일한 리소스에 대해 반복해서 서버를 요청할 필요가 없도록 하는 것&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;캐시 제약 조건은 요청에 대한 응답 내의 데이터에 암시적 또는 명시적으로 캐시 가능 또는 캐시 불가능으로 레이블이 지정되어야 함&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. &lt;/b&gt;&lt;u&gt;&lt;b&gt;uniform interface&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;REST 아키텍처 &lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;코드&lt;/span&gt;스타일을 다른 네트워크 기반 스타일과 구별하는 핵심 기능은 구성 요소 간의 균일한 인터페이스를 강조&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. layered system&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;인터넷 규모 요구 사항에 대한 동작을 더욱 개선하기 위해 계층화된 시스템 제약 조건을 추가&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. code-on-demand (optional)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;서버에서 코드를 클라이언트로 보내서 실행시킬 수 있어야 한다. (자바스크립트)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;*Uniform Interface&lt;/b&gt;의 제약 조건&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. identification of resources&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;리소스가 URI 로 식별되면 된다.&lt;/li&gt;
&lt;li&gt;각 URL이 단일 리소스에 매핑되어야 하며 이 리소스에 대한 모든 액세스는 해당 URL을 통해 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. manipulation of resources through representations&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;representations을 통한 리소스를 조작&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000;&quot;&gt;서버가 리소스 표현을 전송하므로 클라이언트가 클라이언트의 요구에 맞는 특정 표현을 요청할 수 있다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. &lt;/b&gt;&lt;u&gt;&lt;b&gt;self-descriptive messages&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;메시지는 스스로 설명해야한다. &amp;rarr; 요청, 응답 메시지의 내용으로 온전히 해석이 다 가능해야한다.&lt;/li&gt;
&lt;li&gt;서버나 클라이언트가 변경이 되더라도 오고가는 메시지는 언제나 self-descriptive&lt;span&gt;&amp;nbsp;하므로&amp;nbsp;&lt;/span&gt;해석이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. &lt;/b&gt;&lt;u&gt;&lt;b&gt;hypermedia as the engine of application state(HATEOAS)&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;애플리케이션 상태는 Hyperlink를 이용해 다음 상태로 전이되어야 한다.&lt;/li&gt;
&lt;li&gt;이것은 HTML처럼 하이퍼링크가 추가되어서 다음에 어떤 API를 호출해야 하는지를 해당 링크를 통해서 받을 수 있어야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 대부분 RESTful API는 &lt;b&gt;self-descriptive messages&lt;/b&gt; 와 &lt;b&gt;hypermedia as the engine of applicationstate(HATEOAS)&lt;/b&gt; 두 개가&lt;b&gt; 잘 지켜지지 않는다&lt;/b&gt;. &lt;b&gt;사실상 대부분이 HTTP API&lt;/b&gt; 그렇지만 실무, 많은 사람들이 저 두가지를 제외해도 REST API 라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;왜 제약조건을 지켜야 하는가?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;독립적 진화&lt;/b&gt;&lt;/u&gt; 를 하기 위해, &lt;b&gt;REST는 웹의 독립적의 진화를 위해 만들어졌다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버와 클라이언트는 각각 독립적 진화한다.&lt;/li&gt;
&lt;li&gt;서버의 기능이 변경되어도 클라이언트를 업데이트할 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;어떻게 확인하는가?&lt;/b&gt;&lt;/h4&gt;
&lt;ol 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;HTTP 명세가 변경되어도 웹은 잘 동작한다.&lt;/li&gt;
&lt;li&gt;HTML 명세가 변경되어도 웹은 잘 동작한다.&lt;/li&gt;
&lt;/ol&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;API는 왜 REST 하기 어려울까?&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-24 오전 12.59.01.png&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;195&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLOsuN/btrCY2y7egH/9SPJ1hNQd6zMNFsjk751Nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLOsuN/btrCY2y7egH/9SPJ1hNQd6zMNFsjk751Nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLOsuN/btrCY2y7egH/9SPJ1hNQd6zMNFsjk751Nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLOsuN%2FbtrCY2y7egH%2F9SPJ1hNQd6zMNFsjk751Nk%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;599&quot; height=&quot;195&quot; data-filename=&quot;스크린샷 2022-05-24 오전 12.59.01.png&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;195&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- HATEOAS 와 Self-descriptive 를 지키기위한 단점과 번거로움이 있다. (참조된 유튜브 40:30)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;REST 왜 사용할까?&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;결국 REST의 모든 이유는 웹을 표준화하는 것&lt;/li&gt;
&lt;li&gt;&lt;b&gt;각 요청이 어떤 동작이나 정보를 위한 것인지를 그 요청의 모습 자체로 추론이 가능해짐&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;API?&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API는 애플리케이션 소프트웨어를 빌드하고 통합하기 위한 정의 및 프로토콜 세트인 애플리케이션 프로그래밍 인터페이스(Application Programming Interface)를 뜻합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;소프트웨어가 다른 소프트웨어로부터 지정된 형식으로 요청, 명령을 받을 수 있는 수단&lt;/li&gt;
&lt;li&gt;API는 사용자가 원하는 것을 시스템에 전달할 수 있게 지원하여 시스템이 이 요청을 이해하고 이행하도록 할 수 있다.&lt;/li&gt;
&lt;li&gt;API를 사용자 또는 클라이언트, 그리고 사용자와 클라이언트가 얻으려 하는 리소스 사이의 조정자로 생각&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Best practices REST API ?&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;가장 중요한 사항은 웹 표준 및 규칙을 준수하여 일관성을 유지해야 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;1. JSON으로 수락 및 응답&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JSON은 데이터 전송의 표준입니다.&amp;nbsp;거의 모든 네트워크 기술에서 사용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 마지막 경로에서 동사 대신 명사 사용&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 요청 메서드에 이미 동사가 있기 때문&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GET&lt;/b&gt;은 리소스를 검색&lt;/li&gt;
&lt;li&gt;&lt;b&gt;POST&lt;/b&gt;는 새 데이터를 서버에 제출&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PUT&lt;/b&gt;은 기존 데이터를 업데이트&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DELETE&lt;/b&gt;는 데이터를 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 마지막 경로에 논리적 중첩 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 오류를 적절하게 처리하고 표준 오류 코드를 반환&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API의 유지 관리자들에게 발생한 문제를 이해하기에 충분한 정보를 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 필터링, 정렬 및 페이지 지정 허용&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스가 매우 커질 수 있어 속도저하, 시스템 다운 방지를 위해 한 번에 모두 반환X &amp;rarr;항목을 필터링&lt;/li&gt;
&lt;li&gt;한 번에 몇가지 결과만 반환하도록 데이터를 페이징&lt;/li&gt;
&lt;li&gt;필터링 및 페이지 분할은 모두 서버 리소스 사용을 줄임으로써 성능을 향상. 데이터베이스에 더 많은 데이터가 축적될수록 이러한 기능들은 더욱 중요해짐&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 우수한 보안 유지&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개인 정보를 자주 주고 받기 때문에 이런 통신은 비공개여야 한다.&lt;/li&gt;
&lt;li&gt;SSL / TLS 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7. 성능 향상을 위한 캐시 데이터&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가 데이터를 더 빨리 얻을 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8. API 버전 관리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 사람이 동시에 새 API로 이동하도록 하는 대신 이전 엔드포인트를 점진적으로 단계적으로 제거가능&lt;/li&gt;
&lt;li&gt;v1 엔드포인트는 변경을 원하지 않는 사람들을 위해 활성 상태를 유지할 수 있는 반면, 새로운 기능을 갖춘 v2는 업그레이드할 준비가 된 사람들에게 서비스를 제공 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[reference]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.blog/2020/03/02/best-practices-for-rest-api-design/&quot;&gt;https://stackoverflow.blog/2020/03/02/best-practices-for-rest-api-design/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=RP_f5dMoHFc&amp;amp;ab_channel=naverd2&quot;&gt;https://www.youtube.com/watch?v=RP_f5dMoHFc&amp;amp;ab_channel=naverd2&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm&quot;&gt;https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Representational_state_transfer&quot;&gt;https://en.wikipedia.org/wiki/Representational_state_transfer&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sookocheff.com/post/api/how-rest-constraints-affect-api-design/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://sookocheff.com/post/api/how-rest-constraints-affect-api-design/&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;참고로 &lt;a href=&quot;https://www.youtube.com/watch?v=RP_f5dMoHFc&amp;amp;ab_channel=naverd2&quot;&gt;https://www.youtube.com/watch?v=RP_f5dMoHFc&amp;amp;ab_channel=naverd2&lt;/a&gt;&amp;nbsp;이 유튜브는 꼭 한번 시청하기를 권해봅니다.&lt;/p&gt;</description>
      <category>스프링</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/110</guid>
      <comments>https://dding9code.tistory.com/110#entry110comment</comments>
      <pubDate>Thu, 26 May 2022 14:21:35 +0900</pubDate>
    </item>
    <item>
      <title>모던 자바 인 액션 - 6장 스트림으로 데이터 수집</title>
      <link>https://dding9code.tistory.com/109</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.1 컬렉터란 무엇인가?&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Collector 인터페이스 구현은 &lt;b&gt;스트림의 요소를 어떤 식으로 도출할지 지정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함수형 프로그래밍은 &amp;lsquo;무엇'을 원하는지 직접 명시&lt;/b&gt;할 수 있어 어떤 방법으로 이를 얻을지는 신경 쓸 필요가 없다. 이는 다수준으로 그룹화를 수행할 때 명령형 프로그래밍과 함수형 프로그래밍의 차이점이 더욱 두드러진다. 명령형 코드에서는 문제를 해결하는 과정에서 다중 루프와 조건문을 추가하며 가독성과 유지보수성이 떨어지지만 &lt;b&gt;함수형 프로그래밍에서는 컬렉터를 쉽게 추가할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;강점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;collect로 결과를 수집하는 과정을 간단하면서도 유연한 방식으로 정의할 수 있다&lt;/li&gt;
&lt;li&gt;명령형 프로그래밍에서 직접 구현해야 했던 작업이 자동으로 수행&lt;/li&gt;
&lt;li&gt;collect에서는 리듀싱 연산을 이용해서 스트림의 각 요소를 방문하면서 컬렉터가 작업 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Collectors 에서 제공하는 메서드의 기능은 크게 세 가지로 구분이 가능하다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스트림 요소를 하나의 값으로 리듀스하고 요약&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다양한 계산을 수행할 때 유용하게 활용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;요소 그룹화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다수준으로 그룹화 하거나 각각의 결과 서브그룹에 추가로 리듀싱 연산을 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;요소 분할&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그룹화의 특별한 연산 분할 사용&lt;/li&gt;
&lt;li&gt;한 개의 인수를 받아 불리언을 반환하는 함수, 즉 프리디케이트를 그룹화 함수로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.2 리듀싱 요약&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5장에서 사용한 자동차 리스트를 활용해서 Collector 팩토리 클래스로 만든 컬렉터 인스턴스로 어떤 일을 할 수 있는지 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째로 counting() 이라는 팩토리 메서드가 반환하는 컬렉터로 메뉴에서 요리 수를 계산한다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Long howManyCars = carList.stream().collect(Collectors.counting());
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불필요한 과정 생략&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Long howManyCars = carList.stream().count();
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;import static java.util.stream.Collectors.*;
&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;이제는 정적 팩토리 메서드를 모두 import 했다고 가정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Long howManyCars = carList.stream().collect(counting());
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;으로도 표현이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.2.1 스트림값에서 최대,최소 검색&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동차에서 가장 비싼 차를 찾는다고 가정해봅시다.&lt;/p&gt;
&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;Collectors.maxBy, Collectors.minBy&lt;/b&gt; 두 메서드를 이용해&lt;b&gt; 최대, 최소 값을 계산&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 컬렉터는 스트림의 요소를 비교하는 데 사용할 Comparator를 인수로 받습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대 가격 차량&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Optional&amp;lt;Car&amp;gt; highPriceCar = carList.stream().
                collect(maxBy(Comparator.comparingInt(Car::getPrice)));
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소 가격 차량&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Optional&amp;lt;Car&amp;gt; highPriceCar = carList.stream().
                collect(minBy(Comparator.comparingInt(Car::getPrice)));
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.2.2 요약 연산&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Collectors 클래스는 Collectors.summingInt 라는 특별한 요약 팩토리 메서드를 제공한다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;summingInt 는 객체를 int로 매핑하는 함수를 인수로 받음&lt;/li&gt;
&lt;li&gt;summingIn의 인수로 전달된 함수는 객체를 int 로 매핑하는 함수를 인수로 받음&lt;/li&gt;
&lt;li&gt;summingInt가 collect 메서드로 전달되면 요약 작업을 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 차 리스트의 총 가격을 합하는 코드이다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;int totalCarPrice = carList.stream().collect(summingInt(Car::getPrice));
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;summingLong, summingDouble 메서드 또한 같은 방식으로 동작하며 반환 타입이 long, double 형식으로 데이터를 요약한다는 점만 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단순 합계 외에 평균값 계산 등 연산도 요약 기능으로 제공된다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;averagingInt&lt;/li&gt;
&lt;li&gt;averagingLong&lt;/li&gt;
&lt;li&gt;averagingDouble&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;Double collect = carList.stream().collect(averagingInt(Car::getPrice));
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합계, 평균, 최대, 최소 모든 정보를 수집하는 방법도 있다. summarizingInt가 반환하는 컬렉터를 사용하면 된다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;IntSummaryStatistics intSummaryStatistics = carList.stream().collect(summarizingInt(Car::getPrice));
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.2.3 문자열 연결&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉터에 joining 팩토리 메서드를 이용하면 스트림의 각 객체에 toString 메서드를 호출해서 추출한 모든 문자열을 하나의 문자열로 연결해서 반환합니다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;String collect = carList.stream()
                .map(Car::getName)
                .collect(joining(&quot;, &quot;));

//출력
k3, avante, sonata, gv70, benzC, g80, benzE
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;joining 메서드는 내부적으로 StringBuilder를 이용해서 문자열을 하나로 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 Car클래스가 차량명을 반환하는 toString 메서드를 포함하고 있다면 map으로 각 차량의 이름을 추출하는 과정을 생략가능&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;String collect = carList.stream()
                .collect(joining(&quot;, &quot;));
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.2.4 범용 리듀싱 요약 연산&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 살펴본 모든 컬렉터는 reducing 팩토리 메서드로도 정의할 수 있습니다. 즉, 범용 Collectors.reducing으로도 구현할 수 있습니다. 그럼에도 범용 팩토리 메서드 대신 특화된 컬렉터를 사용한 이유는 편의성과 가독성을 위해 사용했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reducing 메서드로 만들어진 컬렉터로도 차량의 모든 가격을 계산할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;Integer totalPrice = carList.stream().
                collect(reducing(0, Car::getPrice, (a, b) -&amp;gt; a + b));
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;세 개의 인수를 받습니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리듀싱 연산의 시작값 or 스트림에 인수가 없을 때는 반환값&lt;/li&gt;
&lt;li&gt;차량을 가격 정수로 변환할 때 사용한 변환 함수&lt;/li&gt;
&lt;li&gt;두 항목을 하나의 값으로 더하는 BinaryOperator&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 개의 인수를 가진 reducing 을 이용해서 가장 비싼 차량을 찾는 방법도 있습니다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;Optional&amp;lt;Car&amp;gt; mostCarPrice = carList.stream().
                collect(reducing(
                        (p1, p2) -&amp;gt; p1.getPrice() &amp;gt; p2.getPrice() ? p1 : p2
                ));
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 개의 인수를 갖는 reducing 팩토리 메서드는 세 개의 인수를 갖는 reducing 메서드에서 스트림의 첫 번째 요소를 시작 요소, 즉 첫 번째 인수로 받으며, 자신을 그대로 반환하는 &lt;b&gt;항등 함수&lt;/b&gt;를 두 번째 인수로 받는 상황에 해당한다. 한 개의 인수를 갖는 reducing 컬렉터는 시작값이 없으므로 빈 스트림이 넘겨졌을 때 시작값이 설정되지 않은 상황이 벌어져 Optional을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다 표현식 대신 Integer 클래스의 sum 메서드 참조를 이용하면 좀더 단순화 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Integer totalCarPrice = carList.stream().
                collect(reducing(0, Car::getPrice, Integer::sum));
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림을 사용하여 같은 결과를 얻는데 다양한 해결 방법이 있지만 가장 일반적으로 &lt;b&gt;문제에 특화된 해결책을 고르는 것&lt;/b&gt;이 바람직 합니다. 왜냐하면 &lt;b&gt;가독성과 성능&lt;/b&gt;이라는 두 가지 장점을 가져갈 수 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.3 그룹화&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8의 함수형을 이용하면 가독성 있는 한줄의 코드로 그룹화를 구현할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Map&amp;lt;Car.Type, List&amp;lt;Car&amp;gt;&amp;gt; carByType = carList.stream()
                .collect(groupingBy(Car::getType));

//출력
{ELECTRIC=[gv70E, gv60],
 GASOLINE=[k3, avante, avanteN, gv70, benzC, g80, benzE],
 HYBRID=[sonata], DIESEL=[benzC]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림에서 각 차량에서 Car.Type 과 일치하는 모든 차량을 추출하는 함수를 groupingBy 메서드로 전달했습니다. 이 함수를 기준으로 스트림이 그룹화되므로 이를 &lt;b&gt;분류함수&lt;/b&gt; 라고 부릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 복잡한 분류 기준이 있을 경우 메서드 참조를 분류 함수로 사용할 수 없고 람다 표현식으로 필요한 로직을 구현할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;//타입 분류를 위한 enum 추가
public enum CarLevel { LOW, MIDDLE, HIGH } 

Map&amp;lt;CarLevel, List&amp;lt;Car&amp;gt;&amp;gt; carByPriceLevel = carList.stream()
                .collect(groupingBy(car -&amp;gt; {
                    if (car.getPrice() &amp;lt;= 3000) return CarLevel.LOW;
                    else if (car.getPrice() &amp;lt;= 6500) return CarLevel.MIDDLE;
                    else return CarLevel.HIGH;
                }));

//출력
{MIDDLE=[avanteN, gv70, gv70E, benzC], 
LOW=[k3, avante, sonata],
HIGH=[gv60, benzC, g80, benzE]}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.3.1 그룹화된 요소 조작&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요소를 그룹화 한 다음에는 각 결과 그룹의 요소를 조작하는 연산이 필요합니다. 차량 가격이 6000이상만 되는 차량만 필터링 한다고 가정해보자 &lt;b&gt;그룹화 하기전&lt;/b&gt;에 &lt;b&gt;프레디케이트로 필터를 적용&lt;/b&gt;해 문제를 해결할 수 있다고 생각할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Map&amp;lt;Car.Type, List&amp;lt;Car&amp;gt;&amp;gt; carListByType = carList.stream()
                .filter(car -&amp;gt; car.getPrice() &amp;gt; 6000)
                .collect(groupingBy(Car::getType));

//출력
{DIESEL=[benzC], ELECTRIC=[gv60], GASOLINE=[benzC, g80, benzE]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;b&gt;위와 같은 코드의 문제점은 HYBRID 의 타입은 &lt;u&gt;필터에서 걸러졌기 때문에 맵에서 해당 키 자체가 사라집니다&lt;/u&gt;.&lt;/b&gt; Collectors 클래스는 일반적인 분류 함수에 Collector 형식의 두 번째 인수를 갖도록 groupingBy 팩토리 메서드를 오버로드해 이 문제를 해결합니다.&lt;/p&gt;
&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;Collector 안으로 필터 프레디케이트를 이동&lt;/b&gt;함으로 이 문제를 해결 할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Map&amp;lt;Car.Type, List&amp;lt;Car&amp;gt;&amp;gt; carListByType = carList.stream()
                .collect(groupingBy(Car::getType,
                        filtering(car -&amp;gt; car.getPrice() &amp;gt; 6000, toList())));

//출력
{ELECTRIC=[gv60], DIESEL=[benzC], GASOLINE=[benzC, g80, benzE], HYBRID=[]}
&lt;/code&gt;&lt;/pre&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;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Map&amp;lt;Car.Type, List&amp;lt;Integer&amp;gt;&amp;gt; carListByType = carList.stream()
                .collect(groupingBy(Car::getType,
                        mapping(Car::getPrice, toList())));

//출력
{HYBRID=[2700], ELECTRIC=[6000, 7000],
 DIESEL=[6400], GASOLINE=[1800, 2300, 3100, 6000, 6700, 8000, 8700]}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.3.2 다수준 그룹화&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 인수를 받는 팩토리 메서드&lt;b&gt; groupingBy를 이용해서 항목을 다수준으로 그룹화 할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;Map&amp;lt;Car.Type, Map&amp;lt;CarLevel, List&amp;lt;Car&amp;gt;&amp;gt;&amp;gt; carByTypePriceLevel = carList.stream()
                .collect(groupingBy(Car::getType,
                        groupingBy(car -&amp;gt; {
                            if (car.getPrice() &amp;lt;= 3000) {
                                return CarLevel.LOW;
                            } else if (car.getPrice() &amp;gt;= 6500) {
                                return CarLevel.HIGH;
                            } else {
                                return CarLevel.MIDDLE;
                            }
                        })));

//출력
{HYBRID={LOW=[sonata]}, GASOLINE={MIDDLE=[avanteN, gv70],
 HIGH=[benzC, g80, benzE], LOW=[k3, avante]}, 
ELECTRIC={MIDDLE=[gv70E], HIGH=[gv60]}, DIESEL={MIDDLE=[benzC]}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그룹화의 결과로 두 수준의 맵이 만들어 진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 groupingBy 연산을 &amp;lsquo;버킷(물건을 담는 양동이)&amp;rsquo; 개념으로 생각하면 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.3.3 서브그룹으로 데이터 수집&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6.3.2 절에서 두 번째 groupingBy 컬렉터를 외부 컬렉터로 전달해서 다수준 그룹화 연산을 구현 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 첫 번째 groupingBy로 넘겨주는 컬렉터의 형식은 제한이 없다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Map&amp;lt;Car.Type, Long&amp;gt; typeCount = carList.stream()
                .collect(groupingBy(Car::getType, counting()));

//출력
{ELECTRIC=2, GASOLINE=7, HYBRID=1, DIESEL=1}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 코드처럼 컬렉터에 두 번째 인수로 counting 컬렉터를 전달해서 메뉴에서 차량수를 종류별로 계산이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분류 함수 한 개의 인수를 갖는 groupingBy(f) 는 groupingBy(f , toList())의 축약형이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 아래와 같은 코드도 구현이 가능하다.&lt;/p&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;Map&amp;lt;Car.Type, Optional&amp;lt;Car&amp;gt;&amp;gt; mostPriceByType = carList.stream()
                .collect(groupingBy(Car::getType,
                        maxBy(Comparator.comparing(Car::getPrice))));

//출력
{DIESEL=Optional[benzC], HYBRID=Optional[sonata], 
ELECTRIC=Optional[gv60], GASOLINE=Optional[benzE]}

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 그룹화 연산에서 맵의 모든 값을 Optional 로 감쌀 필요가 없으므로 Optional을 삭제할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Collectors.collectingAndThen 으로 컬렉터가 반환한 결과를 다른 형식으로 활용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Map&amp;lt;Car.Type, Car&amp;gt; mostPriceByType = carList.stream()
                .collect(groupingBy(Car::getType,
                        collectingAndThen(
                                maxBy(Comparator.comparing(Car::getPrice)),
                                Optional::get)));

//출력
{ELECTRIC=gv60, GASOLINE=benzE, DIESEL=benzC, HYBRID=sonata}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리듀싱 컬렉터는 절대 Optional.empty를 반환하지 않으므로&lt;/b&gt; &lt;b&gt;안전한 코드&lt;/b&gt;이기 때문에 maxBy로 만들어진 컬렉터가 감싸지는 컬렉터며 반환 함수 Optional::get 으로 반환된 Optional에 포함된 값을 추출합니다.&lt;/p&gt;
&lt;p data-ke-size=&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.4 분할&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분할은 &lt;b&gt;분할 함수&lt;/b&gt; 라고 불리는 프&lt;b&gt;레디케이트를 분류 함수로 사용하는 특수한 그룹화 기능&lt;/b&gt;입니다. 분할 함수는 불리언을 반환하므로 맵의 키 형식은 Boolean 입니다. 결과적으로 맵은 true , flase 두개의 그룹으로 분류가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 이용해 차량을 국산차인지 아닌지 분류를 해보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Map&amp;lt;Boolean, List&amp;lt;Car&amp;gt;&amp;gt; partitionedCar = carList.stream()
                .collect(partitioningBy(Car::isMadeKorea));

//출력
{false=[benzC, benzC, benzE],
 true=[k3, avante, avanteN, sonata, gv70, gv70E, gv60, g80]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 참 값을 이용해 맵에서 모든 국산차 리스트를 얻을 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;List&amp;lt;Car&amp;gt; koreanCarList = partitionedCar.get(true);

//출력
[k3, avante, avanteN, sonata, gv70, gv70E, gv60, g80]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 차량 리스트로 생성한 스트림을 프레디케이트로 필터링한 다음에 리스트에 결과를 수집해도 같은 결과를 얻을 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;carList.stream()
                .filter(Car::isMadeKorea)
                .collect(toList());
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.4.1 분할의 장점&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참, 거짓 두 가지 요소의 스트림 리스트를 모두 유지한다는 것이 분할의 장점&lt;/b&gt;입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;참, 거짓 &lt;u&gt;두 가지 키만 포함&lt;/u&gt;하므로 간결하고 효과적&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉터를 두 번째 인수로 전달할 수 있는 오버로드하여 사용된&lt;b&gt; partitioningBy&lt;/b&gt; 메서드도 있습니다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Map&amp;lt;Boolean, Map&amp;lt;Car.Type, List&amp;lt;Car&amp;gt;&amp;gt;&amp;gt; koreanCarByType = carList.stream()
                .collect(partitioningBy(Car::isMadeKorea,
                        groupingBy(Car::getType)));

//출력
{false={DIESEL=[benzC], GASOLINE=[benzC, benzE]},
 true={ELECTRIC=[gv70E, gv60], GASOLINE=[k3, avante, avanteN, gv70, g80],
 HYBRID=[sonata]}}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.5 Collector 인터페이스&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Collector 인터페이스는 리듀싱 연산(컬렉터)을 어떻게 구현할지 제공하는 메서드 집합&lt;/b&gt;으로 구성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 코드는 Collector 인터페이스의 시그니처와 다섯 개의 메서드 정의를 보여줍니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;public interface Collector&amp;lt;T, A, R&amp;gt; {
	Supplier&amp;lt;A&amp;gt; supplier();
	BiConsumer&amp;lt;A, T&amp;gt; accumulator();
	BinaryOperator&amp;lt;A&amp;gt; combiner();
	Function&amp;lt;A, R&amp;gt; finisher();
	Set&amp;lt;Characteristics&amp;gt; characteristics();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 다음처럼 설명할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;T는 수집될 스트림 항목의 제네릭 형식&lt;/li&gt;
&lt;li&gt;A는 누적자, 즉 수집 과정에서 중간 결과를 누적하는 객체의 형식&lt;/li&gt;
&lt;li&gt;R은 수집 연산 결과 객체의 형식(항상 그런 것은 아니지만 대게 컬렉션 형식)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6.5.1 Collector 인터페이스의 메서드 살펴보기&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;supplier 메서드 : 새로운 결과 컨테이너 만들기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;b&gt; supplier 메서드는 빈 결과로 이루어진 Supplier를 반환&lt;/b&gt;해야 한다. 즉 supplier는 수집 과정에서 빈 누적자 인스턴스를 만드는 파라미터가 없는 함수다. ToListCollector 처럼 누적자를 반환하는 컬렉터에서는 빈 누적자가 비어있는 스트림의 수집 과정의 결과가 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ToListCollector에서 supplier는 다음처럼 빈 리스트를 반환한다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public Supplier&amp;lt;List&amp;lt;T&amp;gt;&amp;gt; supplier(){
        return () -&amp;gt; new ArrayList&amp;lt;T&amp;gt;();   
}

public Supplier&amp;lt;List&amp;lt;T&amp;gt;&amp;gt; supplier(){
        return ArrayList::new;  
}

&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;accumlator 메서드 : 결과 컨테이너에 요소 추가하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;b&gt; accumlator 메서드는 리듀싱 연산을 수행하는 함수를 반환&lt;/b&gt;합니다. 스트림에서 n 번째 요소를 탐색할 때 두 인수, 즉 누적자와 n번째 요소를 함수에 적용한다. 함수의 반환값은 void, 요소를 탐색하면서 적용하는 함수에 의해 누적자 내부상태가 바뀌므로 누적자가 어떤 값일지 단정할 수 없다. ToListCollector 에서 accumlator가 반환하는 함수는 이미 탐색한 항목을 포함하는 리스트에 현재 항목을 추가하는 연산을 수행한다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;public BiConsumer&amp;lt;List&amp;lt;T&amp;gt;, T&amp;gt; accumlator(){
		return (list, item) -&amp;gt; list.add(item);
}

public BiConsumer&amp;lt;List&amp;lt;T&amp;gt;, T&amp;gt; accumlator(){
		return List::add;
}

&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;finisher 메서드 : 최종 변환값을 결과 컨테이너로 적용하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;b&gt; finisher 메서드는 스트림 탐색을 끝내고 누적자 객체를 최종 결과로 반환&lt;/b&gt;하면서 누적 과정을 끝낼 때 호출할 함수를 반환해야 한다. 때로는 ToListCollector에서 볼 수 있는 것처럼 누적자 객체가 이미 최종 결과인 상황도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 때는 변환 과정이 필요하지 않으므로 finisher 메서드는 항등 함수를 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1653319998555&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public Function&amp;lt;List&amp;lt;T&amp;gt;, List&amp;lt;T&amp;gt;&amp;gt; finisher() {

	return Function.identity();
}&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;combiner 메서드 : 두 결과 컨테이너 병합&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;combiner는 스트림의 서로 다른 서브파트를 병렬로 처리할 때 누적자가 이 결과를 어떻게 처리할지 정의&lt;/b&gt;한다. toList의 combiner는 비교적 쉽게 구현할 수 있다. 즉, 스트림의 두 번째 서브파트에서 수집한 항목 리스트를 첫 번째 서브파트 결과 리스트의 뒤에 추가하면 된다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;public BinaryOperator&amp;lt;List&amp;lt;T&amp;gt;&amp;gt; combiner() {
	return (list1, list2) -&amp;gt; {
		list1.addAll(list2);
		return list1;
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 메서드를 이용하면 스트림의 리듀싱을 병렬로 수행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Characteristics 메서드&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;Characteristics 메서드는 컬렉터의 연산을 정의하는 Characteristics 형식의 불변 집합을 반환&lt;/b&gt;합니다. Characteristics는 스트림을 병렬로 리듀스할 것인지 그리고 병렬로 리듀스한다면 어떤 최적화를 선택해야 할지 힌트를 제공합니다. Characteristics는 다음 세 항목을 포함하는 열거형입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;UNORDERED&lt;/b&gt; : 리듀싱 결과는 스트림 요소의 방문 순서나 누적 순서에 영향을 받지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CONCURRENT&lt;/b&gt; : 다중 스레드에서 accumlator 함수를 동시에 호출할 수 있으며 이 컬렉터는 스트림의 병렬 리듀싱을 수행할 수 있다. 컬렉터의 플래그 UNORDERED를 함께 설정하지 않았다면 데이터 소스가 정렬되어 있지 않은 상황에서만 병렬 리듀싱을 수행할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IDENTITY_FINISH&lt;/b&gt; : finisher 메서드가 반환하는 함수는 단순히 identity를 적용할 뿐 이므로 이를 생략할 수 있다. 따라서 리듀싱 과정의 최종 결과로 누적자 객체를 바로 사용할 수 있다. 또한 누적자 A를 결과 R로 안전하게 형변환 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;collect 는 스트림의 요소를 요약 결과로 누적하는 다양한 방법(컬렉터라 불리는)을 인수로 갖는 연산&lt;/li&gt;
&lt;li&gt;스트림의 요소를 하나의 값으로 리듀스하고 요약하는 컬렉터뿐 아니라 최소, 최대, 평균값을 계산하는 컬렉터 등이 미리 정의되어 있다.&lt;/li&gt;
&lt;li&gt;미리 정의된 컬렉터인 groupingBy로 스트림의 요소를 그룹화하거나, partitioningBy로 스트림의 요소를 분할 할 수 있다.&lt;/li&gt;
&lt;li&gt;컬렉터는 다수준의 그룹화 , 분할, 리듀싱 연산에 적합하게 설계됨&lt;/li&gt;
&lt;li&gt;Collector 인터페이스에 정의된 메서드를 구현해서 커스텀 컬렉터 개발이 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;추가 팁&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;reduce() 메서드는 항상 새로운 값을 생성하는 반면, collect() 메서드는 기존 값을 업데이트하거나 변경&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;reduce()는 감소를 수행하는 반면 collect()는 가변 감소를 수행&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;collect()&amp;nbsp;can&amp;nbsp;only&amp;nbsp;work&amp;nbsp;with&amp;nbsp;&lt;u&gt;mutable&lt;/u&gt; result objects. (가변)&lt;br /&gt;&lt;br /&gt;reduce()&amp;nbsp;is&amp;nbsp;designed&amp;nbsp;to&amp;nbsp;work&amp;nbsp;with&amp;nbsp;&lt;u&gt;immutable&lt;/u&gt; result objects. (불변)&lt;/b&gt;&lt;/p&gt;</description>
      <category>모던 자바 인 액션 스터디</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/109</guid>
      <comments>https://dding9code.tistory.com/109#entry109comment</comments>
      <pubDate>Tue, 24 May 2022 00:34:44 +0900</pubDate>
    </item>
    <item>
      <title>관심사의 분리(Seperation Of Concern)</title>
      <link>https://dding9code.tistory.com/108</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체지향의 세계에서는 모든 것이 변한다.&lt;/b&gt; 변수나 객체의 필드값이 변하는게 아닌 &lt;b&gt;객체에 대한 설계와 이를 구현한 코드가 변한다는 뜻 &lt;/b&gt;입니다. 사용자의 변화하는 요구사항은 소프트웨어 엔지니어링에서 피할 수 없습니다. 그래서 개발자는 객체를 설계할 때 이 &lt;b&gt;'변화하는 미래를 어떻게 대비할 것인가'&lt;/b&gt;&amp;nbsp;를 고려해야 합니다. 가장 좋은 방법은 변화가 이루어질 때&lt;b&gt; 이 변화의 폭을 최소한으로 줄여주는 것이다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &lt;u&gt;&lt;b&gt;변화의 폭을 최소한으로 줄이기 위해 관심사의 분리가 필요&lt;/b&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;사용자는 자동차를 운전한다 라는 프로그램을 만드려고 합니다.&amp;nbsp; 그런데 사용자가 아반떼를 운전하고싶다는 요구사항이 있습니다. 그럼 어떻게 코드를 구현할 수 있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1652852601726&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Avante {

    public void accel(){
        System.out.println(&quot;아반떼 가속&quot;);
    }

    public stop(){
        System.out.println(&quot;아반떼 멈춤&quot;);
    }

}

class User{
    private Avante avante = new Avante();

    public void rideCar(){
        avante.accel();
    }

    public void stopCar(){
        avante.stop();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 아반떼 클래스와 사용자 클래스를 만들 수 있습니다. 코드상에서는 문제가 없어 보입니다. 하지만 &lt;b&gt;'사용자는 테슬라를 운전한다'라고&lt;/b&gt; 요구사항이 변한다면? 또 &lt;b&gt;'사용자는 제네시스를 운전한다'&lt;/b&gt; 등 다양하게 요구사항이 변화할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 요구사항이 계속 변하면 User 클래스의 코드 또한 전부 바꿔줘야 합니다. 지금 사용자는 어떤 자동차를 탈지 정하는 것뿐만 아니라 자동차를 운전해야 한다는 다양한 책임을 가지고 있으며 이는 SRP(단일 책임 원칙)를 위반하게 됩니다. 따라서 관심사를 분리해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 유저클래스와 아반떼 클래스는 너무 긴밀하게 연결(종속)되어 있기 때문에 높은 결합도를 가지고 있습니다. 그렇지 않도록 중간에 추상적인 연결고리를 만들어 줘 봅시다. 바로 인터페이스를 사용하여 &lt;b&gt;아반떼, 제네시스, 테슬라 등등 모두를 추상화할&lt;/b&gt; 수 있는&lt;b&gt; 자동차 인터페이스를 만들어 봅시다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인터페이스를 통해 접근하므로&amp;nbsp;User 클래스는 어떤 자동차를 선택해야 하는 책임이 없어지고, 자신이 사용할 클래스가 어떤 것인지 몰라도 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-18 오후 4.04.13.png&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;355&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tAORo/btrCtw2HOV6/kBufqXwap0ylYGjr8k3jj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tAORo/btrCtw2HOV6/kBufqXwap0ylYGjr8k3jj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tAORo/btrCtw2HOV6/kBufqXwap0ylYGjr8k3jj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtAORo%2FbtrCtw2HOV6%2FkBufqXwap0ylYGjr8k3jj1%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;604&quot; height=&quot;355&quot; data-filename=&quot;스크린샷 2022-05-18 오후 4.04.13.png&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;355&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;pre id=&quot;code_1652855123649&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Car {
    void accel();
    void stop();
}

class Avante implements Car {

    @Override
    public void accel(){
        System.out.println(&quot;아반떼 가속&quot;);
    }

    @Override
    public void stop(){
        System.out.println(&quot;아반떼 멈춤&quot;);
    }

}

class Tesla implements Car{

    @Override
    public void accel() {
        System.out.println(&quot;테슬라 가속&quot;);
    }

    @Override
    public void stop() {
        System.out.println(&quot;테슬라 멈춤&quot;);
    }
}


class User{

    private Car car = new Avante();

    public void rideCar(){
        car.accel();
    }

    public void stopCar(){
        car.stop();
    }
}&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;이제 사용자가 어떠한 자동차를 운전해도 User 클래스를 전부 뜯어 고칠일은 없을 것 같습니다. 하지만 코드에 new Avante() 라는 구체적인 클래스를 사용할지 선택하는 코드가 남아있습니다. new Tesla()로 바꾸면 되는 아주 짧은 코드이지만 그 자체로도 &lt;b&gt;이미 어떤 구현 클래스의 객체를 이용하는 책임을 가지고 있으므로&lt;/b&gt; 이 코드를 User 에서 분리하지 않으면 User는 결국 독립적으로 확장 가능한 클래스가 될 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 위의 uml 같은 구조를 원했지만 사실 아래와 같은 구조를 가지게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-18 오후 3.40.51.png&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;355&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H8OoB/btrCsjv9kRb/UlqCch8JEMtPFud6OAs8y0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H8OoB/btrCsjv9kRb/UlqCch8JEMtPFud6OAs8y0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H8OoB/btrCsjv9kRb/UlqCch8JEMtPFud6OAs8y0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH8OoB%2FbtrCsjv9kRb%2FUlqCch8JEMtPFud6OAs8y0%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;604&quot; height=&quot;355&quot; data-filename=&quot;스크린샷 2022-05-18 오후 3.40.51.png&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;355&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;객체 사이의 관계가 만들어지려면 일단 만들어진 객체가 있어야 하는데 Car car = new Avante( )를 사용하는 방법도 있지만 외부에서 만들어 준 것을 가져오는 방법도 있습니다. 사용하려는 객체를 꼭 User 클래스 내에서 만들 필요가 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체는 메서드 파라미터 등을 이용해 전달할 수 있으니 외부에서 만들 걸 가져오면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;생성자 파라미터를 이용할 것&lt;/b&gt;인데 이때 &lt;b&gt;파라미터의 타입을 인터페이스로 선언&lt;/b&gt;하면 전달되는 객체는 이 &lt;b&gt;인터페이스를 구현한 어떤 것이든 될 수 있습니다&lt;/b&gt;. 바로 &lt;b&gt;다형성&lt;/b&gt;을 이용하는 것 입니다. 이를 통해 파라미터를 통해 전달이 되고, 파라미터로 제공받은 객체는 인터페이스에 정의된 메서드만 사용하면 그 객체가 어떤 클래스로부터 만들어졌는지 신경쓰지 않아도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;어떤 자동차를 선택할지 책임을 가지는 제3 클래스를 만들어 관심을 분리&lt;/b&gt;해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1652856864382&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class User{

    private final Car car;

    public User(Car car) {
        this.car = car;
    }

    public void rideCar(){
        car.accel();
    }

    public void stopCar(){
        car.stop();
    }
}

class Config{
    public User user(){
        return new User(selectCar());
    }

    private Car selectCar() {
        return new Avante();
    }
}&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;이제 User는 자신의 관심사이제 책임인 운전만 하면 됩니다. 어떠한 자동차가 들어와도 상관이 없고, 필요에 따라 자동차도 자유롭게 확장할 수 있는 구조가 되었습니다. 이렇게 해도 User 코드는 아무런 영향을 받지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 해온 리팩토링 작업이 자연스럽게 객체지향 기술을 적용했다고 보면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SRP&lt;/b&gt; : &lt;b&gt;한 클래스는 하나의 책임을 가진다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 관심사의 분리, User는 오직 운전만 하는 책임을 가지게 만들었다.&lt;/p&gt;
&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;OCP&lt;/b&gt; :&lt;b&gt; 클래스나 모듈은 확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 확장이 이루어져도 User 클래스의 코드는 변경할 필요가 없다.&lt;/p&gt;
&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;DIP&lt;/b&gt; :&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;고차원 모듈은 저차원 모듈에 의존하면 안된다.&amp;nbsp; &lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로그래머는 추상화에 의존해야지 구체화에 의존하면 안 된다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; User 클래스는 Car인터페이스에 의존하고 있었다.&lt;/p&gt;
&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;IoC : 제어의&amp;nbsp; 역전&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; User클래스가 능동적으로 자신이 사용할 객체를 선택하지 않고 제어의 흐름이 넘어가 Config 클래스에서 자신이 사용할 오브젝트를 공급받아 수동적으로 사용해야 하는 입장이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 IoC를 통해 &lt;u&gt;&lt;b&gt;DI(Dependency Injection)&lt;/b&gt;&lt;/u&gt;이 이루어집니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-18 오후 4.04.13.png&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;355&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kSDKa/btrCvJneZu2/t5C2RYiskBJKJIY7Xi4fo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kSDKa/btrCvJneZu2/t5C2RYiskBJKJIY7Xi4fo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kSDKa/btrCvJneZu2/t5C2RYiskBJKJIY7Xi4fo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkSDKa%2FbtrCvJneZu2%2Ft5C2RYiskBJKJIY7Xi4fo1%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;604&quot; height=&quot;355&quot; data-filename=&quot;스크린샷 2022-05-18 오후 4.04.13.png&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;355&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 이 그림을 보면 &lt;b&gt;User는 Car 인터페이스에 직접 의존&lt;/b&gt;합니다. User는 Avante 와 Tesla의 존재를 알지도 못합니다. 이 클래스 모델의 관점에서 보면 User는 Avante, Tesla 클래스에는 의존하지 않기 때문입니다. 이렇게 낮은 결합도를 갖게 되는 구조는 직접 실행하기 전까지 객체의 관계를 알 수 없습니다. &lt;b&gt;런타임시에 User객체가 &lt;u&gt;제3의 존재에게 제어의 흐름이 넘겨 실제 사용할 객체와 의존관계가 결정&lt;/u&gt;&lt;/b&gt;이 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;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;p data-ke-size=&quot;size16&quot;&gt;의존관계 주입은 다음과 같은 세 가지 조건을 충족해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해 인터페이스에 의존하고 있어야 함&lt;/li&gt;
&lt;li&gt;런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제3의 존재가 결정 (여기서는 Config)&lt;/li&gt;
&lt;li&gt;의존관계는 사용할 객체에 대한 래퍼런스를 외부에서 제공(주입)해줌으로써 만들어짐&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;참고: 토비스프링 3.1&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>스프링</category>
      <category>DI</category>
      <category>IOC</category>
      <category>관심사의 분리</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/108</guid>
      <comments>https://dding9code.tistory.com/108#entry108comment</comments>
      <pubDate>Wed, 18 May 2022 16:49:21 +0900</pubDate>
    </item>
    <item>
      <title>모던 자바 인 액션 - 5장 스트림 활용</title>
      <link>https://dding9code.tistory.com/106</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;스트림 활용&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 장에서 외부 반복을 내부 반복으로 바꾸는 방법을 살펴봤습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터를 어떻게 처리할지는 스트림 API가 관리 &amp;rarr; 편리하게 데이터관련 작업을 할 수 있다.&lt;/li&gt;
&lt;li&gt;스트림 API 내부적으로 다양한 최적화가 이루어질 수 있다.&lt;/li&gt;
&lt;li&gt;스트림 API는 내부반복 뿐 아니라 코드를 병렬로 실행할지 결정 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 일은 단일 스레드로 구현하는 외부 반복으로는 달성할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이번 파트는 스트림 API가 지원하는 다양한 연산을 살펴볼 것입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 필터링&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림의 요소를 선택하는 방법 두가지 &lt;b&gt;프레디케이트 필터링&lt;/b&gt; 방법과 &lt;b&gt;고유 요소만 필터링&lt;/b&gt; 하는 방법을 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;b&gt;1.1 프레디케이트 필터링&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스트림 인터페이스는 filter 메서드를 지원&lt;/li&gt;
&lt;li&gt;프레디케이트를 인수로 받아 프레디케이트와 일치하는 모든 요소를 포함하는 스트림 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;List&amp;lt;Car&amp;gt; koreanCar = carList.stream()
                .filter(Car::isMadeKorea)
                .collect(Collectors.toList());

//출력
k3
sonata
gv70
g80
avante
k5
TUCSON
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 모든 국산차만 필터링 해서 국산차 리스트를 만들 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;b&gt;1.2 고유 요소 필터링&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;고유 요소로 이루어진 스트림을 반환&lt;/b&gt;하는 distinct 메서드 지원 (중복 제거)&lt;/li&gt;
&lt;li&gt;&amp;rarr; 고유 여부는 스트림에서 만든 객체의 hashCode, equals 로 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; numbers = Arrays.asList(1, 2, 2, 3, 4, 5, 6, 6, 7);
        numbers.stream()
                .filter(i -&amp;gt; i % 2 == 0)
                .distinct()
                .forEach(System.out::println);

//출력
2
4
6
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 스트림 슬라이싱&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 스트림의 요소를 선택하거나 스킵하는 다양한 방법을 설명합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프레디케이트 이용하는 방법&lt;/li&gt;
&lt;li&gt;스트림의 처음 몇 개의 요소를 무시하는 방법&lt;/li&gt;
&lt;li&gt;특정 크기로 스트림을 줄이는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;u&gt;&lt;b&gt;2.1 프레디케이트를 이용한 슬라이싱&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바 9는 스트림의 요소를 효과적으로 선택할 수 있도록 takeWhile, dropWhile 두 가지 새로운 메서드를 지원합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;takeWhile&lt;/b&gt; &amp;rarr; 처음으로 거짓이 되는 지점까지 요소를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;dropWhile&lt;/b&gt; &amp;rarr; 처음으로 거짓이 되는 지점까지 요소를 버리고 남은 요소를 반환한다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;List&amp;lt;Car&amp;gt; carList = Arrays.asList(
                new Car(&quot;k3&quot;, 1800, GASOLINE, true),
                new Car(&quot;avante&quot;, 2300, GASOLINE, true),
                new Car(&quot;sonata&quot;, 2700, HYBRID, true),
                new Car(&quot;gv70&quot;, 6000, GASOLINE, true),
                new Car(&quot;benzC&quot;, 6400, DIESEL, false),
                new Car(&quot;g80&quot;, 8000, GASOLINE, true),
                new Car(&quot;benzE&quot;, 8700, GASOLINE, false)
                );
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같은 코드가 있습니다. 만약 6000만원 보다작은 값의 차량을 어떻게 선택할 수 있을까요? filter 를 사용하여 해결하는 방법도 있지만 위 리스트는&lt;b&gt; 이미 가격별로 정렬&lt;/b&gt;이 되어있습니다.&lt;b&gt; filter 연산을 이용하면 &lt;u&gt;전체 스트림을 반복&lt;/u&gt;하면서 각 요소에 프레디케이트를 적용&lt;/b&gt;하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리스트가 이미 정렬되어있는 사실을 이용&lt;/b&gt;하여 6000만원이라는 기준보다 크거나 같은 요리가 나왔을 때 &lt;b&gt;takeWhile&lt;/b&gt; or &lt;b&gt;dropWhile&lt;/b&gt; 을 사용하여 &lt;b&gt;반복작업을 중단&lt;/b&gt; 할 수 있습니다. 별거 아닌 것 같지만 아주많은 요소를 포함하는 큰 스트림에서는 큰 차이가 납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;TAKEWHILE 활용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;takeWhile&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; 처음으로 거짓이 되는 지점까지 요소를 가진다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;List&amp;lt;Car&amp;gt; sliceCarList = carList.stream()
                .takeWhile(car -&amp;gt; car.getPrice() &amp;lt; 6000)
                .collect(Collectors.toList());

//출력
k3
avante
sonata
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;DROPWHILE 활용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;dropWhile&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; 처음으로 거짓이 되는 지점까지 요소를 버리고 남은 요소를 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;List&amp;lt;Car&amp;gt; sliceCarList = carList.stream()
                .dropWhile(car -&amp;gt; car.getPrice() &amp;lt; 6000)
                .collect(Collectors.toList());

//출력
gv70
benzC
g80
benzE
&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;&amp;nbsp;&lt;/h3&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;b&gt;&lt;u&gt;2.2 스트림 축소&lt;/u&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주어진 값 이하의 크기를 갖는 새로운 스트림을 반환하는 limit(n) 메서드 지원&lt;/li&gt;
&lt;li&gt;스트림이 정렬되어 있으면 최대 요소 n 개를 반환할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;List&amp;lt;Car&amp;gt; sliceCarList = carList.stream()
                .dropWhile(car -&amp;gt; car.getPrice() &amp;lt; 6000)
                .limit(2)
                .collect(Collectors.toList());

//출력
gv70
benzC
&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;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;b&gt;2.3 요소 건너뛰기&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음 n개 요소를 제외한 스트림을 반환하는 skip(n) 메서드를 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;List&amp;lt;Car&amp;gt; sliceCarList = carList.stream()
                .dropWhile(car -&amp;gt; car.getPrice() &amp;lt; 6000)
                .skip(2)
                .collect(Collectors.toList());

//출력
g80
benzE

//결과가 4개인데 스킵이 4이면 빈 스트림을 반환한다.
List&amp;lt;Car&amp;gt; sliceCarList = carList.stream()
                .dropWhile(car -&amp;gt; car.getPrice() &amp;lt; 6000)
                .skip(4)
                .collect(Collectors.toList());

//출력
//없음
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 매핑&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 객체에서 특정 데이터를 선택하는 작업은 데이터 처리과정에서 자주 수행되는 연산이다.&lt;/p&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;u&gt;&lt;b&gt;3.1 스트림의 각 요소에 함수 적용하기&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스트림은 함수를 인수로 받는 map 메서드 지원&lt;/li&gt;
&lt;li&gt;인수로 제공된 함수는 각 요소에 적용 &amp;rarr; 결과가 새로운 요소로 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; sliceCarList = carList.stream()
                .map(Car::getName)
                .collect(Collectors.toList());

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getName 은 String을 반환하므로 map 메서드의 출력 스트림은 Stream&amp;lt;String&amp;gt;의 형식을 갖습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 차의 이름의 길이를 알고 싶다면 어떻게 해야할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 &lt;b&gt;다른 map 메서드를 연결&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; sliceCarList = carList.stream()
                .map(Car::getName)
                .map(String::length)
                .collect(Collectors.toList());
&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;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;b&gt;3.2 스트림 평면화&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트에서 고유 문자로 이루어진 리스트를 반환하고 싶다. 어떻게 해야할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) &amp;ldquo;Hello&amp;rdquo;, &amp;ldquo;World&amp;rdquo; &amp;rarr; H, e, l, o, W, r, d 를 포함하는 리스트&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;faltMap 사용&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; uniqueChar = word.stream()
                .map(ch -&amp;gt; ch.split(&quot;&quot;))
                .flatMap(Arrays::stream)
                .distinct()
                .collect(Collectors.toList());

//출력
H
e
l
o
W
r
d
&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;flatMap은 각 배열을 스트림이 아닌 스트림의 콘텐츠로 매핑한다.&lt;/li&gt;
&lt;li&gt;map(Arrays::stream) 과 달리 faltMap은 하나의 평면화된 스트림을 반환한다.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-18 오전 11.31.49.png&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djsbED/btrCs3Z4WvM/WWrDRbFB829UY4nk6Tqlc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djsbED/btrCs3Z4WvM/WWrDRbFB829UY4nk6Tqlc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djsbED/btrCs3Z4WvM/WWrDRbFB829UY4nk6Tqlc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjsbED%2FbtrCs3Z4WvM%2FWWrDRbFB829UY4nk6Tqlc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;607&quot; height=&quot;432&quot; data-filename=&quot;스크린샷 2022-05-18 오전 11.31.49.png&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;u&gt;&lt;b&gt;4. 검색과 매칭&lt;/b&gt;&lt;/u&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;스트림 API는 &lt;b&gt;allMatch, anyMatch, noneMatch, findFirst, findANy&lt;/b&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;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;b&gt;4.1 프레디케이트가 적어도 한 요소와 일치하는지 확인&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프레디케이트가 주어진 스트림에서 적어도 한 요소와 일치하는지 확인할 때 &lt;b&gt;anyMatch&lt;/b&gt; 메서드 를 이용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;anyMatch&lt;/b&gt;는 &lt;b&gt;boolean을 반환하므로 최종연산&lt;/b&gt;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 예는 carList에 국산차가 있는지 확인하는 코드입니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;if (carList.stream().anyMatch(Car::isMadeKorea)) {
       System.out.println(&quot;국산차 있습니다.&quot;);
}
&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;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;b&gt;4.2 프레디 케이트가 모든 요소와 일치하는지 확인&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;allMatch 메서드는 모든 요소가 주어진 프레디케이트와 일치하는지 검사&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어 모든 차가 6000만원이 넘는지 검사하는지 확인할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;boolean isCar = carList.stream().**allMatch**(car -&amp;gt; car.getPrice() &amp;gt; 9000);

//isCar =&amp;gt; false
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프레디케이트와 일치하는 요소가 없어 false 반환&lt;/p&gt;
&lt;p data-ke-size=&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;NONEMATCH&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;noneMatch는 &lt;b&gt;allMatch와 반대 연산을 수행&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;noneMatch는 주어진 프레디케이트와 일치하는 요소가없는지 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;boolean isCar = carList.stream().**noneMatch**(car -&amp;gt; car.getPrice() &amp;gt; 9000);

//isCar ==&amp;gt; true
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프레디케이트와 일치하는 요소가 없어 true 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*anyMatch, allMatch, noenMatch 세 메서드는 스트림 &lt;b&gt;쇼트서킷&lt;/b&gt; 기법, 즉 자바의 &amp;amp;&amp;amp;, || 와 같은 연산 사용&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;u&gt;&lt;b&gt;4.3 요소 검색&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;findAny 메서드는 현재 스트림에서 임의의 요소를 반환한다.&lt;/li&gt;
&lt;li&gt;다른 스트림 연산과 연결해서 사용 가능&lt;/li&gt;
&lt;li&gt;반환타입 Optional&amp;lt;T&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;Optional&amp;lt;Car&amp;gt; car = carList.stream()
                .filter(Car::isMadeKorea)
                .findAny();
&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;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;*Optional이란?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;값의 존재나 부재 여부를 표현&lt;/b&gt;하는 컨테이너 클래스&lt;/li&gt;
&lt;li&gt;값이 존재하는지 확인하고 값이 없을 때 어떻게 처리할지 강제하는 기능을 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;findAny 에서 아무 요소도 반환하지 않을 수 있다. null 은 에러를 일으킬 수 있는 문제가 있음.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;u&gt;&lt;b&gt;4.4 첫 번째 요소 찾기&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트 또는 정렬된 연속 데이터로부터 생성된 스트림처럼 일부 스트림에는 논리적인 아이템 순서가 정해져 있을 수 있다. 이런 스트림에서 첫 번째 요소를 찾으려면 어떻게 해야할까?&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; someNumbers = Arrays.asList(1, 2, 3, 4, 5);
        Optional&amp;lt;Integer&amp;gt; firstSquareDivisibleByThree = someNumbers.stream()
                .map(n -&amp;gt; n * n)
                .filter(n -&amp;gt; n % 3 == 0)
                .findFirst();

firstSquareDivisibleByThree.stream().forEach(System.out::println);

//출력 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;findFrist 와 findAny는 그럼 언제 사용할까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;병렬 실행에서 첫 번째 요소를 찾기 어렵다. 따라서 요소의 반환 순서가 상관없다면 병렬 스트림에서는 제약이 적은 findAny를 사용한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 리듀싱&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 살펴본 최종 연산은 boolean, void, Optional 객체를 반환했다.이번에는 &lt;b&gt;리듀스 연산을 이용&lt;/b&gt;하여 &lt;b&gt;스트림 요소를 조합해서 더 복잡한 질의를 표현&lt;/b&gt;하는 방법을 알아볼 것 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) 자동차 중에서 가장 비싼 차는?, 자동차의 모든 가격을 합계는?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 질의를 수행하려면 Integer 같은 결과가 나올 때 까지 &lt;b&gt;스트림의&lt;/b&gt; &lt;b&gt;모든 요소를 반복적으로 처리&lt;/b&gt;해야 한다. 이런 질의를 &lt;b&gt;리듀싱 연산&lt;/b&gt; 이라고 한다. 함수형 프로그래밍 언어 용어로는 이 과정이 종이를 작은 조각이 될 때까지 반복해서 접는 것과 비슷하다는 의미로 &lt;b&gt;폴드(fold)&lt;/b&gt;라고 불린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;b&gt;5.1 요소의합&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 reduce를 보기전에 for-each 문을 사용하여 리스트의 숫자를 더하는 코드를 확인해보자.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int sum = 0;
List&amp;lt;Integer&amp;gt; numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);   
for (Integer x : numbers) {
    sum += x;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;numbers 의 각 요소는 결과에 반복적으로 더해진다. 리스트에서 하나의 숫자가 남을 때까지 reduce 과정을 반복한다. 코드에는 파라미터를 두 개 사용했다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sum 변수의 초기값 0&lt;/li&gt;
&lt;li&gt;리스트의 모든 요소를 조합하는 연산 +&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 복붙하지 않고 모든 숫자를 곱하는 연산을 구현할 수 있다면 좋을 것 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황에서 reduce를 이용하면 애플리케이션의 반복된 패턴을 추상화할 수 있다. reduce를 이용해서 다음처럼 스트림의 모든 요소를 더할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;int sum = numbers.stream().reduce(0, (a, b) -&amp;gt; a + b);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reduce는 두 개의 인수를 갖는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기값 0&lt;/li&gt;
&lt;li&gt;두 요소를 조합해서 새로운 값을 만드는 BinaryOperator&amp;lt;T&amp;gt;, 예제에서는 람다 표현식 (a, b) &amp;rarr; a + b 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 예로 a , b &amp;rarr; a * b 를 사용하면 모든 요소에 곱셈을 적용할 수 있다.&lt;/p&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;b&gt;초기값 없음&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기값을 받지 않도록 오버로드된 reduce 도 있다. 그러나 이&lt;b&gt; reduce는 Optional 객체를 반환&lt;/b&gt;한다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;Optional&amp;lt;Integer&amp;gt; sum = numbers.stream().reduce((a, b) -&amp;gt; a + b);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 Optional 객체를 반환할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 스트림에 아무 요소도 없는 상황을 생각하면 초기값이 없어 reduce 는 합계를 반환할 수 없다. 따라서 합계가 없음을 가리킬 수 있도록 Optional 객체로 감싼 결과를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 리듀스를 활용하여 자동차 리스트의 전체 가격합을 구해보자.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Optional&amp;lt;Integer&amp;gt; sum = carList.stream()
                .map(Car::getPrice)
                .reduce((a, b) -&amp;gt; a + b);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;map과 reduce를 연결&lt;/b&gt;하는 기법을 &lt;u&gt;&lt;b&gt;맵 리듀스 패턴&lt;/b&gt;&lt;/u&gt;이라하며, &lt;b&gt;쉽게 병렬화하는 특징&lt;/b&gt;이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 구글이 웹 검색에 적용하면서 유명해 졌다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;u&gt;&lt;b&gt;5.2 최댓값과 최솟값&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최댓값과 최솟값을 찾을 때도 reduce를 활용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Optional&amp;lt;Integer&amp;gt; sum = carList.stream()
                .map(Car::getPrice)
                .reduce(Integer::max);

//출력
8700
&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;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;*스트림 연산 : 상태 없음과 상태 있음&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map, filter 등은 입력 스트림에서 각 요소를 받아 0 또는 결과를 출력 스트림으로 보낸다. 따라서 이들은 보통 상태가 없는, 즉 &lt;u&gt;&lt;b&gt;내부 상태를 갖지 않는 연산&lt;/b&gt;(&lt;b&gt;stateless operation&lt;/b&gt;)&lt;/u&gt;이다. 하지만 &lt;b&gt;reduce, sum, max&lt;/b&gt; 같은 연산은 결과를 누적할 &lt;b&gt;내부 상태가 필요&lt;/b&gt;하다. 예제의 내부 상태는 작은 값이다. 스트림에서 처리하는 요소의 수와 관게없이 내부 상태의 크기는 &lt;b&gt;한정(bounded)&lt;/b&gt; 되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 &lt;b&gt;sorted&lt;/b&gt;나 &lt;b&gt;distinct&lt;/b&gt; 같은 연산은 &lt;b&gt;filter&lt;/b&gt;나 &lt;b&gt;map&lt;/b&gt;처럼 스트림을 입력으로 받아 다른 스트림을 출력하는 것처럼 보일 수 있다. 하지만 &lt;b&gt;sorted&lt;/b&gt;나 &lt;b&gt;distinct&lt;/b&gt;는 &lt;b&gt;filter&lt;/b&gt;나 &lt;b&gt;map&lt;/b&gt;과는 다르다. &lt;b&gt;스트림의 요소를 정렬하거나 중복을 제거하려면 과거의 이력을 알고 있어야 한다.&lt;/b&gt; 예를 들어 어떤 요소를 출력 스트림으로 추가하려면 &lt;b&gt;모든 요소가 버퍼에 추가되어 있어야 한다.&lt;/b&gt; 연산을 수행하는 데 필요한 저장소 크기는 정해져 있지 않다. 따라서 데이터 스트림의 크기가 크거나 무한이라면 문제가 생길 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 연산을 &lt;u&gt;&lt;b&gt;내부 상태를 갖는 연산(stateful operation)&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;b&gt;5.3 기본형 특화 스트림&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5.1 에서 reduce를 사용하여 요소의 합을 구해봤지만 해당 코드에는 박싱 비용이 숨어있다.내부적으로 합계를 계산하기 전에 Integer 를 기본형으로 언박싱해야한다. &lt;b&gt;기본형 특화 스트림&lt;/b&gt;을 사용하면 &lt;b&gt;박싱 비용을 피할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;int 요소에 특화된 IntStream&lt;/li&gt;
&lt;li&gt;double 요소에 특화된 DoubleStream&lt;/li&gt;
&lt;li&gt;long 요소에 특화된 LongStream&lt;/li&gt;
&lt;li&gt;각 인터페이스는 sum, max 같이 자주 사용하는 숫자 관련 리듀싱 연산 수행 메서드 제공&lt;/li&gt;
&lt;li&gt;필요할 때 다시 객체 스트림으로 복원하는 기능 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특화 스트림은 오직 박싱 과정에서 일어나는 효율성과 관련이 있으며 스트림에 추가 기능을 제공하지 않는다.&lt;/p&gt;
&lt;pre class=&quot;axapta&quot;&gt;&lt;code&gt;int sum = carList.stream()
                .mapToInt(Car::getPrice)   //IntStream 반환
                .sum();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;객체 스트림으로 복원하기&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;IntStream intStream = carList.stream().mapToInt(Car::getPrice);
Stream&amp;lt;Integer&amp;gt; stream = intStream.boxed();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특화 스트림을 일반 스트림으로도 변환이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;기본값 : OptionalInt&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 최댓값을 찾을 때 0이라는 기본값이 있으면 잘못된 결과가 도출될 수 있다. 스트림에 요소가 없는 상황에 실제 최댓값이 0인 상황을 구별할 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 이전에는 값이 존재하는지 여부를 Optional 을 언급하였다. 이 Optional을 Integer, String 등의 참조 형식으로 파라미터화 할 수 있따. 또한 OptionalInt, OptionalDouble, OptionalLong 세 가지 기본형 특화 스트림 버전도 제공한다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;OptionalInt maxPriceCar = carList.stream()
                .mapToInt(Car::getPrice)
                .max();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 OptionalInt 를 사용하여 IntStream의 최댓값 요소를 찾을 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;u&gt;&lt;b&gt;5.4 숫자 범위&lt;/b&gt;&lt;/u&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;자바 8의 IntStream 과 LongStream 에서는 range와 rangeClosed라는 두 가지 정적 메서드 제공&lt;/li&gt;
&lt;li&gt;두 메서드 모두 첫 번째 인수 시작값, 두 번째 인수 종료값을 가짐&lt;/li&gt;
&lt;li&gt;range 메서드 &amp;rarr; 시작값과 종료값 결과에 포함 X&lt;/li&gt;
&lt;li&gt;rangeClosed 메서드 &amp;rarr; 시작값과 종료값 결과에 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;IntStream evenNumbers = IntStream.rangeClosed(1, 100)
                .filter(n -&amp;gt; n % 2 == 0);

System.out.println(evenNumbers.count());

//출력 50  , 100포함

IntStream evenNumbers = IntStream.range(1, 100)
                .filter(n -&amp;gt; n % 2 == 0);

System.out.println(evenNumbers.count());
//출력 49  , 100포함 안됨
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 스트림 만들기&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;u&gt;&lt;b&gt;6.1 값으로 스트림 만들기&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;임의의 수를 인수로 받는 정적 메서드 Stream.of 를 이용하여 스트림을 만들 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;Stream&amp;lt;String&amp;gt; stream = Stream.of(&quot;Modern&quot;, &quot;Java&quot;, &quot;In&quot;, &quot;Action&quot;);
        
stream.map(String::toUpperCase)
          .forEach(System.out::println);
&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;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;b&gt;6.2 null이 될 수 있는 객체로 스트림 만들기&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바 9에서 null이 될 수 있는 개체를 스트림으로 만들 수 있는 새로운 메소드 추가&lt;/li&gt;
&lt;li&gt;ex) System.getProperty &amp;rarr; 제공된 키에 대응하는 속성이 없으면 null을 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;String homeValue = System.getProperty(&quot;home&quot;);

        
Stream&amp;lt;String&amp;gt; homeValueStream
            = Stream.ofNullable(System.getProperty(&quot;home&quot;));
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;null 이 될 수 있는 객체를 포함하는 스트림값을 flatMap과 함께 사용하는 상황에서는 이 패턴을 더 유용하게 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;String homeValue = System.getProperty(&quot;home&quot;);

        
Stream&amp;lt;String&amp;gt; values = Stream.of(&quot;config&quot;, &quot;home&quot;, &quot;user&quot;)
                .flatMap(key -&amp;gt; Stream.ofNullable(System.getProperty(key)));
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;b&gt;6.3 배열로 스트림 만들기&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열을 인수로 받는 정적 메서드 Arrays.stream을 이용해서 스트림을 만들 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int[] numbers = {2, 3, 5, 7, 11, 13};
int sum = Arrays.stream(numbers).sum();
&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;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;b&gt;6.4 파일로 스트림 만들기&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일을 처리하는 등의 I/O 연산에 사용하는 자바 NIO API(비블록 I/O)도 스트림 API를 활용할 수 있도록 업데이트 됨&lt;/li&gt;
&lt;li&gt;java.nio.file.Files의 많은 정적 메서드가 스트림을 반환&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;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;b&gt;6.5 함수로 무한 스트림 만들기&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스트림 API는 함수에서 스트림을 만들 수 있는 두 정적 메서드 Stream.iterate 와 Stream.generate 제공&lt;/li&gt;
&lt;li&gt;두 연산을 이용해서 무한 스트림, 즉 &lt;b&gt;크기가 고정되지 않은 스트림을 만들 수 있다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;iterate&lt;/b&gt; 와 &lt;b&gt;generate&lt;/b&gt;에서 만든 스트림은 &lt;b&gt;요청할 때마다 주어진 함수를 이용해서 값을 만듬&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;따라서 무제한으로 값을 계산할 수 있다.&lt;/li&gt;
&lt;li&gt;하지만 &lt;b&gt;무한한 값을 출력하지 않도록 limit(n) 함수를 함께 연결하여 사용&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;무한 스트림의 요소는 무한적 계산이 반복되므로 &lt;b&gt;정렬이나 리듀스가 불가능&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;iterate 메서드&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Stream.iterate(0, n -&amp;gt; n * 2)
                .limit(5)
                .forEach(System.out::println);

Stream.iterate(0, n -&amp;gt; n * 2)
                .takeWhile(n -&amp;gt; n &amp;lt; 100)
                .forEach(System.out::println);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청이 올 때마다 값을 생성할 수 있어 &lt;b&gt;무한스트림&lt;/b&gt;을 만든다. 이러한 스트림을 &lt;b&gt;언바운드 스트림&lt;/b&gt;이라고 표현한다 . 이런 특징이 컬렉션과의 가장 큰 차이점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;generate 메서드&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Stream.generate(Math::random)
                .takeWhile(n -&amp;gt; n &amp;lt; 100)
                .forEach(System.out::println);

Stream.generate(Math::random)
                .takeWhile(n -&amp;gt; n &amp;lt; 100)
                .forEach(System.out::println);

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;generate도 요구할 때 값을 계산하는 무한 스트림을 만들 수 있다. 하지만 iterate와 달리 generate는 생산된 각 값을연속적으로 계산하지 않는다. generate는 Supplier&amp;lt;T&amp;gt;를 인수로 받아서 새로운 값을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림을 병렬로 처리하면서 올바른 결과를 얻으려면 불변 상태 기법을 고수해야하는데 7장에서 배울 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마치며&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스트림 API를 이용하면 복잡한 데이터 처리 질의를 표현할 수 있다.&lt;/li&gt;
&lt;li&gt;다양한 메서드로 스트림을 필터링하거나 자를 수 있다.&lt;/li&gt;
&lt;li&gt;소스가 정렬되어 있다는 사실을 알고 있으면 takeWhile 과 dropWhile 메소드 효과적 사용이 가능하다.&lt;/li&gt;
&lt;li&gt;map, flatMap 메서드로 스트림의 요소를 추출하거나 변환할 수 있다.&lt;/li&gt;
&lt;li&gt;findFirst, findAny 메서드로 스트림의 요소를 검색할 수 있다.&lt;/li&gt;
&lt;li&gt;reduce 메서드로 스트림의 모든 요소를 반복 조합하며 값을 도출할 수 있다.&lt;/li&gt;
&lt;li&gt;상태 없는 연산, 상태가 있는 연산이 있다.&lt;/li&gt;
&lt;li&gt;기본형 특화 스트림이 있다.&lt;/li&gt;
&lt;li&gt;iterate 와 generate 같은 메서드로도 스트림을 만들 수 있다.&lt;/li&gt;
&lt;li&gt;무한한 개수의 요소를 가진 스트림을 무한 스트림이라 한다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>모던 자바 인 액션 스터디</category>
      <category>5장</category>
      <category>모던 자바 인 액션</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/106</guid>
      <comments>https://dding9code.tistory.com/106#entry106comment</comments>
      <pubDate>Mon, 16 May 2022 23:51:38 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스 Level3] 불량 사용자(JAVA) - 2019 카카오 인턴</title>
      <link>https://dding9code.tistory.com/105</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/64064?language=java&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/64064?language=java&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1652366464018&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 불량 사용자&quot; data-og-description=&quot;개발팀 내에서 이벤트 개발을 담당하고 있는 &amp;quot;무지&amp;quot;는 최근 진행된 카카오이모티콘 이벤트에 비정상적인 방법으로 당첨을 시도한 응모자들을 발견하였습니다. 이런 응모자들을 따로 모아 불량 &quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/64064?language=java&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/64064?language=java&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rSuTS/hyOnO93dXx/AP7xwzYBjM9cpRmDngtEd1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/Zity3/hyOmA6ARAv/MPAWpgBTGyvEa1d2wNip31/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/64064?language=java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/64064?language=java&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rSuTS/hyOnO93dXx/AP7xwzYBjM9cpRmDngtEd1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/Zity3/hyOmA6ARAv/MPAWpgBTGyvEa1d2wNip31/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 불량 사용자&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개발팀 내에서 이벤트 개발을 담당하고 있는 &quot;무지&quot;는 최근 진행된 카카오이모티콘 이벤트에 비정상적인 방법으로 당첨을 시도한 응모자들을 발견하였습니다. 이런 응모자들을 따로 모아 불량&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&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;user_id 배열의 크기는 1 이상 8 이하입니다.&lt;/li&gt;
&lt;li&gt;user_id 배열 각 원소들의 값은 길이가 1 이상 8 이하인 문자열입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응모한 사용자 아이디들은 서로 중복되지 않습니다.&lt;/li&gt;
&lt;li&gt;응모한 사용자 아이디는 알파벳 소문자와 숫자로만으로 구성되어 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;banned_id 배열의 크기는 1 이상 user_id 배열의 크기 이하입니다.&lt;/li&gt;
&lt;li&gt;banned_id 배열 각 원소들의 값은 길이가 1 이상 8 이하인 문자열입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;불량 사용자 아이디는 알파벳 소문자와 숫자, 가리기 위한 문자 '*' 로만 이루어져 있습니다.&lt;/li&gt;
&lt;li&gt;불량 사용자 아이디는 '*' 문자를 하나 이상 포함하고 있습니다.&lt;/li&gt;
&lt;li&gt;불량 사용자 아이디 하나는 응모자 아이디 중 하나에 해당하고 같은 응모자 아이디가 중복해서 제재 아이디 목록에 들어가는 경우는 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;제재 아이디 목록들을 구했을 때 아이디들이 나열된 순서와 관계없이 아이디 목록의 내용이 동일하다면 같은 것으로 처리하여 하나로 세면 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제풀이&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&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;user_id 배열의 크기는 1 이상 8 이하. &amp;rarr; 매우 작은수로 &lt;b&gt;완탐을 고려&lt;/b&gt;해 볼 수 있다.&lt;/li&gt;
&lt;li&gt;banned_id 배열의 크기 1 이상 user_id 크기 이하&lt;/li&gt;
&lt;li&gt;응모한 사용자 아이디들은 &lt;b&gt;서로 중복되지 않는다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;불량 사용자 아이디 하나는 응모자 아이디 중 하나에 해당, 같은 응모자 아이디가 중복해서 제제 아이디 목록에 들어가는 경우는 없다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;크기는 불량 사용자 아이디 만큼 유저아이디로 만들 수 있는 경우의 수를 만들어 본다.&lt;/li&gt;
&lt;li&gt;중복을 제거하기 위해 해시셋을 사용하였다. &lt;b&gt;추가한 순서를 보장하기 위하여 LinkedHashSet을 사용&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;만들어진 불량 사용자 리스트가, 주어진 불량사용자리스트에 맞는지 확인 해본다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;소스코드&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1652366574957&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    static HashSet&amp;lt;HashSet&amp;lt;String&amp;gt;&amp;gt; answer;
    public int solution(String[] user_id, String[] banned_id) {
        answer = new HashSet&amp;lt;&amp;gt;();

        dfs(new LinkedHashSet&amp;lt;&amp;gt;(), user_id, banned_id);

        return answer.size();
    }


    private static void dfs(HashSet&amp;lt;String&amp;gt; hs, String[] user_id, String[] banned_id) {
        if (hs.size() == banned_id.length) {
            if (isBanList(hs, banned_id)) {
                answer.add(new HashSet&amp;lt;&amp;gt;(hs));
            }
            return;
        }

        for (String userId : user_id) {
            if (hs.add(userId)) {
                dfs(hs, user_id, banned_id);
                hs.remove(userId);
            }
        }
    }


    private static boolean isBanList(HashSet&amp;lt;String&amp;gt; hs, String[] banned_id) {
        int idx = 0;
        for (String userID : hs) {
            String banID = banned_id[idx++];
            if (userID.length() != banID.length()) {
                return false;
            }
            for (int i = 0; i &amp;lt; banID.length(); i++) {
                if (banID.charAt(i) == '*') {
                    continue;
                }
                if (userID.charAt(i) != banID.charAt(i)) {
                    return false;
                }
            }
        }
        return true;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/105</guid>
      <comments>https://dding9code.tistory.com/105#entry105comment</comments>
      <pubDate>Thu, 12 May 2022 23:43:19 +0900</pubDate>
    </item>
    <item>
      <title>모던 자바 인 액션 - 4장 스트림 소개</title>
      <link>https://dding9code.tistory.com/104</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스트림 소개&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거의 모든 자바 애플리케이션은 컬렉션을 만들고 처리하는 과정을 포함합니다. 대부분의 프로그래밍 작업에 사용되며, 컬렉션으로 데이터를 그룹화하고 처리할 수 있습니다. 비즈니스 로직상 컬렉션에 대해 특정 카테고리로 그룹화 하던가, 특정 키워드를 사용하여 원하는 결과를 찾는 연산을 요구하는 작업이 있을 수 있습니다. 대부분 데이터베이스에서는 선언형으로 이와 같은 연산을 표현할 수 있습니다. 예를 들어 &amp;lsquo;SELECT name FROM cars WHERE price &amp;lt; 2500&amp;rsquo;이라는 문장같이 2500 이하인 차량을 선택하라는 SQL질의를 만들 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 자동차의 속성을 이용하여 어떻게 필터링 할 것인지는 구현할 필요가 없습니다. 어떻게 구현해야 할지 명시할 필요가 없고 구현은 자동으로 제공됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션으로도 이와 비슷한 기능을 만들 수 있지 않을까?&amp;nbsp; 많은 요소를 포함하는 커다란 컬렉션은 어떻게 처리해야 할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;이런 문제를 해결하기 위해, &lt;/b&gt;&lt;b&gt;프로그래머가 더 편하게 개발을 하기 위해 만들어 진 것이&amp;nbsp;스트림입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스트림이란 무엇인가?&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8 API에 추가된 기능으로 스트림을 이용하면 선언형으로 컬렉션 데이터를 처리할 수 있습니다. 또한 스트림을 이용하면 멀티스레드 코드를 구현하지 않아도 데이터를 투명하게 병렬로 처리할 수 있습니다. 우선은 병렬 처리는 7장에서 설명하고 우선 스트림이 어떤 유용한 기능을 제공하는지 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1652101336303&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package streamExample;

import java.util.Arrays;
import java.util.List;

import static streamExample.Car.Type.*;

public class Car {

    private final String name;
    private final int price;
    private final Type type;

    public Car(String name, int price, Type type) {
        this.name = name;
        this.price = price;
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }

    public Type getType() {
        return type;
    }

    @Override
    public String toString() {
        return name;
    }

    public enum Type{
        GASOLINE,
        DIESEL,
        ELECTRIC,
        HYBRID
        }

    public static final List&amp;lt;Car&amp;gt; carList = Arrays.asList(
        new Car(&quot;k3&quot;, 1800, GASOLINE),
        new Car(&quot;sonata&quot;, 2700, HYBRID),
        new Car(&quot;gv70&quot;, 6000, GASOLINE),
        new Car(&quot;g80&quot;, 8000, GASOLINE),
        new Car(&quot;benzC&quot;, 6400, DIESEL),
        new Car(&quot;benzE&quot;, 8700, GASOLINE),
        new Car(&quot;avante&quot;, 2700, GASOLINE),
        new Car(&quot;k5&quot;, 2800, HYBRID),
        new Car(&quot;TUCSON&quot;, 3000, DIESEL)
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;List&amp;lt;Car&amp;gt; lowPriceCars = new ArrayList&amp;lt;&amp;gt;();
        for (Car car : Car.carList) {
            if (car.getPrice() &amp;lt; 3000) {
                lowPriceCars.add(car);
            }
        }

        Collections.sort(lowPriceCars, new Comparator&amp;lt;Car&amp;gt;() {
            @Override
            public int compare(Car o1, Car o2) {
                return o1.getPrice() - o2.getPrice();
            }
        });

        List&amp;lt;String&amp;gt; lowPriceCarsName = new ArrayList&amp;lt;&amp;gt;();
        for (Car car : lowPriceCars) {
            lowPriceCarsName.add(car.getName());
        }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서는 lowPirceCars라는&lt;b&gt; &amp;lsquo;가비지 변수&amp;rsquo;&lt;/b&gt; 즉 중간 컨테이너 역할을 하는 중간 변수이다. 자바 8에서 이러한 세부 구현은 라이브러리 내에서 모두 처리한다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; lowPriceCarsName = Car.carList.stream()
                .filter(c -&amp;gt; c.getPrice() &amp;lt; 3000)   //3000미만 자동차 선택
                .sorted(Comparator.comparing(Car::getPrice)) //가격순으로 정렬
                .map(Car::getName)    //자동차 이름 추출
                .collect(Collectors.toList()); //모든 자동차 이름을 리스트에 저장&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림의 새로운 기능이 소프트웨어공학적으로 다음의 다양한 이득을 줄 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선언형으로 코드를 구현할 수 있다. 어떻게 동작을 구현할지 지정할 필요 없이 &amp;lsquo;특정 가격이하의 자동차를 선택해라&amp;rsquo; 동작의 수행을 지정할 수 있다. &lt;b&gt;선언형 코드와 동작 파라미터화를 활용하면 변화하는 요구에도 쉽게 대응이 가능&lt;/b&gt;하다.&lt;/li&gt;
&lt;li&gt;filter, sorted, map, collect 같은 여러 빌딩 블록 연산을 연결해서 복잡한 데이터 처리 파이프라인을 만들 수 있습니다. 여러 연산을 파이프라인으로 연결해도 여전히 가독성과 명확성을 유지할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;filter (sorted, map, collect) 같은 연산은 &lt;b&gt;고수준 빌딩 블록&lt;/b&gt; 으로 이루어져 있으므로 특정 스레딩 모델에 제한되지 않고 자유롭게 어떤 상황에서든 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 이들은 내부적으로 단일 스레드 모델에 사용할 수 있지만 멀티코어 아키텍처를 최대한 투명하게 활용할 수 있게 구현되어 있습니다. 결과적으로 우리는 &lt;b&gt;스트림 API를 통해 데이터 처리 과정을 병렬화화면서 스레드와 락을 걱정할 필요할 없습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8 스트림의 API 특징을 다음처럼 요약할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;선언형&lt;/b&gt; : 더 간결하고 가독성이 좋아진다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조립가능&lt;/b&gt; : 유연성이 좋아진다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;병렬화&lt;/b&gt; : 성능이 좋아진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스트림 시작하기&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 스트림 작업인 컬렉션 스트림 부터 살펴봅시다. 자바 8 컬렉션에는 스트림을 반환하는 stream 메서드가 추가됐습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;스트림이란 정확이 뭘까요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 스트림이란 &amp;lsquo;&lt;b&gt;데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소&lt;/b&gt;' 로 정의할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 정의를 하나씩 살펴 보겠습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;연속된 요소&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컬렉션과 마찬가지로 스트림은 특정 요소 형식으로 이루어진 연속된 값 집합의 인터페이스를 제공합니다. 컬렉션은 자료구조이므로 컬렉션에서는 시간과 공간의 복잡성과 관련된 요소 저장 및 접근 연산이 주를 이룹니다. 반면 스트림은 filter, sorted, map 처럼 표현 계산식이 주를 이룹니다. &lt;b&gt;즉, 컬렉션의 주제는 데이터이고 스트림의 주제는 계산입니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;소스&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스트림은 컬렉션, 배열, IO 자원 등의 데이터 제공 소스로부터 데이터를 소비합니다. 정렬된 컬렉션으로 스트림을 생성하면 정렬이 그대로 유지된다. 즉, 리스트로 스트림을 만들면 스트림의 요소는 리스트의 요소와 같은 순서를 유지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 처리 연산&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스트림은 함수형 프로그래밍 언어에서 일반적으로 지원하는 연산과 데이터베이스와 비슷한 연산을 지원합니다. ex) filter, map, reduce, find, match . . . 등 으로 데이터를 조작할 수 있습니다. 스트림 연산은 순차적 또는 병렬로 실행 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 스트림에는 두 가지 중요 특성이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파이프라이닝:&lt;/b&gt; 대부분 스트림 연산은 스트림 연산끼리 연결해서 커다란 파이프라인을 구성할 수 있도록 스트림 자신을 반환합니다. 그 덕분에 게으름(laziness), 쇼트서킷(short-circuiting) 같은 최적화도 얻을 수 있습니다. 연산 파이프라인은 데이터 소스에 적용하는 데이터베이스 질의와 비슷합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;내부 반복:&lt;/b&gt; 반복자를 이용해서 명시적으로 반복하는 컬렉션과 달리 스트림은 내부 반복을 지원합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; twoHighPriceCarNames =
             Car.carList.stream()
                     .filter(car -&amp;gt; car.getPrice() &amp;gt; 5000)
                     .map(Car::getName)
                     .limit(2)
                     .collect(Collectors.toList());
  
System.out.println(twoHighPriceCarNames);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 소스&lt;/b&gt;는 차량 리스트 이고, 데이터 소스는 &lt;b&gt;연속된 요소&lt;/b&gt;를 스트림에 제공합니다. 다음으로 스트림의 filter, map, limiit, collect 로 이어지는 일련의 &lt;b&gt;데이터 처리 연산을 적용&lt;/b&gt;하고 collect를 제외한 모든 연산은 파이프라인을 형성할 수 있도록 스트림을 반환합니다. 마지막으로 collect 연산으로 &lt;b&gt;파이프라인&lt;/b&gt;을 처리해서 결과를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 collect를 호출하기 전까지는 carList에서 무엇도 선택되지 않으며 출력 결과도 없습니다. 즉 collect가 호출되기 전까지 메서드 호출이 저장되는 효과가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;filter :&lt;/b&gt; 람다를 인수로 받아 스트림에서 특정 요소를 제외시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;map :&lt;/b&gt; 람다를 이용해서 한 요소를 다른 요소로 변환하거나 정보를 추출합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;limit :&lt;/b&gt; 정해진 개수 이상의 요소가 스트림에 저장되지 못하게 스트림 크기를 축소합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;collect :&lt;/b&gt; 스트림을 다른 형식으로 변환합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;b&gt;스트림과 컬렉션&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바의 기존 컬렉션과, 스트림 모두 연속된 요소 형식의 값을 저장하는 자료구조의 인터페이스를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;연속된&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시각적으로 차이를 한번 알아봅시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-09 오후 10.10.39.png&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;433&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SpYEZ/btrBF5E3FA4/tOemgFbORSSx1PlYkKP7L0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SpYEZ/btrBF5E3FA4/tOemgFbORSSx1PlYkKP7L0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SpYEZ/btrBF5E3FA4/tOemgFbORSSx1PlYkKP7L0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSpYEZ%2FbtrBF5E3FA4%2FtOemgFbORSSx1PlYkKP7L0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;665&quot; height=&quot;433&quot; data-filename=&quot;스크린샷 2022-05-09 오후 10.10.39.png&quot; data-origin-width=&quot;665&quot; data-origin-height=&quot;433&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터를 언제 계산&lt;/b&gt;하느냐가 컬렉션과 스트림의 가장 큰 차이입니다. 컬렉션은 현재 자료구조가 포함하는 모든 값을 메모리에 저장하는 자료구조입니다. 그래서 컬렉션의 모든 요소는 컬렉션에 추가하기 전에 계산되어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림은 이론적으로 &lt;b&gt;요청할 때만 요소를 계산&lt;/b&gt; 하는 고정된 자료구조 입니다.(스트림에 요소를 추가/제거 불가) 이러한 스트림의 특성은 프로그래밍에 큰 도움을 줍니다. 요청할 때만 요소를 계산하기 때문에 사용자가 요청하는 값만 스트림에서 추출한다는 것이 핵심입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉, 스트림은 게으르게 만들어지는 컬렉션과 같습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;딱 한 번만 탐색할 수 있다.&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복자와 마찬가지로 스트림도 한 번만 탐색이 가능합니다. 탐색된 스트림의 요소는 소비되며 반복자와 마찬가지로 한 번 탐색한 요소를 다시 탐색하려면 초기 데이터 소스에서 새로운 스트림을 만들어야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*만약 데이터 소스가 I/O 채널이라면 소스를 반복사용 할 수 없어 새로운 스트림을 만들 수 없다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;b&gt;외부 반복과 내부 반복&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;컬렉션 인터페이스&lt;/b&gt;를 사용하려면 사용자가 명시적으로 &amp;lsquo;직접 요소를 반복해야 합니다.&amp;rsquo; 이를 &lt;b&gt;외부 반복&lt;/b&gt; 이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 &lt;b&gt;스트림 라이브러리&lt;/b&gt;는 반복을 알아서 처리하고 결과 스트림값을 어딘가 저장해주는 &lt;b&gt;내부 반복&lt;/b&gt;을 사용합니다. 함수에 어떤 작업을 수행할지만 지정하면 모든 것이 알아서 처리가 됩니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;//외부 반복
List&amp;lt;String&amp;gt; names = new ArrayList&amp;lt;&amp;gt;();
     for (Car car : Car.carList) { //메뉴 리스트를 명시적으로 순차 반복
         names.add(car.getName());
       
 }

//내부 반복
List&amp;lt;String&amp;gt; name = Car.carList.stream()
             .map(Car::getName)  //map 메서드를 getNAme 메서드로 파라미터화하여 추출
             .collect(Collectors.toList());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-09 오후 10.11.49.png&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;485&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bd8OC0/btrBFcRJX9A/nXzNdv6oDJ7ONvwcWAXFvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bd8OC0/btrBFcRJX9A/nXzNdv6oDJ7ONvwcWAXFvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bd8OC0/btrBFcRJX9A/nXzNdv6oDJ7ONvwcWAXFvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbd8OC0%2FbtrBFcRJX9A%2FnXzNdv6oDJ7ONvwcWAXFvk%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;661&quot; height=&quot;485&quot; data-filename=&quot;스크린샷 2022-05-09 오후 10.11.49.png&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;485&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스트림은 내부 반복을 사용하므로 반복 과정을 신경 쓰지 않아도 된다&lt;/b&gt;. 하지만 이와 같은 이점을 누리려면 filter, map 같은 반복을 숨겨주는 연산 리스트가 미리 정의되어 있어야 한다. 반복을 숨겨주는 대부분의 연산은 람다 표현식을 인수로 받으므로 동작 파라미터화를 활용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스트림 연산&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; twoHighPriceCarNames =
             Car.carList.stream()  //요리 리스트에서 스트림 얻기
                     .filter(car -&amp;gt; car.getPrice() &amp;gt; 5000) //중간 연산
                     .map(Car::getName) //중간 연산
                     .limit(2) //중간 연산
                     .collect(Collectors.toList()); //스트림을 리스트로 변환
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림 인터페이스의 연산을 크게 두가지로 구분할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;filter, map, limit는 서로 연결되어 파이프라인을 형성한다.&lt;/li&gt;
&lt;li&gt;collect로 파이프라인을 실행한 다음에 닫는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결할 수 있는 스트림 연산을 &lt;b&gt;중간 연산&lt;/b&gt;이라고 하며, 스트림을 닫는 연산을 &lt;b&gt;최종 연산&lt;/b&gt;이라고 한다. 왜 스트림의 연산을 두 가지로 구분할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;중간 연산&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;filter나 sorted 같은 중간 연산은 다른 스트림을 반환한다. 따라서 여러 중간 연산을 연결해서 질의를 만들 수 있다. 중간 연산의 중요한 특징은 단말 연산을 스트림 파이프라인에 실행하기 전까지는 아무 연산도 수행하지 않는다는 것, 즉 lazy 하다는 것입니다. 중간 연산을 합친 다음에 합쳐진 중간 연산을 최종 연산으로 한번에 처리하기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*중간 연산만으로는 결과를 생성할 수 없다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;최종 연산&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 연산은 스트림 파이프라인에서 결과를 도출한다. 보통 최종 연산에 의해 List, Integer, void 등 스트림 이외의 결과가 반환된다. 예를 들어 다음 파이프라인에서 forEach는 소스의 각 요리에 람다를 적용한 다음에 void를 반환하는 최종 연산입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) Car.carList.stream().forEach(System.out::println);&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스트림 이용하기&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스트림 이용 과정은 다음과 같이 세 가지로 요약할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;질의를 수행할 (컬렉션 같은) 데이터 소스&lt;/li&gt;
&lt;li&gt;스트림 파이프라인을 구성할 중간 연산 연결&lt;/li&gt;
&lt;li&gt;스트림 파이프라인을 실행하고 결과를 만들 최종 연산&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;중간 연산&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 136px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px; text-align: left;&quot;&gt;&lt;b&gt;연산&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px; text-align: left;&quot;&gt;&lt;b&gt;형식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px; text-align: left;&quot;&gt;&lt;b&gt;반환 형식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px; text-align: left;&quot;&gt;&lt;b&gt;연산의 인수&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px; text-align: left;&quot;&gt;&lt;b&gt;함수 디스크립터&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;filter&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;중간 연산&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;Stream&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;Predicate&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;T &amp;rarr; boolean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;map&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;중간 연산&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;Stream&amp;lt;R&amp;gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;Function&amp;lt;T, R&amp;gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;T &amp;rarr; R&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;limit&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;중간 연산&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;Stream&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;sorted&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;중간 연산&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;Stream&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;Comparator&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;(T, T) &amp;rarr; int&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;distinct&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;중간 연산&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;Stream&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&amp;nbsp;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;최종 연산&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;연산&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;형식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;반환 형식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;목적&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;forEach&lt;/td&gt;
&lt;td&gt;최종 연산&lt;/td&gt;
&lt;td&gt;void&lt;/td&gt;
&lt;td&gt;스트림의 각 요소를 소비하면서 람다를 적용한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;count&lt;/td&gt;
&lt;td&gt;최종 연산&lt;/td&gt;
&lt;td&gt;long (generic)&lt;/td&gt;
&lt;td&gt;스트림의 요소 개수를 반홚나다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;collect&lt;/td&gt;
&lt;td&gt;최종 연산&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스트림은 소스에서 추출된 &lt;b&gt;연속 요소&lt;/b&gt;로, &lt;b&gt;데이터 처리 연산을 지원&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;스트림은 내부 반복을 지원한다. 내부 반복은 filter, map, sorted 등의 연산으로 반복을 추상화한다.&lt;/li&gt;
&lt;li&gt;스트림에는&lt;b&gt; 중간 연산&lt;/b&gt;과 &lt;b&gt;최종 연산&lt;/b&gt;이 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중간 연산&lt;/b&gt;을 이용해서 파이프라인을 구성할 수 있지만 &lt;b&gt;어떤 결과도 생성할 수 없다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;스트림이 아닌 &lt;b&gt;결과를 반환하는 연산&lt;/b&gt;을 &lt;b&gt;최종 연산&lt;/b&gt;이라고 한다.&lt;/li&gt;
&lt;li&gt;스트림의 요소는 요청할 때&lt;b&gt; lazily 하게 계산&lt;/b&gt;된다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>모던 자바 인 액션 스터디</category>
      <category>4장 스트림</category>
      <category>모던 자바 인 액션</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/104</guid>
      <comments>https://dding9code.tistory.com/104#entry104comment</comments>
      <pubDate>Mon, 9 May 2022 22:14:58 +0900</pubDate>
    </item>
    <item>
      <title>트랜젝션(Transaction)</title>
      <link>https://dding9code.tistory.com/102</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;트랜잭션&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜젝션은 데이터베이스 내에서 수행되는 더 이상 쪼갤 수 없는 &lt;b&gt;최소 작업의 단위&lt;/b&gt;로, &lt;b&gt;데이터베이스의 무결성을 유지하며 상태를 변화&lt;/b&gt;시키는 기능을 수행합니다.&amp;nbsp; 트랜잭션은 &lt;b&gt;원자성&lt;/b&gt;(Atomicity), &lt;b&gt;일관성&lt;/b&gt;(Consistency), &lt;b&gt;격리성&lt;/b&gt;(Isolation), &lt;b&gt;영구성&lt;/b&gt;(Durability) 를 보장합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 성질의 앞 글자를 따서 &lt;b&gt;ACID&lt;/b&gt; 라고 부릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*데이터베이스는 COMMIT 과 ROLLBACK 명령어를 통해 데이터의 무결성을 보장합니다.&lt;/p&gt;
&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;Commit&lt;/b&gt; : 모든 작업이 성공해서 데이터베이스에 정상 반영하는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Rollback&lt;/b&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;트랜잭션의 목적&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;은행 시스템에서 A 가 B에게 출금을해서 입금하는 상황이 있습니다.&amp;nbsp; 송금하려는 중 오류가 생겨서 A의 계좌에는 돈이 빠져나가고 B의 계좌에는 입금 되지 않았습니다. 이런 상황은 시스템의 치명적인 오류이며 이와 같은 상황을 막으려면 모든 입출금은 하나의 묶음 형태로 작동해야 합니다. 출금을 하면 입금까지 되던지 아니면 없던 일이 되어야 합니다. 이런 식으로 출금과 입금 두 행위는 더 이상 쪼갤 수 없는 최소 단위이며 이를 트랜잭션이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 데이터를 다룰 때 장애가 일어나는 경우 이 트랜잭션은 장애 발생시 데이터를 복구하는 작업의 단위가 됩니다. 또한 여러 작업이 동시에 같은 데이터에 접글할 때 트랜잭션을 통해 이 작업을 서로 분리하고 오류가 생기지 않게 합니다. 데이터베이스의 트랜잭션이 이러한 규칙을 유지하도록 지원합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;ACID&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;*Atomicity(&lt;/span&gt;원자성)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 트랜잭션에 포함된 작업은 하나의 작업인 것 처럼 전부 수행되거나 아니면 전부 수행되지 말아야 한다. (all or nothing)&lt;/p&gt;
&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 data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;*Consistency&lt;/span&gt;(일관성)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 모든 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ex) 송금 전 후 데이터의 타입이 바뀌면 안된다.&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 data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;*Isolation&lt;/span&gt;(격리성)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 동시에 실행되는 트랜잭션들이 서로에게 영향을 미치지 않도록 독립적으로 작업을 수행해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 동시성과 관련된 성능 이슈로 인해 &lt;b&gt;트랜잭션 격리 수준(Isolation level)&lt;/b&gt;을 선택할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;*Durability&lt;/span&gt;(지속성)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 성공적으로 수행된 트랜잭션은 데이터베이스에 영원히 반영되어야 한다. 저장이 완료 된 데이터베이스는 저장 후에 시스템에 문제가 생겨도 영향을 받지 않아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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>CS</category>
      <category>데이터베이스</category>
      <category>트랜잭션</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/102</guid>
      <comments>https://dding9code.tistory.com/102#entry102comment</comments>
      <pubDate>Tue, 3 May 2022 23:37:04 +0900</pubDate>
    </item>
    <item>
      <title>모던 자바 인 액션 - 3장 람다 표현식</title>
      <link>https://dding9code.tistory.com/101</link>
      <description>&lt;h1&gt;&lt;b&gt;람다표현식&lt;/b&gt;&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 람다 표현식을 어떻게 만드는지, 어떻게 사용하는지, 어떻게 코드를 간결하게 만들 수 있는지 설명하는 장입니다. 또한 자바 8 API에 추가된 중요한 인터페이스와 형식 추론 등의 기능도 확인하며, 마지막으로 람다 표현식과 함께 위력을 발휘하는 새로운 기능인 메서드 참조를 설명하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;람다란 무엇인가?&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;람다 표현식&lt;/b&gt;은 메서드로 전달할 수 있는 익명 함수를 단순화한 것이라고 할 수 있습니다. 람다 표현식에는 이름은 없지만, 파라미터 리스트, 바디, 반환 형식, 발생할 수 있는 예외 리스트는 가질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*람다의 특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;익명&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;보통의 메서드와 달리 이름이 없어 &lt;b&gt;익명이라&lt;/b&gt; 표현합니다. 구현해야 할 코드에 대한 걱정거리가 줄어든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;함수&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;람다는 메서드처럼 특정 클래스에 종속되지 않으므로 함수라고 부릅니다. 하지만 메서드처럼 파라미터 리스트, 바디, 반환 형식, 가능한 예외 리스트를 포함한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전달&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;람다 표현식을 메서드 인수로 전달하거나 변수로 저장할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간결성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;익명 클래스처럼 많은 자질구레한 코드를 구현할 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시)&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;Comparator&amp;lt;Car&amp;gt; byPrice = new Comparator&amp;lt;Car&amp;gt;() {
     @Override
     public int compare(Car o1, Car o2) {
     return o1.getPrice() - o2.getPrice();

     }  
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 많이 사용하는 Comparator를 사용하여 가격별로 오름차순을 할 수 있게 익명 클래스를 구현했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다표현식을 사용하면 코드를 더 간결하게 만들 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;Comparator&amp;lt;Car&amp;gt; byPrice = (o1, o2) -&amp;gt; o1.getPrice() - o2.getPrice();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다표현식을 사용하면 이처럼 compare 메서드의 바디를 직접 전달하는 것처럼 코드를 작성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 확인할 수 있듯이 람다 &lt;b&gt;파라미터&lt;/b&gt;, &lt;b&gt;화살표&lt;/b&gt;, &lt;b&gt;바디&lt;/b&gt; 로 이루어져 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;람다의 표현식은 2가지 스타일이 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;표현식 스타일 (expression style) - 람다라고 알려진 람다의 기본 문법&lt;/li&gt;
&lt;li&gt;(parameters) &amp;rarr; expression&lt;/li&gt;
&lt;li&gt;블록 스타일 (block - style)&lt;/li&gt;
&lt;li&gt;(parameters) &amp;rarr; { statements; }&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자바에서 람다 표현식을 작성할 때 유의해야 할 사항은 뭘까요?&lt;/b&gt;&lt;/p&gt;
&lt;ol 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;함수의 몸체가 하나의 return 문으로만 이루어진 경우에는 중괄호를 생략할 수 없습니다.&lt;/li&gt;
&lt;li&gt;return 문 대신 표현식을 사용할 수 있으며, 이때 반환값은 표현식의 결과값이 됩니다. (이때 세미콜론은 붙이지 않음)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다양한 람다 예제&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 118px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.0233%; height: 18px;&quot;&gt;&lt;b&gt;사용 사례&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 76.9767%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;람다 예제&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.0233%; height: 18px;&quot;&gt;불리언 표현식&lt;/td&gt;
&lt;td style=&quot;width: 76.9767%; height: 18px;&quot;&gt;(List&amp;lt;String&amp;gt; list) &amp;rarr; list.isEmpty( );&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.0233%; height: 18px;&quot;&gt;객체 생성&lt;/td&gt;
&lt;td style=&quot;width: 76.9767%; height: 18px;&quot;&gt;( ) &amp;rarr; new Car( )&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.0233%; height: 18px;&quot;&gt;객체에서 소비&lt;/td&gt;
&lt;td style=&quot;width: 76.9767%; height: 18px;&quot;&gt;(Car car) &amp;rarr; { System.out.println(car.getPrice()); }&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.0233%; height: 18px;&quot;&gt;객체에서 선택/추출&lt;/td&gt;
&lt;td style=&quot;width: 76.9767%; height: 18px;&quot;&gt;(Car car1, Car car2) &amp;rarr; car1.getPrice().compareTo(car2.getPrice())&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 23.0233%; height: 10px;&quot;&gt;두 값을 조합&lt;/td&gt;
&lt;td style=&quot;width: 76.9767%; height: 10px;&quot;&gt;(int a, int b) &amp;rarr; a * b&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.0233%; height: 18px;&quot;&gt;두 값을 비교&lt;/td&gt;
&lt;td style=&quot;width: 76.9767%; height: 18px;&quot;&gt;(Car car1, Car car2) &amp;rarr; car1.getPrice().compareTo(car2.getPrice())&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;어디에, 어떻게 람다를 사용할까?&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 람다 표현식을 배웠는데 정확히 어디에 사용할 수 있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash;&amp;gt; &lt;b&gt;함수형 인터페이스&lt;/b&gt;라는 문맥에서 람다 표현식을 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 인터페이스라는 말이 새로 등장을 했는데 함수형 인터페이스가 무엇인지 알아보러 갑시다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;함수형 인터페이스&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전에 만들었던 Predicate &amp;lt;T&amp;gt; 인터페이스로 필터 메서드를 파라미터화 할 수 있었음을 기억하나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Predicate &amp;lt;T&amp;gt;가 바로 함수형 인터페이스입니다. &lt;b&gt;함수형 인터페이스&lt;/b&gt;는 &lt;b&gt;오직 하나의 추상 메서드만 지정&lt;/b&gt;하기 때문입니다. Comparator, Runnable 등도 함수형 인터페이스 입니다.&lt;/p&gt;
&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;??? Comparator에는 안에는 다른 메서드도 많은데 왜 함수형 인터페이스 인가요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash;&amp;gt; 인터페이스는 *&lt;b&gt;디폴트 메서드&lt;/b&gt;를 포함할 수 있습니다. 많은 디폴트 메서드가 있더라도 &lt;b&gt;추상 메서드가 오직 하나면 함수형 인터페이스입니다.&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 Object 클래스 메서드는 디폴트 메서드 취급을 합니다!! equals, hashCode 등등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;디폴트 메서드&lt;/b&gt; : 인터페이스의 메서드를 구현하지 않은 클래스를 고려해서 기본 구현을 제공하는 바디를 포함하는 메서드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함수형 인터페이스로 뭘 할 수 있을까요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 람다 표현식으로 함수형 인터페이스의 추상 메서드 구현을 직접 전달할 수 있으므로 &lt;b&gt;전체 표현식을 함수형 인터페이스의 인스턴스 취급&lt;/b&gt; (기술적으로 따지면 함수형 인터페이스를 &lt;b&gt;구현한&lt;/b&gt; 클래스의 인스턴스) 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;함수 디스크립터&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 인터페이스의 추상 메서드 시그니처는 람다 표현식의 시그니처를 가리킵니다. 람다 표현식의 시그니처를 서술하는 메서드를 &lt;b&gt;함수 디스크립터라고&lt;/b&gt; 부릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 Runnable 인터페이스의 &lt;b&gt;유일한 추상 메서드 run은 인수와 반환값(void)이 없으므로&lt;/b&gt; Runnable 인터페이스는 &lt;b&gt;인수와 반환값이 없는 시그니처&lt;/b&gt;로 생각할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( ) &amp;rarr; void 표기는 파라미터 리스트가 없으며 void를 반환하는 함수를 의미합니다. 앞서 설명한 Runnable이 이에 해당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;예제)&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;public void process(Runnable r){
	 r.run();
}

process(() -&amp;gt; System.out.println(&quot;Lamda is good&quot;));

//process(() -&amp;gt; { System.out.println(&quot;Lamda is good&quot;)); };
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;() -&amp;gt; System.out.println(&quot;Lamda is good&quot;) 은 인수가 없으며 void를 반환하는 람다 표현식이다. 이는 &lt;b&gt;Runnable 인터페이스의 run 메서드 시그니처와 같습니다.&lt;/b&gt; 직접 들어가서 확인해 보면 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 여기서 &lt;b&gt;@FunctionalInterface&lt;/b&gt;가 있습니다. 여기서 &lt;b&gt;@FunctionalInterface는 무엇일까요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--&amp;gt; 이 어노테이션은 바로 &lt;b&gt;함수형 인터페이스임을 가리키는 어노테이션&lt;/b&gt;입니다. 해당 어노테이션을 사용하게 되면 함수형 인터페이스가 아니게 되면 컴파일러가 에러를 발생시킵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;람다 활용 : 실행 어라운드 패턴&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다와 동작 파라미터화로 유연하고 간결한 코드를 구현하는 데 도움을 주는 실용적인 예제를 살펴봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자원 처리에 사용하는 순환 패턴은 자원을 열고, 처리한 다음에, 자원을 닫는 순서로 이루어집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 자원을 처리하는 코드를 설정과 정리 두 과정이 둘러싸는 형태를 갖습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public String processFile() throws IOException{
        try(BufferedReader br = new BufferedReader(new FileReader(&quot;data.txt&quot;))){
            return br.readLine();
        }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 파라미터화&lt;/b&gt;를 떠올린다면 다양하게 바뀌는 &lt;b&gt;요구사항에 전략적으로 대응&lt;/b&gt;을 할 수 있었습니다. 작업 A, 작업 B만 다르고 나머지 부분은 같습니다. 그러면 &lt;b&gt;반복되는 코드를 추상화&lt;/b&gt;하여 다른 동작을 수행할 수 있도록 만들어 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업을 제외한 설정, 정리 과정은 재사용하고 &lt;b&gt;processFile을 동작 파라미터화&lt;/b&gt;하여 다른 동작을 수행할 수 있도록 만들면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BufferedReader를 인수로 받아 String을 반환하고 IOExeption을 던질 수 있는 형태의 시그니처와 일치하는 &lt;b&gt;함수형 인터페이스를 만들어야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;BufferedReader&lt;/b&gt; &amp;rarr; &lt;b&gt;String&lt;/b&gt;&amp;nbsp; thorws IOExeption&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@FunctionalInterface
public interface BufferedReaderProcessor {
    String process(BufferedReader b) throws IOException;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인터페이스를 BufferedReaderProcessor&lt;/b&gt; 라고 정의를 하였고, 정의한 &lt;b&gt;인터페이스를&lt;/b&gt; &lt;b&gt;processFile 메서드의 인수로 전달&lt;/b&gt;할 수 있게 되었습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public String processFile(BufferedReaderProcessor p) throws IOException{
    try(BufferedReader br = new BufferedReader(new FileReader(&quot;data.txt&quot;))){
         return p.process(br);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 BufferedReaderProcessor에 정의된 process 메서드의 시그니처 (&lt;b&gt;BufferedReader &amp;rarr; String&lt;/b&gt;) 과 일치하는 람다를 전달할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;String oneLine = processFile((BufferedReader br) -&amp;gt; br.readLine());

//또는
String twoLine = processFile(br -&amp;gt; br.readLine() + br.readLine());
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약에 단순 일회성이 아닌 사용하는 곳이 많아진다면 람다를 사용하는 게 아닌 BufferedReaderProceesor를 직접 구현한 클래스를 만들어서 사용하는 것이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;함수형 인터페이스 사용&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 복습하면, &lt;b&gt;함수형 인터페이스는 오직 하나의 추상 메서드를 지정&lt;/b&gt;한다고 설명드렸습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함수형 인터페이스의 추상 메서드는 람다 표현식의 시그니처를 묘사&lt;/b&gt;합니다. 함수형 인터페이스의 추상 메서드 시그니처를 &lt;b&gt;함수 디스크립터&lt;/b&gt;라고 합니다. 다양한 람다 표현식을 사용하려면 공통의 함수 디스크럽터를 기술하는 함수형 인터페이스 집합이 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 자바 API는 다양한 함수형 인터페이스를 포함하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) Predicate, Comparable, Runnable, Callable...&lt;/p&gt;
&lt;p data-ke-size=&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;u&gt;&lt;b&gt;*기본형 특화&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바의 모든 형식은 참조형 아니면 기본형에 해당합니다. 하지만 제네릭 파라미터에는 참조형만 사용할 수 있습니다. 제네릭의 내부 구현 때문에 어쩔 수 없는 일입니다. 자바에서는 기본형을 참조형으로 변환하는 기능을 제공하는데 이 기능을 &lt;b&gt;박싱(boxing)&lt;/b&gt; 이라고 하고, 참조형에서 기본형에서 변환하는 기능을 &lt;b&gt;언박싱(unboxing)이라고&lt;/b&gt; 이라고 합니다. 또한 프로그래머가 편리하게 코드를 구현할 수 있도록 해당 기능이 자동으로 이루어지는데 그 기능을 &lt;b&gt;오토박싱&lt;/b&gt; 이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;ex) ArrayList&amp;lt;Integer&amp;gt; list 에 int 자료형을 추가할 때 list.add(10), list,add(20) . . .&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하지만 이런 변환 과정은 비용이 소모&lt;/b&gt;가 됩니다. 박싱한 값은 기본형을 감싸는 래퍼며 힙에 저장됩니다. 따라서 &lt;b&gt;박싱한 값은 메모리를 더 소비하며 기본형을 가져올 때도 메모리를 탐색하는 과정이 필요&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 자바 8에서는 기본형을 입출력으로 사용하는 상황에서 오토박싱 동작을 피할 수 있도록 특별한 버전의 함수형 인터페이스를 제공해줍니다. ex) &lt;b&gt;Double&lt;/b&gt;Predicate, &lt;b&gt;In&lt;/b&gt;tConsumer, &lt;b&gt;Long&lt;/b&gt;BinaryOperatior, &lt;b&gt;ToInt&lt;/b&gt;Function, I&lt;b&gt;ntToDouble&lt;/b&gt;Function&lt;/p&gt;
&lt;p data-ke-size=&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;u&gt;*&lt;b&gt;예외, 람다, 함수형 인터페이스의 관계&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr;&lt;b&gt; 함수형 인터페이스는 확인된 예외를 던지는 동작을 허용하지 않습니다.&lt;/b&gt; 즉, 예외를 던지는 람다표현식을 만들려면 확인된 예외를 선언하는 함수형 인터페이스를 직접 정의하거나 람다를 try/catch 블록으로 감싸야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 BufferedReaderProcessor 인터페이스와 달리 Function&amp;lt;T, R&amp;gt; 형식의 함수형 인터페이스를 기대하는 API를 사용하고 있으며 직접 함수형 인터페이스를 만들기 어려운 상황에 다음처럼 명시적으로 확인된 예외를 잡을 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;Function&amp;lt;BufferedReader, String&amp;gt; f = (BufferedReader b) -&amp;gt; {
        try {
            return b.readLine()
        } catch (IOException e) {
            throw new RuntimeException(e);
      	}       
};
&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;&amp;nbsp;&lt;/h3&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;b&gt;형식 검사&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다가 사용하는 *&lt;b&gt;콘텍스트&lt;/b&gt;를 이용해서 람다의 형식을 추론할 수 있습니다. 어떤 콘텍스트에서 기대되는 람다 표현식의 형식을 &lt;b&gt;대상 형식(target type)&lt;/b&gt; 이라고 부릅니다. 람다 표현식을 사용할 때 실제 어떤 일이 일어나는지 보여주는 예제를 보여드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*콘텍스트&lt;/b&gt; : 람다가 전달될 메서드 파라미터나 람다가 할당되는 변수 등&lt;/p&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;public static &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; filter(List&amp;lt;T&amp;gt; list, Predicate&amp;lt;T&amp;gt; p) {
     List&amp;lt;T&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();
     for (T e : list) {
         if (p.test(e)) {
             result.add(e);
         }
     }
     return result;
}

List&amp;lt;Car&amp;gt; carGV70 = filter(carList, car -&amp;gt; car.getModel() == Model.GV70);
&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;람다가 사용된 콘텍스트는 뭐지? filter 메서드의 선언을 확인한다.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;filter 메서드는 두 번째 파라미터로 Predicate&amp;lt;Car&amp;gt; 형식( 대상 형식 ) 을 기대한다.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;Predicate&amp;lt;Car&amp;gt;는 test라는 한 개의 추상 메서드를 정의하는 함수형 인터페이스다.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;test 메서드는 Car를 받아 boolean을 반환하는 함수 디스크립터를 묘사한다.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;filter 메서드로 전달된 인수는 이와 같은 요구사항을 만족해야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Car &amp;rarr; boolean 이므로 람다의 시그니처와 일치한다!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;같은 람다, 다른 함수형 인터페이스&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;대상 형식&lt;/b&gt;이라는 특징 때문에 같은 람다 표현식이더라도 호환되는 추상 메서드를 가진 다른 함수형 인터페이스로 사용될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 Callabe과 PrivilegedAction 인터페이스는 인수를 받지 않고 제네릭 형식 T를 반환하는 함수를 정의합니다. 따라서 아래와 같은 코드는 모두 유효합니다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;Callable&amp;lt;Integer&amp;gt; c = () -&amp;gt; 42;
PrivilegedAction&amp;lt;Integer&amp;gt; p = () -&amp;gt; 42;

Callable&amp;lt;String&amp;gt; c = () -&amp;gt; &quot;abc&quot;;
PrivilegedAction&amp;lt;String&amp;gt; p = () -&amp;gt; &quot;abc&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;할당문 콘텍스트, 메서드 호출 콘텍스트(파라미터, 반환값), 형변환 콘텍스트 등으로 람다 표현식의 형식을 추론할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public static void example(Callable c) throws Exception {
    c.call();
}

public static void example(PrivilegedAction p){
     p.run(); 
}

example(() -&amp;gt; 10);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;만약 위와 같은 코드가 있으면 제대로 수행을 할까요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 정답은 아닙니다. 왜냐하면 Callable과 PrivilegedAction의 함수 디스크립터가 같으므로 example메서드가 누구를 가리키는지 명확하지 않습니다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;example((PrivilegedAction) () -&amp;gt; 10);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 &lt;b&gt;캐스팅&lt;/b&gt;을 하면 누구를 호출할 것인지가 명확해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;형식 추론&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 좀 더 단순하게 만들 수 있는 방법이 있습니다. 자바 컴파일러는 람다 표현식이 사용된 콘텍스트(대상 형식)을 이용해서 람다 표현식과 관련된 함수형 인터페이스를 추론합니다. 즉, &lt;b&gt;대상 형식을 이용해서 함수 디스크립터를 알 수 있으므로 컴파일러는 람다의 시그니처도 추론할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 &lt;b&gt;컴파일러는 람다 표현식의 파라미터 형식에 접근&lt;/b&gt;할 수 있으므로&lt;b&gt; 람다 문법에서 이를 생략&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;Comparator&amp;lt;Car&amp;gt; byPrice = (Car c1, Car c2) -&amp;gt; c1.getPrice() - c2.getPrice();

Comparator&amp;lt;Car&amp;gt; byPrice = (c1, c2) -&amp;gt; c1.getPrice() - c2.getPrice()&amp;nbsp;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 꼭 반드시 생략하는 게 좋다고는 할 수 없습니다! 프로그래머가 판단하기에 상황에 따라서 어떻게 쓰면 더 좋은지 결정해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;지역 변수 사용&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지는 람다 표현식은 인수를 자신의 바디 안에서만 사용했습니다. 하지만 람다 표현식에서는 익명 함수가 하는 것처럼 &lt;b&gt;자유 변수&lt;/b&gt;(파라미터로 넘겨진 변수가 아닌 외부에서 정의된 변수)를 활용할 수 있다. 이와 같은 동작을 &lt;b&gt;람다 캡쳐링&lt;/b&gt;이라고 부릅니다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;Integer a = 100;
Callable&amp;lt;Integer&amp;gt; c = () -&amp;gt; a;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 제약 조건이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다는 인스턴스 변수와 정적 변수를 자유롭게 캡쳐(자신의 바디에서 참조할 수 있도록)할 수 있습니다. 하지만 그러려면 지역변수는 명시적으로 &lt;b&gt;final 선언&lt;/b&gt;이 되어있거나, &lt;b&gt;실질적으로 final처럼 사용&lt;/b&gt;을 해야 합니다. 즉 &lt;b&gt;람다 표현식은 한 번만 할당할 수 있는 지역 변수를 캡쳐할 수 있습니다&lt;/b&gt;. ( 인스턴스 변수 캡처는 final 지역변수 this를 캡쳐하는 것과 마찬가지)&lt;/p&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;Integer a = 100;
Callable&amp;lt;Integer&amp;gt; c = () -&amp;gt; a; //에러 a의 값이 변함
a++; 
&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;u&gt;*&lt;b&gt;지역 변수의 제약&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 지역 변수에 이런 제약이 필요로 할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;우선 인스턴스 변수(힙 영역)와 지역 변수(스택 영역)는 메모리에 저장되는 위치부터 다릅니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다에서 지역 변수에 바로 접근할 수 있다는 가정하에 람다가 스레드에서 실행이 되면 변수를 할당한 스레드가 사라져서 변수 할당이 해제되었는데도 람다가 실행하는 스레드에서는 해당 변수에 접근하려 할 수 있습니다. 따라서 자바 구현에서는 원래 변수에 접근을 허용하는 것이 아니라 자유 지역 변수의 복사본을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 복사본의 값이 바뀌지 않아야 하므로 지역 변수에는 한 번만 값을 할당해야 한다는 제약이 생겼습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;메서드 참조&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드 참조를 이용하면 &lt;b&gt;기존의 메서드 정의를 재활용해서 람다처럼 전달할 수 있습니다.&lt;/b&gt; 때로는 람다 표현식 보다 메서드 참조를 사용하는 것이 더 가독성이 좋으며 자연스러울 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;carList.sort((o1, o2) -&amp;gt; o1.getPrice() - o2.getPrice());
carList.sort(comparing(Car::getPrice));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜 메서드 참조가 중요할까요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 메서드 참조는 특정 메서드만을 호출하는 람다의 축약형이라고 생각할 수 있습니다. 메서드를 어떻게 호출해야 하는지 설명을 참조하기보다는 메서드명을 직접 참조하는 것이 편리합니다. 명시적으로 메서드를 참조함으로써 가독성을 높일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;메서드 참조를 만드는 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 메서드 참조는 세 가지 유형으로 구분할 수 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정적 메서드 참조&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Integer의 parseInt메서드는 Integer::parseInt로 표현할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다양한 형식의 인스턴스 메서드 참조&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;String의 length 메서드는 String::length로 표현할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기존 객체 인스턴스 메서드 참조&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어 Transcation 객체를 할당받은 expensiveTransaction 지역 변수가 있고, Transaction 객체에는 getValue메서드가 있다면, 이를 expensiveTransaction::getValue 라고 표현할 수 있습니다.&lt;/li&gt;
&lt;li&gt;비공개 메서드를 정의한 상황에서 유용하게 활용이 가능 람다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; str = Array.asList(&quot;a&quot;, &quot;b&quot;, &quot;A&quot;, &quot;B&quot;);
str.sort((s1, s2) -&amp;gt; s1.comparToIgnoreCase(s2));

//메서드 참조 사용
List&amp;lt;String&amp;gt; str = Array.asList(&quot;a&quot;, &quot;b&quot;, &quot;A&quot;, &quot;B&quot;);
str.sort(String::compareToIgnoreCase);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일러는 람다 표현식의 형식을 검사하던 방식과 비슷한 과정으로 메서드 참조가 주어진 함수형 인터페이스와 호환하는지 확인한다. 즉, 메서드 참조는 콘텍스트의 형식과 일치해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;생성자 참조&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ClassName::new 처럼 클래스명과 new 키워드를 이용해서 기존 생성자의 참조를 만들 수 있습니다. 정적 메서드의 참조를 만드는 방법과 비슷한데. 예를 들어 Supplier의 () &amp;rarr; Car 와 같은 시그니처를 갖는 생성자가 있다고 가정해봅시다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;Supplier&amp;lt;Car&amp;gt; c1 = Car::new;
Car c2 = c1.get(); //Supplier의 get 메서드를 호출해서 새로운 Car객체를 만들 수 있다.

//아래와 같다.
Supplier&amp;lt;Car&amp;gt; c1 = () -&amp;gt; new Car();
Car c2 = c1.get();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스화 하지 않고도 생성자에 접근할 수 있는 기능을 다양한 상황에 응용할 수 있습니다. 예를 들어 Map으로 생성자와 문자열 값을 관련시킬 수 있다. String과 Integer가 주어졌을 때 다양한 가격을 만드는 giveMeCar라는 메서드를 만들 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;static Map&amp;lt;String, Function&amp;lt;Integer, Car&amp;gt;&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
    
static {
    map.put(&quot;gv60&quot;, Car::new);
    map.put(&quot;k3&quot;, Car::new);
}
    
public static Car giveMeCar(String car,Integer price){
    return map.get(car).apply(price);
}
&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;&amp;nbsp;&lt;/h3&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;b&gt;람다 표현식을 조합할 수 있는 유용한 메서드&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8 API 의 몇몇 함수형 인터페이스는 다양한 유틸리티 메서드를 포함합니다. 예를 들어 &lt;b&gt;Comparator, Function, Predicate&lt;/b&gt; 같은 &lt;b&gt;함수형 인터페이스는 람다 표현식을 조합할 수 있도록 유틸리티 메서드를 제공&lt;/b&gt;합니다. 간단하게 여러 개의 람다 표현식을 조합해서 복잡한 람다 표현식을 만들 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 이 유틸리티 메서드가 &lt;b&gt;디폴트 메서드입니다.&lt;/b&gt; 자세한 건 추후에 나오지만 간단하게 Comparator만 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&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;Comparator 조합&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에도 보았듯이, 정적 메서드 Comparator.comparing을 이용해서 비교에 사용할 키를 추출하는 Function 기반의 Comparator를 반환할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;Comparator&amp;lt;Car&amp;gt; c = Comparator.comparing(Car::getPrice);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약에 가격을 내림차순으로 만들자 하면 어떻게 해야 할까요? 또 다른 Comparator인스턴스를 만들 필요가 없습니다. 인스턴스 자체에서 주어진 비교자의 순서를 뒤바꾸는 &lt;b&gt;reverse라는 디폴트 메서드&lt;/b&gt;를 제공하기 때문입니다.&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;Comparator&amp;lt;Car&amp;gt; c = Comparator.comparing(Car::getPrice).reversed();
carList.sort(c);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 가격이 같은 차량이 존재해야 한다면 어떻게 해야할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때는 &lt;b&gt;thenComparing 메서드&lt;/b&gt;로 두 번째 비교자를 만들 수 있습니다. thenComparing은 (comparing메서드 처럼) 함수를 인자로 받아 첫 번째 비교자를 이용해서 두 객체가 같다고 판단되면 두 번째 비교자에 객체를 전달합니다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;carList.sort(c.thenComparing(Car::getModel)); //두 차의 가격이 같으면 모델명으로 정렬
&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;&amp;nbsp;&lt;/h3&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;b&gt;마무리&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;람다 표현식&lt;/b&gt;은 익명 함수의 일종이다. 이름은 없지만 파라미터 리스트, 바디, 반환 형식을 가지며 예외를 던질 수 있습니다.&lt;/li&gt;
&lt;li&gt;람다 표현식을 통해 간결한 코드를 구현할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;함수형 인터페이스&lt;/b&gt;란 단 하나의 추상 메서드만을 정의하는 인터페이스입니다.&lt;/li&gt;
&lt;li&gt;람다 표현식 전체가 함수형 인터페이스의 인스턴스로 취급됩니다.&lt;/li&gt;
&lt;li&gt;자바 8은 오토박싱 동작을 피할 수 잇는 기본형 특화 인터페이스도 제공합니다.&lt;/li&gt;
&lt;li&gt;람다 표현식의 기대 형식을 대상 형식이라고 합니다.&lt;/li&gt;
&lt;li&gt;메서드 참조를 이용하면 기존의 메서드 구현을 재사용하고 직접 전달할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>모던 자바 인 액션 스터디</category>
      <category>3장</category>
      <category>모던 자바 인 액션</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/101</guid>
      <comments>https://dding9code.tistory.com/101#entry101comment</comments>
      <pubDate>Mon, 2 May 2022 23:44:21 +0900</pubDate>
    </item>
    <item>
      <title>가상메모리(virtual memory)</title>
      <link>https://dding9code.tistory.com/100</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;가상메모리(virtual memory)&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;=&amp;gt; 램과 하드디스크를 하나의 추상화된 메모리 영역으로 제공한다.&lt;/b&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;u&gt;&lt;b&gt;가상메모리는 왜 태어났는가?&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예전 도스시절 하나의 프로그램만 실행시키던 그 때 프로그램이 메모리를 사용하다가 프로그램이 죽는경우 이 메모리를 회수시킬 방법이 없어 결국 OS를 재시작하게 되는 문제로부터 시작되었다고 한다..&lt;/li&gt;
&lt;li&gt;즉, 프로세스가 운영체제(시스템) 전체에 문제가 나는것을 막기 위해&lt;/li&gt;
&lt;li&gt;프로세스의가 사용하는 공간을 가상세계로 범위를 제한시켜 애플리케이션이 죽어도 OS는 살아남는다. (시스템 안정성을 위해)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;가상메모리 사용하면 가장 좋은점&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OS가 프로그램에게 가상메모리 영역을 할당하기 때문에 프로그램이 뻗어도 OS가 해당 프로그램의 주소위치를 알기 때문에 자원을 회수할 수 있어 메모리의 낭비가 없고, 프로그램이 죽어도 OS에 영향이 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로세스 전체가 메모리에 올라오지 않더라도 실행이 가능&lt;/b&gt;하도록 하는 기법, 가상 메모리 기법을 통해 사용자 프로그램이 물리적 메모리보다 커져도 실행이 가능하도록 만듭니다. 가상메모리는 실제의 물리 메모리 개념과 사용자 관점의 논리 메모리를 분리한 것입니다. 그래서 사용자가 메모리 크기에 관련한 문제를 염려하지 않아도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제는 가상 메모리 기법을 통해 프로그램의 논리적주소 영역에서 필요한 부분만 물리적 메모리에 적재하고, 직접적으로 필요하지 않은메모리 공간은 디스크에 저장하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 필요한 부분만 어떻게 물리적 메모리에 적재를 할까요?&amp;nbsp; 아래를 확인하시면 됩니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;요구페이징(demand paging)&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;필요한 부분만 물리적 메모리에 page단위로 적재하는 방법&lt;/b&gt;을 &lt;b&gt;요구 페이징 &lt;/b&gt;이라고 합니다. 요구 페이징 기법에서는 특정 page에 대해 cpu요청이 들어온 후에 해당 page를 메모리에 적재합니다. 그렇기 때문에 당장 필요한 page만을 메모리에 적재하기 때문에 메모리 사용량이 감소하고, 프로세스 전체를 메모링 적재하는 입출력 오버헤드도 감소하는 장점이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요구 페이징 기법에서는 *&lt;b&gt;유효/무효 비트(valid/invalid bit)를&amp;nbsp;&lt;/b&gt;두어 각 page가 메모리에 존재하는지 표시하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*유효/무효 비트&lt;/b&gt; : &lt;b&gt;해당 비트가 유효하면 메모리에 있음을 의미하고, 무효하면 메모리에 없음을 의미합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;* Page fault&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CPU가 무효비트로 표시된 page에 엑세스하는 상황&lt;/b&gt;을 page fault라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;페이지 부재를 처리하는 과정&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU가 특정 페이지를 접근하여 페이지 테이블에서 무효 상태인지 아닌지 확인을 합니다.&lt;/li&gt;
&lt;li&gt;페이지가 무효 상태일 경우 &lt;b&gt;*MMU&lt;/b&gt;에서 Page fault trap이 발생합니다.&lt;/li&gt;
&lt;li&gt;디스크에서 해당 페이지를 빈 프레임에 적재하고 페이지 테이블을 업데이트 합니다. (무효 -&amp;gt; 유효)&lt;/li&gt;
&lt;li&gt;트랩에 의해 중단되었던 명령을 다시 수행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*MMU : 가상 주소를 물리 메모리 주소로 변환해주는 하드웨어 장치&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;*Page 교체 알고리즘(replacement algorithm)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;page fault가 발생하면, 요쳥된 page를 디스크에서 메모리로 가져옵니다. 이 때 물리적 메모리 공간이 부족한 상황이 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때 메모리에 올라와 있는 page를 디스크로 옮겨서 메모리 공간을 확보해야 합니다. 이를 페이지 교체라고 하고, 어떤 page를 교체할지 결정하는 방법은 Page 교체 알고리즘에 따라 달라집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 교체 알고리즘은 최대한 page fault가 적게 일어나도록 도와줘야 합니다. 그래서 앞으로 사용될 일이 적은 page를 선택하여 교체하는 것이 성능을 향상시킬 수 있습니다.&lt;/p&gt;
&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25.8139%;&quot;&gt;알고리즘&lt;/td&gt;
&lt;td style=&quot;width: 74.1861%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25.8139%;&quot;&gt;OPT(Optimal)&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 74.1861%;&quot;&gt;앞으로 가장 오랫동안 사용하지 않을 page를 찾아 교체한다. &lt;br /&gt;하지만 실제로 구현하기 거의 불가능한 알고리즘 이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25.8139%;&quot;&gt;FIFO(First in First Out)&lt;/td&gt;
&lt;td style=&quot;width: 74.1861%;&quot;&gt;메모리에 올라온지 가장 오래된 page를 교체하는 알고리즘.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25.8139%;&quot;&gt;LRU(Least Recently Used)&lt;/td&gt;
&lt;td style=&quot;width: 74.1861%;&quot;&gt;가장 오랫동안 사용하지 않은 page를 교체하는 알고리즘.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25.8139%;&quot;&gt;LFU(Least Frequently Used)&lt;/td&gt;
&lt;td style=&quot;width: 74.1861%;&quot;&gt;가장 참조횟수가 적은 page를 교체하는 알고리즘.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;[참고]&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=dPoNLIPo3_8&amp;amp;ab_channel=%EB%84%90%EB%84%90%ED%95%9C%EA%B0%9C%EB%B0%9C%EC%9E%90TV&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;널널한 개발자YOUTUBE&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>CS</category>
      <category>가상메모리</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/100</guid>
      <comments>https://dding9code.tistory.com/100#entry100comment</comments>
      <pubDate>Sat, 30 Apr 2022 23:31:17 +0900</pubDate>
    </item>
    <item>
      <title>[백준 2343] 기타레슨 - JAVA</title>
      <link>https://dding9code.tistory.com/99</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2343&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/2343&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1651562311706&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;2343번: 기타 레슨&quot; data-og-description=&quot;강토는 자신의 기타 강의 동영상을 블루레이로 만들어 판매하려고 한다. 블루레이에는 총 N개의 강의가&amp;nbsp;들어가는데, 블루레이를 녹화할 때, 강의의 순서가 바뀌면 안 된다. 순서가 뒤바뀌는 경&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/2343&quot; data-og-url=&quot;https://www.acmicpc.net/problem/2343&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bRdzRC/hyOgucQqie/NPU1KdelPo0G1JkI3kFsG0/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2343&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/2343&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bRdzRC/hyOgucQqie/NPU1KdelPo0G1JkI3kFsG0/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;2343번: 기타 레슨&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;강토는 자신의 기타 강의 동영상을 블루레이로 만들어 판매하려고 한다. 블루레이에는 총 N개의 강의가&amp;nbsp;들어가는데, 블루레이를 녹화할 때, 강의의 순서가 바뀌면 안 된다. 순서가 뒤바뀌는 경&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-03 오후 4.18.20.png&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOhHGi/btrA8ViHrl4/vtrvbLwJbAMr6gBmRhLCw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOhHGi/btrA8ViHrl4/vtrvbLwJbAMr6gBmRhLCw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOhHGi/btrA8ViHrl4/vtrvbLwJbAMr6gBmRhLCw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOhHGi%2FbtrA8ViHrl4%2FvtrvbLwJbAMr6gBmRhLCw0%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;1154&quot; height=&quot;530&quot; data-filename=&quot;스크린샷 2022-05-03 오후 4.18.20.png&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;530&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제풀이&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;*접근방법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 제한 조건이 강의의 수는 100,000 과 각 강의의 길이는 10,000분이 넘지 않는다고 주어졌다. 여기서 가능한 블루레이의 크기 중 최소를 구하는 프로그램을 만들어야 하는데 최대치를 두고 생각을 했을 때는 너무 터무니 없이 큰 제한이라&lt;b&gt; 블루레이의 크기를 기준으로 이분탐색&lt;/b&gt;을 하면 찾을 수 있겠다 라고 생각이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 보통 이분탐색은 정렬된 곳에서 찾는게 보통인데 해당 문제에서는 &lt;b&gt;강의의 순서가 뒤바 뀌면 안된다&lt;/b&gt; 라고 적혀있다. 따라서 정렬을 하지 않고 &lt;b&gt;블루레이의 길이에 따라 만들어지는 강의의 수를 체크&lt;/b&gt;하여 &lt;b&gt;가장 최소의 길이가 되는 블루레이 크기를 구해야한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;소스코드&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1651563092769&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());
        int[] lessonList = new int[n];

        int left = 0;
        int right = 0;
        st = new StringTokenizer(br.readLine());
        for (int i = 0; i &amp;lt; n; i++) {
            lessonList[i] = Integer.parseInt(st.nextToken());
            right += lessonList[i];
            left = Math.max(left, lessonList[i]);
        }

        while (left &amp;lt;= right) {
            int mid = (left + right) / 2;

            int count = getCount(n, lessonList, mid);

            if(count &amp;gt; m){
                left = mid + 1;
            }else{
                right = mid - 1;
            }
        }

        System.out.println(left);
    }

    private static int getCount(int n, int[] lessonList, int mid) {
        int sum = 0;
        int count = 0;
        for (int i = 0; i &amp;lt; n; i++) {
            if (sum + lessonList[i] &amp;gt; mid) {
                sum = 0;
                count++;
            }
            sum += lessonList[i];
        }

        if(sum != 0) count++;
        return count;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준 문제풀이</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/99</guid>
      <comments>https://dding9code.tistory.com/99#entry99comment</comments>
      <pubDate>Fri, 29 Apr 2022 23:24:47 +0900</pubDate>
    </item>
    <item>
      <title>[백준 - 2615] 오목 - JAVA</title>
      <link>https://dding9code.tistory.com/98</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2615&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/2615&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1651561455634&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;2615번: 오목&quot; data-og-description=&quot;오목은 바둑판에 검은 바둑알과 흰 바둑알을 교대로 놓아서 겨루는 게임이다. 바둑판에는 19개의 가로줄과 19개의 세로줄이 그려져 있는데 가로줄은 위에서부터 아래로 1번, 2번, ... ,19번의 번호&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/2615&quot; data-og-url=&quot;https://www.acmicpc.net/problem/2615&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dhz4HE/hyOgxOat6K/yGgF84PQwEefwPbDCmEBa1/img.jpg?width=548&amp;amp;height=606&amp;amp;face=0_0_548_606&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2615&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/2615&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dhz4HE/hyOgxOat6K/yGgF84PQwEefwPbDCmEBa1/img.jpg?width=548&amp;amp;height=606&amp;amp;face=0_0_548_606');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;2615번: 오목&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오목은 바둑판에 검은 바둑알과 흰 바둑알을 교대로 놓아서 겨루는 게임이다. 바둑판에는 19개의 가로줄과 19개의 세로줄이 그려져 있는데 가로줄은 위에서부터 아래로 1번, 2번, ... ,19번의 번호&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-03 오후 4.03.30.png&quot; data-origin-width=&quot;1156&quot; data-origin-height=&quot;793&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W0b48/btrA7Oxifgy/JkLNZgfL3FHNwKYfMHEUH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W0b48/btrA7Oxifgy/JkLNZgfL3FHNwKYfMHEUH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W0b48/btrA7Oxifgy/JkLNZgfL3FHNwKYfMHEUH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW0b48%2FbtrA7Oxifgy%2FJkLNZgfL3FHNwKYfMHEUH0%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;1156&quot; height=&quot;793&quot; data-filename=&quot;스크린샷 2022-05-03 오후 4.03.30.png&quot; data-origin-width=&quot;1156&quot; data-origin-height=&quot;793&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제풀이&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 제한조건이 생각보다 까따로웠다. 연속적 5알이 되는 색이 이기는 구조인데, 검은색과 흰색이 동시에 이기는 경우도 없고, 두 곳 이상에서 이기는 경우도 없다. 제일 중요한 &lt;b&gt;제한조건인 여섯알이 연속적으로 놓은 경우 이긴 것이 아니다.&lt;/b&gt;&amp;nbsp;라는 말이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여섯알이 될 경우 승부가 결정이 안나 0을 출력해야한다는 것으로 착각했지만 다른 곳에 오목이 되면 그 색이 이기는 문제였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;*접근방법&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 오목판은 19 * 19 고정인 배열 이기 때문에 시간복잡도는 크게 걱정하지 않아도 된다고 생각을 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;연속적으로 5알&lt;/b&gt;을 찾는다와, 각 이동하는 칸의 가중치가 1이기 때문에 Bfs 탐색을 생각했습니다.&lt;/p&gt;
&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;갈 수 있는 방향은 8가지&lt;/b&gt; 입니다. 상하좌우 + 대각선4방향 하지만 모든 정점에서 8방향으로 탐색하게 된다면연속적인 5알 이상인 곳에서 어느 한 알에서 출발할 경우 5알이 될 때 와 5알 이상이 되는 경우를 처리하기가 매우 까다로워 집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;진행방향과 반대방향을 동시에 체크&lt;/b&gt;를 하면 위의 문제를 해결하면서 탐색이 가능해 집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 아이디어를 토대로 열심히 구현을 하면 됩니다. 참고로 방향 설정에 유의해야 합니다. 제가 구현한 코드는 +4를 하면 반대방향을 찾도록 구현을 했는데 다른 방법도 사용이 가능하니 더 좋은방법이 있으면 해당 방법으로 구현하셔도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;소스코드&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1651561934358&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {
    static int n = 19;
    static int[][] map;
    static boolean[][] check;
    static boolean[][] winCheck;
    static final int[] dx = {-1, 0, -1, -1, 1, 0, 1, 1};
    static final int[] dy = {0, -1, -1, 1, 0, 1, 1, -1};
    static ArrayList&amp;lt;Node&amp;gt; list;
    static StringBuilder sb = new StringBuilder();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        map = new int[n][n];
        check = new boolean[n][n];

        for (int i = 0; i &amp;lt; n; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            for (int j = 0; j &amp;lt; n; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        for (int i = 0; i &amp;lt; n; i++) {
            for (int j = 0; j &amp;lt; n; j++) {
                if (!check[i][j] &amp;amp;&amp;amp; map[i][j] != 0) {
                    if (bfs(i, j, map[i][j])) {
                        System.out.println(sb);
                        return;
                    }
                }
            }
        }

        System.out.println(0);
    }

    static boolean bfs(int x, int y, int color) {
        Queue&amp;lt;Node&amp;gt; q = new LinkedList&amp;lt;&amp;gt;();
        check[x][y] = true;
        q.add(new Node(x, y));

        winCheck = new boolean[n][n];
        winCheck[x][y] = true;

        while (!q.isEmpty()) {
            Node now = q.poll();
            x = now.x;
            y = now.y;

            for (int k = 0; k &amp;lt; 4; k++) {

                int count = 1;
                list = new ArrayList&amp;lt;&amp;gt;();
                list.add(new Node(x, y));

                if (k == 0) {
                    count += search(k, winCheck, now, color);
                    count += search(k + 4, winCheck, now, color);
                }

                if (k == 1) {
                    count += search(k, winCheck, now, color);
                    count += search(k + 4, winCheck, now, color);
                }

                if (k == 2) {
                    count += search(k, winCheck, now, color);
                    count += search(k + 4, winCheck, now, color);
                }

                if (k == 3) {
                    count += search(k, winCheck, now, color);
                    count += search(k + 4, winCheck, now, color);
                }

                if (count == 5) {
                    sb.append(color + &quot;\n&quot;);
                    findPoint(list);
                    return true;
                }
            }
        }
        return false;
    }

    static int search(int k, boolean[][] winCheck, Node now, int color) {
        int count = 0;
        int nx = now.x + dx[k];
        int ny = now.y + dy[k];

        while(0 &amp;lt;= nx &amp;amp;&amp;amp; nx &amp;lt; n &amp;amp;&amp;amp; 0 &amp;lt;= ny &amp;amp;&amp;amp; ny &amp;lt; n) {
            if (color == map[nx][ny] &amp;amp;&amp;amp; !winCheck[nx][ny]) {
                winCheck[nx][ny] = true;
                list.add(new Node(nx, ny));
                nx += dx[k];
                ny += dy[k];
                count++;
            }else{
                break;
            }
        }
        return count;
    }

    static void findPoint(ArrayList&amp;lt;Node&amp;gt; list) {

        Collections.sort(list, (o1, o2) -&amp;gt; o1.y - o2.y);

        if (list.get(0).y == list.get(list.size() - 1).y) {
            Collections.sort(list, (o1, o2) -&amp;gt; o1.x - o2.x);
        }

        sb.append((list.get(0).x + 1) + &quot; &quot; +(list.get(0).y + 1));
    }

    static class Node{
        int x;
        int y;

        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준 문제풀이</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/98</guid>
      <comments>https://dding9code.tistory.com/98#entry98comment</comments>
      <pubDate>Tue, 26 Apr 2022 23:39:30 +0900</pubDate>
    </item>
    <item>
      <title>모던 자바 인 액션 - 2장 동작 파라미터화 코드 전달하기</title>
      <link>https://dding9code.tistory.com/97</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;*책 예제를 그대로 따라치는게 아닌 예제를 직접한번 만들어 보면서 학습을 해봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;동작 파라미터화 코드 전달하기&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변화하는 요구사항은 소프트웨어 엔지니어링에서 피할 수 없는 문제! &lt;b&gt;시시각각 변하는 사용자의 요구&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash;&amp;gt; &lt;b&gt;동작 파라미터화&lt;/b&gt; 효과적인 대응 이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동작 파라미터화란 아직은 어떻게 실행할 것인지 결정하지 않은 코드 블록을 의미, 이 코드 블록의 실행은 나중으로 미뤄진다. 어떻게 실행되는지 예제를 통해서 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명을 돕기 위한 기본셋팅입니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;enum Color { WHITE, BLACK, RED, BLUE }
enum Model { GV70, GV80, G70, G80, G90 }

class Car{
    private int price;
    private Color color;
    private Model model;

    public Car(int price, Color color, Model model) {
        this.price = price;
        this.color = color;
        this.model = model;
    }
}

//Main문에서 차량 리스트 추가
List&amp;lt;Car&amp;gt; carList = Arrays.asList(
                new Car(5500, Color.BLACK, Model.GV70),
                new Car(8000, Color.RED, Model.GV80),
                new Car(5000, Color.WHITE, Model.G70),
                new Car(7000, Color.BLUE, Model.G80),
                new Car(9000, Color.WHITE, Model.G90),
                new Car(5600, Color.BLUE, Model.GV70),
                new Car(6100, Color.BLACK, Model.G70)
        );&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;검은차량 필터링&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public static List&amp;lt;Car&amp;gt; filterBlackCar(List&amp;lt;Car&amp;gt; carList) {
        List&amp;lt;Car&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();
        for (Car car : carList) {
            if (car.getColor() == Color.BLACK) {
                result.add(car);
            }
        }
        return result;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 차를 구매하기 원하는 &lt;b&gt;소비자가&lt;/b&gt; &lt;b&gt;검은색 차량이 아닌 흰색 차량을 필터링해서 보고 싶다면?&lt;/b&gt; 어떻게 수정해야 할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크게 고민을 하지 않는다면 위와 같은 코드를 복사하여 if문을 수정하는 방법을 선택할 수 도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이런 방법은 새로운 색이 추가가 되거나, 소비자가 더 다양한 색의 필터를 요구하면 적절하게 대응할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 어떻게 해결해야 할까요? &amp;rarr; &lt;b&gt;비슷한 코드가 반복 존재하면 코드를 추상화&lt;/b&gt;를 하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선은 왜 코드를 추상화해야하는지 좋지 않은 예를 시작으로 하여 단계별로 알아보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;색을 파라미터 화&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 반복하지 않고 다양한 색을 필터링할 수 있는 메서드를 만들려면 &lt;b&gt;색을 파라미터화&lt;/b&gt;할 수 있도록 메서드에 파라미터를 추가하면 유연하게 대응이 가능합니다.&lt;/p&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;public static List&amp;lt;Car&amp;gt; filterCarByColor(List&amp;lt;Car&amp;gt; carList, **Color color**) {
        List&amp;lt;Car&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();

        for (Car car : carList) {
            if (**car.getColor() == color**) {
                result.add(car);
            }
        }
        return result;
    }

//사용
List&amp;lt;Car&amp;gt; blackCars = filterCarByColor(carList, Color.BLACK);
List&amp;lt;Car&amp;gt; whiteCars = filterCarByColor(carList, Color.WHITE);
&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;색을 매개변수로 주어 소비자가 원하는 대로 차량의 색을 필터링을 할 수 있게 되었습니다. 하지만 가격이 6000 이하인 차량의 요구사항이 주어지거나, 모델이 G70인 차량 다양하게 요구사항이 들어온다면 위와 같이 파라미터 정보를 추가하여 해결할 수 있겠지만, 생각해보면 &lt;b&gt;결국 코드가 중복&lt;/b&gt;된다는 사실을 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;zephir&quot;&gt;&lt;code&gt;public static List&amp;lt;Car&amp;gt; filterCarByPrice(List&amp;lt;Car&amp;gt; carList, int price) {
        List&amp;lt;Car&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();

        for (Car car : carList) {
            if (car.getPrice() &amp;lt; price) {
                result.add(car);
            }
        }
        return result;
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 소프트웨어 공학의 &lt;b&gt;DRY&lt;/b&gt;(don&amp;rsquo;t repeat yourselft, 같은 것을 반복) 원칙을 어기는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탐색 과정을 고치려면 한 줄이 아닌 메서드 전체를 수정해야 하는 일이 생길 수 있어 엔지니어링적으로 비싼 대가를 치러야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;색과 가격, 모델 등을 따로 메서드로 합치는 방법도 있겠지만, 그렇게 된다면 어떤 기준으로 필터링할지 구분하는 또 다른 방법이 필요합니다.&amp;nbsp;따라서 어떤 기준으로 필터링할지 플래그를 추가하는 방법도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;mdash;&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&amp;nbsp;하지만 실무, 실전에서는 절대 사용 X&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;가능한 모든 속성으로 필터링&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실전에서는 절대 사용하지 말라는 플래그로 메서드를 구현해보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;zephir&quot;&gt;&lt;code&gt;public static List&amp;lt;Car&amp;gt; filterCars(List&amp;lt;Car&amp;gt; carList, Color color,
                                       int price, boolean flag) {
        List&amp;lt;Car&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();

        for (Car car : carList) {
            if ((flag &amp;amp;&amp;amp; car.getPrice() &amp;lt; price) ||
            (!flag &amp;amp;&amp;amp; car.getColor() == color)) {
                result.add(car);
            }
        }
        return result;
    }

List&amp;lt;Car&amp;gt; G70Cars = filterCars(carList, null, Model.G70, true);
List&amp;lt;Car&amp;gt; blackCars = filterCars(carList, Color.BLACK, null, false);

&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;작성자도 보기 힘든 가독성을 가지고, true flase 가 뭘 하는지도 모르겠고 코드가 개판이 났습니다.&lt;/li&gt;
&lt;li&gt;여기에 필터링 조건으로 가격이 추가가 된다면 벌써 머리가 아파집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash;&amp;gt; 이를 &lt;b&gt;동작 파라미터화&lt;/b&gt;를 이용해서 해결해 보겠습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;동작 파라미터화&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 코드를 보면 파라미터를 추가하는 방법이 아니라 변화 좀 더 유연하게 대응할 수 있는 방법이 필요하다는 것을 확인했습니다. 반복되는 코드를 추상화하기 위하여 &lt;b&gt;선택 조건을 결정하는 인터페이스&lt;/b&gt;를 만들어 봅시다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;public interface CarPredicate{
	   boolean test(Car car);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; *&lt;b&gt;참 또는 거짓을 반환하는 함수를 프레디케이트(Predicate) &lt;/b&gt;라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;//7000만원 이하차량 선택
public class CarPircePredicate implements CarPredicate{
        @Override
        public boolean test(Car car) {
            return car.getPrice() &amp;lt;= 7000;
        }
}

//GV70 만 선택
public class CarModelPredicate implements CarPredicate {
        @Override
        public boolean test(Car car) {
            return car.getModel() == Model.GV70;
        }
}

&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;조건에 따라 filter 메서드가 다르게 동작할 것이라고 예측할 수 있습니다. 이를 &lt;b&gt;전략 디자인 패턴&lt;/b&gt;이라고 부릅니다. 전략 디자인 패턴은 각 알고리즘(전략이라 불리는)을 &lt;b&gt;캡슐화&lt;/b&gt;하는 알고리즘 패밀리를 정의해둔 다음에 런타임에 알고리즘을 선택하는 기법입니다.&lt;/li&gt;
&lt;li&gt;여기서 &lt;b&gt;인터페이스 CarPredicate가 알고리즘 패밀리&lt;/b&gt;고, &lt;b&gt;구현체가 전략&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 이 인터페이스는 어떻게 다양한 동작을 수행할 수 있을까요, &lt;b&gt;메서드에서 인터페이스 객체를 받아&lt;/b&gt; 차량의 &lt;b&gt;조건을 검사&lt;/b&gt;하도록 메서드를 만들어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash;&amp;gt; 이렇게 &lt;b&gt;동작 파라미터화&lt;/b&gt; , 즉 &lt;b&gt;메서드가&lt;/b&gt; &lt;b&gt;다양한&lt;/b&gt; &lt;b&gt;동작(or 전략)을 받아&lt;/b&gt;서 내부적으로 &lt;b&gt;다양한 동작을 수행&lt;/b&gt;할 수 있습니다. 기존의 코드를 고쳐 어떤 좋은 점이 있는지 한번 확인해 봅시다!&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;추상적 조건으로 필터링&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;public static List&amp;lt;Car&amp;gt; filterCars(List&amp;lt;Car&amp;gt; carList, CarPredicate p) {
        List&amp;lt;Car&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();

        for (Car car : carList) {
            if (p.test(car)) {
                result.add(car);
            }
        }
        return result;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 코드에 비해 유연한 코드를 얻었으며, 가독성도 좋아지고 사용하기도 쉬워졌습니다. 필요한 대로 인터페이스를 구현하여 filterCars 메서드로 전달할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차량이 9000만 원 이하, 색은 파랑, 모델은 G80이라고 하면 적절하게 인터페이스를 구현하는 클래스를 만들면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public static class ChoiceCars implements CarPredicate {
        @Override
        public boolean test(Car car) {
            return car.getModel() == Model.G80
                    &amp;amp;&amp;amp; car.getPrice() &amp;lt;= 9000
                    &amp;amp;&amp;amp; car.getColor() == Color.BLUE;
        }
}

List&amp;lt;Car&amp;gt; ChoiceCars = filterCars(carList, new ChoiceCar());

//List&amp;lt;Car&amp;gt; priceCars = filterCar(carList, new CarPircePredicate());
//List&amp;lt;Car&amp;gt; modelCars = filterCar(carList, new CarModelPredicate());
//List&amp;lt;Car&amp;gt; ChoiceCars = filterCars(carList, 만든 객체 전달);

&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;직접 만든 CarPredicate 객체에 의해&lt;/b&gt; filterCars &lt;b&gt;메서드의 동작이 결정&lt;/b&gt;이 된다. 이것이 &lt;b&gt;filterCars메서드의 동작을 파라미터화&lt;/b&gt;한 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 블록을 조립하듯이, 한 메서드가 다른 동작을 수행할 수 있도록 재활용할 수 있다. 유연한 API를 만들 때 동작 파라미터화가 중요한 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;복잡한 과정 간소화&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동작을 파라미터화 하여서 가독성도 좋아지고, 사용하기 쉬워졌지만 뭔가 새로운 동작을 만들어 filterCars 메서드로 전달하려면 인터페이스를 구현하는 여러 클래스를 정의한 다음에 인스턴스화를 해야 하는 번거로운 작업을 해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바는 클래스의 선언과 인스턴스화를 동시에 수행할 수 있도록 &lt;b&gt;익명 클래스&lt;/b&gt; 기법을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;익명 클래스&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익명 클래스는 자바의 지역 클래스와 비슷한 개념으로, 말 그대로 이름이 없는 클래스입니다. 즉석에서 필요한 구현을 만들어서 사용이 가능합니다.&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;List&amp;lt;Car&amp;gt; redCars = filterCar(carList, new CarPredicate() {
            @Override
            public boolean test(Car car) {
                return Color.RED == car.getColor();
            }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 클래스를 만들어 인스턴스화를 하는 작업이 없어졌지만, 익명클래스는 많은 공간을 차지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드의 장황함(verbosity)는 나쁜 특성입니다. 왜냐하면 장황한 코드는 유지 보수하는데 시간이 오래 걸릴 뿐만 아니라, 코드를 보는 즐거움도 빼앗는 요소입니다. 따라서 한눈에 이해할 수 있어야 좋은 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;람다 표현식 사용&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8의 람다 표현식을 이용하면 위 예제 코드를 다음처럼 간단하게 구현이 가능하게 됩니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;List&amp;lt;Car&amp;gt; redCars = filterCar(carList, car -&amp;gt; Color.RED == car.getColor());
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드를 모르는 사람이 봐도 간결해짐을 느낄 수 있습니다. 이렇게 람다표현식을 사용하면 복잡성 문제를 해결할 수 있습니다.&lt;/li&gt;
&lt;/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;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;리스트 형식으로 추상화&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre class=&quot;zephir&quot;&gt;&lt;code&gt;public interface Predicate&amp;lt;T&amp;gt; {
    boolean test(T t);
}

public static &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; filter(List&amp;lt;T&amp;gt; list, Predicate&amp;lt;T&amp;gt; p) {
        List&amp;lt;T&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();
        for (T e : list) {
            if (p.test(e)) {
                result.add(e);
            }
        }
        return result;
}

List&amp;lt;Integer&amp;gt; numbers = new ArrayList&amp;lt;&amp;gt;();

for (int i = 0; i &amp;lt; 100; i++) {
     numbers.add(i);
}

List&amp;lt;Integer&amp;gt; evenNumber = filter(numbers, i -&amp;gt; i % 2 == 0);
List&amp;lt;Car&amp;gt; carGV70 = filter(carList, car -&amp;gt; car.getModel() == Model.GV70);

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제네릭스를 이용하여 다양한 타입의 객체를 다룰 수 있게 만들었다. 어떤 타입이든 한 가지 타입을 정해서 담을 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;타입 안정성&lt;/b&gt; 제공&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타입체크&lt;/b&gt;와 형변환을 생략할 수 있어 코드가 간결해진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동작 파라미터화를 이용하면 변화하는 요구사항에 더 잘 대응하는 코드를 구현할 수 있다.&lt;/li&gt;
&lt;li&gt;자바 8(람다)을 활용하여 인터페이스를 상속받아 여러 클래스를 구현하는 고생을 덜 수 있다.&lt;/li&gt;
&lt;li&gt;자바 API의 많은 메서드는 정렬, 스레드, GUI 처리 등을 포함한 다양한 동작으로 파라미터화 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>모던 자바 인 액션 스터디</category>
      <category>동작 파라미터화</category>
      <category>모던 자바 인 액션</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/97</guid>
      <comments>https://dding9code.tistory.com/97#entry97comment</comments>
      <pubDate>Mon, 25 Apr 2022 23:55:54 +0900</pubDate>
    </item>
    <item>
      <title>교착상태(DeadLock)</title>
      <link>https://dding9code.tistory.com/96</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;교착상태(DeadLock)&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개 이상의 작업이 서로 상대방의 작업이 끝나기만을 기다리고 있는 상태, 결국 아무것도 완료되지 못하는 상태를 말합니다. 같은 말로 둘 이상의 스레드가 각기 다른 스레드가 점유하고 있는 자원을 서로 기다릴 때, 무한 대기에 빠지는 상태라고도 합니다.&lt;/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;스크린샷 2022-04-22 오전 11.59.37.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfOpxy/btrz52QiezG/UMLWsbtmYeerfssZc4yVk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfOpxy/btrz52QiezG/UMLWsbtmYeerfssZc4yVk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfOpxy/btrz52QiezG/UMLWsbtmYeerfssZc4yVk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfOpxy%2Fbtrz52QiezG%2FUMLWsbtmYeerfssZc4yVk1%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;257&quot; data-filename=&quot;스크린샷 2022-04-22 오전 11.59.37.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;232&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교착상태가 발생하는 조건은 &lt;b&gt;상호 배제&lt;/b&gt;, &lt;b&gt;점유 대기&lt;/b&gt;, &lt;b&gt;비선점&lt;/b&gt;, &lt;b&gt;순환 대기&amp;nbsp;&lt;/b&gt;4가지 조건이 동시에 성립할 때 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 교착상태 문제를 해결하는 방법으로는 &lt;b&gt;무시&lt;/b&gt;, &lt;b&gt;예방&lt;/b&gt;, &lt;b&gt;회피&lt;/b&gt;, &lt;b&gt;탐지 회복&lt;/b&gt; 4가지 방법이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;발생조건&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 80px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 20.1163%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;상호 배제&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.8837%; height: 20px;&quot;&gt;한 자원은 동시에 쓸 수 없는 상황, 하나의 스레드만이 자원을 점유 할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 20.1163%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;점유 대기&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.8837%; height: 20px;&quot;&gt;한 스레드가 자원을 붙잡은 상태에서 다른 스레드가 보유한 자원을 기다리고 있는 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 20.1163%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;비선점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.8837%; height: 20px;&quot;&gt;다른 스레드가 사용중인 자원을 강제로 선점할 수 없는 상황&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 20.1163%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;순환 대기&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.8837%; height: 20px;&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;해결방법&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 72px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 20.8915%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;무시&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.7751%; height: 18px;&quot;&gt;아무런 조치도 취하지않고 deadlock을 무시한다.&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;- 시스템 성능 저하가 없다는 장점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 20.8915%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;예방&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.7751%; height: 18px;&quot;&gt;교착 상태의 4가지 발생 조건중 하나가 성립하지 않게 하는 방법&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;- 순환 대기 조건이 성립하지 않도록 하는것이 현실적 가능한 예방&lt;br /&gt;- 자원 사용의 효율성이 떨어지고 비용이 크다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 20.8915%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;회피&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.7751%; height: 18px;&quot;&gt;교착상태가 발생하지 않도록 자원을 할당하는 방법&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;- 자원 할당 그래프 알고리즘, 은행원 알고리즘 등 이 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 20.8915%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;탐지-회복&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.7751%; height: 18px;&quot;&gt;시스템 검사를 통해 교착상태 발생을 탐지하고 회복하는 방법&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <category>DeadLock</category>
      <category>교착상태</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/96</guid>
      <comments>https://dding9code.tistory.com/96#entry96comment</comments>
      <pubDate>Fri, 22 Apr 2022 12:00:09 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스 Level2] 거리두기 확인하기(JAVA) - 2021 카카오 인턴</title>
      <link>https://dding9code.tistory.com/95</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/81302&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/81302&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1650378570664&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 거리두기 확인하기&quot; data-og-description=&quot;[[&amp;quot;POOOP&amp;quot;, &amp;quot;OXXOX&amp;quot;, &amp;quot;OPXPX&amp;quot;, &amp;quot;OOXOX&amp;quot;, &amp;quot;POXXP&amp;quot;], [&amp;quot;POOPX&amp;quot;, &amp;quot;OXPXP&amp;quot;, &amp;quot;PXXXO&amp;quot;, &amp;quot;OXXXO&amp;quot;, &amp;quot;OOOPP&amp;quot;], [&amp;quot;PXOPX&amp;quot;, &amp;quot;OXOXP&amp;quot;, &amp;quot;OXPOX&amp;quot;, &amp;quot;OXXOP&amp;quot;, &amp;quot;PXPOX&amp;quot;], [&amp;quot;OOOXX&amp;quot;, &amp;quot;XOOOX&amp;quot;, &amp;quot;OOOXX&amp;quot;, &amp;quot;OXOOX&amp;quot;, &amp;quot;OOOOO&amp;quot;], [&amp;quot;PXPXP&amp;quot;, &amp;quot;XPXPX&amp;quot;, &amp;quot;PXPXP&amp;quot;, &amp;quot;XPXPX&amp;quot;, &amp;quot;PXPXP&amp;quot;]] [1, 0, 1, 1, 1]&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/81302&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/81302&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/li69E/hyN612PmYa/UFdRvuD8YWikTXkc6GF0uK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/NJ1f7/hyN6V2Cg1P/2KIs2SqOYXBdBt7zA8KKSk/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/o7CZ5/hyN61V5cwm/iSOwpORu95G3SKYTg3HNiK/img.png?width=242&amp;amp;height=242&amp;amp;face=0_0_242_242&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/81302&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/81302&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/li69E/hyN612PmYa/UFdRvuD8YWikTXkc6GF0uK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/NJ1f7/hyN6V2Cg1P/2KIs2SqOYXBdBt7zA8KKSk/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/o7CZ5/hyN61V5cwm/iSOwpORu95G3SKYTg3HNiK/img.png?width=242&amp;amp;height=242&amp;amp;face=0_0_242_242');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 거리두기 확인하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[[&quot;POOOP&quot;, &quot;OXXOX&quot;, &quot;OPXPX&quot;, &quot;OOXOX&quot;, &quot;POXXP&quot;], [&quot;POOPX&quot;, &quot;OXPXP&quot;, &quot;PXXXO&quot;, &quot;OXXXO&quot;, &quot;OOOPP&quot;], [&quot;PXOPX&quot;, &quot;OXOXP&quot;, &quot;OXPOX&quot;, &quot;OXXOP&quot;, &quot;PXPOX&quot;], [&quot;OOOXX&quot;, &quot;XOOOX&quot;, &quot;OOOXX&quot;, &quot;OXOOX&quot;, &quot;OOOOO&quot;], [&quot;PXPXP&quot;, &quot;XPXPX&quot;, &quot;PXPXP&quot;, &quot;XPXPX&quot;, &quot;PXPXP&quot;]] [1, 0, 1, 1, 1]&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제의 내용이 길어 생략했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제풀이&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-22 오후 1.11.29.png&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sMqPF/btrz7yItEhn/KA3dKMOzRfBJDrDOdKnuq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sMqPF/btrz7yItEhn/KA3dKMOzRfBJDrDOdKnuq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sMqPF/btrz7yItEhn/KA3dKMOzRfBJDrDOdKnuq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsMqPF%2Fbtrz7yItEhn%2FKA3dKMOzRfBJDrDOdKnuq0%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;705&quot; height=&quot;185&quot; data-filename=&quot;스크린샷 2022-04-22 오후 1.11.29.png&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;185&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 그림이 제일 큰 힌트를 주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참가자 사이의 거리가 2가 되더라도 X로 막혀있을 경우 거리두기를 지킨 것이고, 파티션을 사이에 두고 앉은 경우도 지킨 것이 됩니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;세번째 그림은 참가자 사이의 거리가 2이고 빈테이블이 있어 거리두기를 지키지 못했습니다.&lt;/li&gt;
&lt;li&gt;이를 토대로 결국 도달할 수 있는가 없는가로 생각하여, 상하좌우로 움직이는 BFS로 문제를 풀 수 있다는 사실을 알았습니다.&lt;/li&gt;
&lt;li&gt;또한 문제의 제한이 5라는 매우작은 수로 모든 테이블마다 참가자를 BFS탐색해도 시간초과가 나지 않겠다 라고 생각을 했습니다.&lt;/li&gt;
&lt;li&gt;이제 문제의 조건대로 구현만 하면 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;소스코드&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1650378792447&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {

    static final int dx[] = {0, 0, 1, -1};
    static final int dy[] = {1, -1, 0, 0};
    static int[][] check;
    static char[][] map;
    static int n = 5;
    static class Node{
        int x;
        int y;

        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    public int[] solution(String[][] places) {
        int[] answer = new int[n];

        int i = 0;
        for (String[] place : places) {
            answer[i] = func(place);
            i++;
        }

        return answer;
    }


    static int func(String[] place) {
        check = new int[n][n];
        map = new char[n][n];

        for (int i = 0; i &amp;lt; n; i++) {
            for (int j = 0; j &amp;lt; n; j++) {
                map[i][j] = place[i].charAt(j);
            }
        }

        for (int i = 0; i &amp;lt; n; i++) {
            for (int j = 0; j &amp;lt; n; j++) {
                if (map[i][j] == 'P') {
                    if (!bfs(i, j)) {
                        return 0;
                    }
                }
            }
        }
        return 1;
    }

    static boolean bfs(int x, int y) {
        Queue&amp;lt;Node&amp;gt; q = new LinkedList&amp;lt;&amp;gt;();
        check = new int[n][n];
        for (int i = 0; i &amp;lt; n; i++) {
            Arrays.fill(check[i], -1);
        }

        q.add(new Node(x, y));
        check[x][y] = 0;

        while (!q.isEmpty()) {
            Node now = q.poll();
            x = now.x;
            y = now.y;

            for (int k = 0; k &amp;lt; 4; k++) {
                int nx = x + dx[k];
                int ny = y + dy[k];

                if (0 &amp;lt;= nx &amp;amp;&amp;amp; nx &amp;lt; n &amp;amp;&amp;amp; 0 &amp;lt;= ny &amp;amp;&amp;amp; ny &amp;lt; n) {
                    if (map[nx][ny] != 'X' &amp;amp;&amp;amp; check[nx][ny] == -1) {
                        check[nx][ny] = check[x][y] + 1;
                        if (map[nx][ny] == 'P' &amp;amp;&amp;amp; check[nx][ny] &amp;lt;= 2) {
                            return false;
                        }
                        q.add(new Node(nx, ny));
                    }
                }
            }
        }

        return true;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래머스</category>
      <category>거리두기 확인하기</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/95</guid>
      <comments>https://dding9code.tistory.com/95#entry95comment</comments>
      <pubDate>Tue, 19 Apr 2022 23:36:17 +0900</pubDate>
    </item>
    <item>
      <title>스레드와 멀티스레드 (Thread &amp;amp; Multi Thread)</title>
      <link>https://dding9code.tistory.com/94</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Thread&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스레드는 한 프로그램 or 프로세스 내에서 실행되는 동작(기능, 흐름)의 단위&lt;/b&gt; 입니다. 한 프로세스 내의 스레드는 Stack Memory를 제외한 나머지 Memory 영역을 공유할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-19 오후 3.43.35.png&quot; data-origin-width=&quot;293&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rATaU/btrzQYUcuRb/D56sgL53Si8Es5JTKX160k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rATaU/btrzQYUcuRb/D56sgL53Si8Es5JTKX160k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rATaU/btrzQYUcuRb/D56sgL53Si8Es5JTKX160k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrATaU%2FbtrzQYUcuRb%2FD56sgL53Si8Es5JTKX160k%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;293&quot; height=&quot;398&quot; data-filename=&quot;스크린샷 2022-04-19 오후 3.43.35.png&quot; data-origin-width=&quot;293&quot; data-origin-height=&quot;398&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 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Multi Thread&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티 스레드란 하나의 프로세스내에서 두 개의 이상의 스레드를 가지게 됩니다. 한 프로세스가 동시에 여러작업(병렬로 처리)을 하기 위해 멀티 스레드를 사용하며, 각각의 스레드는 독립적으로 기능을 수행하기 위해 독립적인 &lt;b&gt;Stack Memory와 PC Register&lt;/b&gt; 가지며 나머지&amp;nbsp; Code, Data, Heap 영역을 공유하여 사용합니다.&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;스크린샷 2022-04-19 오후 3.43.52.png&quot; data-origin-width=&quot;339&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mYKFU/btrzMJ5gcB8/6UG6UKatnsJEcWDo0ez3k0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mYKFU/btrzMJ5gcB8/6UG6UKatnsJEcWDo0ez3k0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mYKFU/btrzMJ5gcB8/6UG6UKatnsJEcWDo0ez3k0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmYKFU%2FbtrzMJ5gcB8%2F6UG6UKatnsJEcWDo0ez3k0%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;339&quot; height=&quot;398&quot; data-filename=&quot;스크린샷 2022-04-19 오후 3.43.52.png&quot; data-origin-width=&quot;339&quot; data-origin-height=&quot;398&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Stack Memory&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;스레드가 함수를 호출하기 위해서는 매개변수, 리턴값, 지역변수 저장 등을 위한 독립적인 Stack 영역이 필요합니다. 결과적으로 스레드는 프로세스로부터 Stack 영역을 독립적으로 할당 받고 나머지 영역(Code, Data, Headp) 영역은 공유하는 형태를 갖게 됩니다.&amp;nbsp;&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;PC Register&lt;/b&gt;&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;멀티 스레드는 스레드마다의 각각 PC Register를 가져야하는데 그 이유는 프로세스 내의 스레드끼리 Context Switcing이 일어나게 되는데 이를 수행하려면 PC register에 code address가 저장되어 있어야 스레드를 이어서 실행할 수 있기 때문입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Multi Process 와 Multi Thread&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티 프로세스와 멀티 스레드는 동시에 여러 작업을 수행할 수 있어 유사한 점이 있습니다. 하지만 두 방법은 장점과 단점이 다릅니다. 어떤차이가 있을까요?&lt;/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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&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;독립된 메모리 영역을 가져 안정성이 높아 하나의 프로세스가 문제가 생겨도 다른 프로세스에는 영향을 주지 않습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;독립된 메모리 영역을 가지기 때문에 많은 메모리공간과 CPU 시간을 차지&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;h4 data-ke-size=&quot;size20&quot;&gt;&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;메모리 영역을 공유를 하기 때문에 메모리 공간과 시스템 자원 소모가 줄어들게 되며, 멀티 프로세스와 다르게 캐시메모리를 초기화할 필요가 없기 때문에 컨텍스트 스위칭 연산이 빠릅니다.&lt;/li&gt;
&lt;li&gt;프로세스간의 통신(IPC) 보다 스레드간의 통신 비용이 적기 때문에 통신으로 인한 오버헤드가 적습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;스레드간의 자원을 공유하기 때문에 *&lt;b&gt;동기화문제&lt;/b&gt;가 발생할 수 있기 때문에 주의깊은 설계가 필요합니다.&lt;/li&gt;
&lt;li&gt;하나의 스레드가 문제가 생기면 프로세스내의 다른 스레드에도 문제가 생길 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리 구분이 필요할 경우에는 멀티프로세스가 유리하고, 컨텍스트 스위칭이 자주 일어나고 데이터 공유가 빈번하면 멀티 스레드를 사용하는것이 유리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/94</guid>
      <comments>https://dding9code.tistory.com/94#entry94comment</comments>
      <pubDate>Mon, 18 Apr 2022 23:07:14 +0900</pubDate>
    </item>
    <item>
      <title>[백준 2304] - 창고  다각형(JAVA)</title>
      <link>https://dding9code.tistory.com/93</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2304&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/2304&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1650342159953&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;2304번: 창고 다각형&quot; data-og-description=&quot;첫 줄에는 기둥의 개수를 나타내는 정수 N이 주어진다. N은 1 이상 1,000 이하이다. 그 다음 N 개의 줄에는 각 줄에 각 기둥의 왼쪽 면의 위치를 나타내는 정수 L과 높이를 나타내는 정수 H가 한 개의&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/2304&quot; data-og-url=&quot;https://www.acmicpc.net/problem/2304&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bO9KTI/hyN5u6ewd4/l7yQxVywa0YJcNjtDt6unK/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2304&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/2304&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bO9KTI/hyN5u6ewd4/l7yQxVywa0YJcNjtDt6unK/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;2304번: 창고 다각형&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫 줄에는 기둥의 개수를 나타내는 정수 N이 주어진다. N은 1 이상 1,000 이하이다. 그 다음 N 개의 줄에는 각 줄에 각 기둥의 왼쪽 면의 위치를 나타내는 정수 L과 높이를 나타내는 정수 H가 한 개의&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-19 오후 1.22.08.png&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;1039&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqxvAh/btrzJ2Kw6LC/bh5HLdnpp76rOEGmh0vLp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqxvAh/btrzJ2Kw6LC/bh5HLdnpp76rOEGmh0vLp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqxvAh/btrzJ2Kw6LC/bh5HLdnpp76rOEGmh0vLp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqxvAh%2FbtrzJ2Kw6LC%2Fbh5HLdnpp76rOEGmh0vLp1%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;1162&quot; height=&quot;1039&quot; data-filename=&quot;스크린샷 2022-04-19 오후 1.22.08.png&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;1039&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;b&gt;[문제풀이 전]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기둥들의 위치와 높이가 주어질 때, 가장 작은 창고 다각형의 면적을 구하면 되는 문제입니다. 힌트에서는 문제 분류가 브루트포스로 되어있지만 x축 (기둥의 왼쪽 면의 위치) 기준으로 정렬을 하여 구하여 항상 작은 면적이 나오게 구현을 했기 때문에 그리디 방법이 아닌가 생각이 들기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브루트포스는 가능한 모든 경우의 수를 탐색하는데 그런 경우를 따져 풀지 않았다고 생각합니다. 혹시 제가 잘못된 생각을 했다면 댓글 남겨주시면 정말 감사하겠습니다 ㅎㅎ....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제풀이]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 찾아오게 된다면 아마 한 방향으로 면적을 구하려다 실패를 해서이기 때문이지 않을까 생각을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제는 제일 높은 기둥을 기준으로 문제의 조건에 맞게 오른쪽은 작아지는 구간만을 계산을 하고, 왼쪽 면적은 기둥이 커지는 구간만 계산을 한 뒤에 제일 큰 기둥의 면적을 더해주면 답이 구해집니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;b&gt;[소스코드]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1650343203967&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {

    static class LowHigh{
        int low;
        int high;

        public LowHigh(int low, int high) {
            this.low = low;
            this.high = high;
        }
    }
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int n = Integer.parseInt(br.readLine());

        ArrayList&amp;lt;LowHigh&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();

        for (int i = 0; i &amp;lt; n; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int l = Integer.parseInt(st.nextToken());
            int h = Integer.parseInt(st.nextToken());

            list.add(new LowHigh(l, h));
        }

        Collections.sort(list, (o1, o2) -&amp;gt; o1.low - o2.low); //x축 기준 정렬

        int sum = 0;
        int maxHeightPoint = 0;

        LowHigh highCol = list.get(0);
        for (int i = 1; i &amp;lt; list.size(); i++) {
            LowHigh currentCol = list.get(i);

            if (highCol.high &amp;lt;= currentCol.high) {
                sum += (currentCol.low - highCol.low) * highCol.high;
                highCol = currentCol;
                maxHeightPoint = i;
            }
        }


        highCol = list.get(list.size() - 1);
        for (int i = 1; i &amp;lt; list.size() - maxHeightPoint; i++) {
            LowHigh currentCol = list.get(list.size() - 1 - i);

            if (highCol.high &amp;lt;= currentCol.high) {
                sum += (highCol.low - currentCol.low) * highCol.high;
                highCol = currentCol;
            }
        }

        sum += list.get(maxHeightPoint).high;

        System.out.println(sum);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준 문제풀이</category>
      <category>백준 2304</category>
      <category>창고 다각형</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/93</guid>
      <comments>https://dding9code.tistory.com/93#entry93comment</comments>
      <pubDate>Sat, 16 Apr 2022 22:42:03 +0900</pubDate>
    </item>
    <item>
      <title>멀티 프로세스(Multi process), Context 와 Context Switching</title>
      <link>https://dding9code.tistory.com/92</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Multi Process&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티 프로세스는 말 그대로 2개 이상의 프로세스가 &lt;b&gt;동시에 실행되는&lt;/b&gt; 것을 의미합니다. 여기서 동시에 라는 말이 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 동시에라는 것은 &lt;b&gt;동시성(Concurrency)&lt;/b&gt; 와 &lt;b&gt;병렬성(Parallelism)&lt;/b&gt; 을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동시성(Concurrency)&lt;/b&gt; : Single Core에서 여러 프로세스를 &lt;b&gt;빠르게&lt;/b&gt; &lt;b&gt;번갈아 가면서&lt;/b&gt; &lt;b&gt;연산&lt;/b&gt;하는 시분할 시스템(Time Sharing System) 으로 실행됩니다. (동시에 실행되는 것 같아 보인다.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;병렬성(Parallelism)&lt;/b&gt; : Multi Core에서 &lt;b&gt;실제로 동시에 여러 프로세스를 실행&lt;/b&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;span style=&quot;color: #555555;&quot;&gt;*시분할 시스템 ?&amp;nbsp;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;시분할 시스템은 하나의 CPU에서는 여러 개의 작업을 동시에 수행이 불가하여, 아주 짧은 시간 간격을 두고 여러 개의 프로세스를 전환하면서 실행합니다. 매우 빠른 속도로 사용자는 동시에 실행되는 것처럼 느껴집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Context&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시분할 시스템에서 짧은 간격으로 여러 프로세스를 전환하면서 각 프로세스가 CPU를 점유하면서 일정부분의 명령을 수행하게 됩니다. 전환이 되면 이전에 어디까지 명령을 수행했고, register에는 어떤 값이 저장되어 있는지에 대한 정보가 필요합니다. 즉 프로세스가 현재 어떤 상태로 수행되고 있는지에 대한 정보가 Context 입니다. 해당 정보는 커널내부에 존재하는 *PCB(Process Control Block)에 저장이 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;*PCB(Process Control Block)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제가 프로세스를 표현한 자료구조입니다. 일반적으로 다음과 같은 정보가 포함됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스 식별자(Process ID)&lt;/li&gt;
&lt;li&gt;프로세스 상태(Process State) : 생성, 준비, 실행, 대기, 완료&lt;/li&gt;
&lt;li&gt;프로그램 카운터(Program Counter) : 프로그램 카운터는 이 프로스세가 다음에 실행할 명령어의 주소를 가리킵니다.&lt;/li&gt;
&lt;li&gt;CPU 레지스터 및 일반 레지스터&lt;/li&gt;
&lt;li&gt;base register, limit register, page table ...&lt;/li&gt;
&lt;li&gt;... 등등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Context Switching&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텍스트 스위칭은 한 Task가 끝날 때까지 기다리는 것이 아니라 여러 작업을 번갈아 가면서 실행해서 동시에 처리될 수 있도록 하는 방법입니다. 인터럽트가 발생했을 때 한 프로세스에서 다른 프로세스로 CPU 제어권을 넘겨주는 것을 의미합니다.&amp;nbsp; 이 전의 프로세스의 상태를 PCB에 저장하여 보관하고 새로운 프로세스의 PCB를 읽어서 보관된 상태를 복구하는 작업이 이루어집니다. 이때 CPU는 아무런 일을 하지 않으므로 잦은 컨텍스트 스위칭은 성능 저하를 이르킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;메모리 관리&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티 프로세스는 여러개의 프로세스가 실행되는 것을 의미한다고 설명드렸습니다. 그러면 여러 개의 프로세스가 메모리에 적재될 것입니다. 이때의 서로의 다른 프로세스의 영역을 침범하지 않도록 각 프로세스가 자신의 메모리 영역에만 접근하도록 *운영체제가 관리해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*base register 와 limit register 를 통하여 각 프로세스를 처리할 때에는 정해진 메모리 구간 외에는 접근할 수 없도록 memory protection 구현, 해당 범위 넘어가는 주소 사용하면 OS에 의해 강제종료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*base register: 메모리에 프로그램이 적재될 때의 register의 주소&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*limit register: 현재 프로그램이 사용할 수 있는 register의 마지막 주소&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <category>context</category>
      <category>context switching</category>
      <category>Process</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/92</guid>
      <comments>https://dding9code.tistory.com/92#entry92comment</comments>
      <pubDate>Thu, 14 Apr 2022 23:33:04 +0900</pubDate>
    </item>
    <item>
      <title>프로세스 메모리 구조</title>
      <link>https://dding9code.tistory.com/91</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;프로세스란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스란 실행중인 프로그램입니다. 프로그램이 &lt;b&gt;메모리에 적재&lt;/b&gt;되어&lt;b&gt; CPU를 할당받아 실행&lt;/b&gt;하는 것 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;프로세스 메모리 구조&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스에 할당되는 메모리 공간은 Code, Data, Stack, Heap 4개의 영역으로 이루어져있습니다. 각 프로세스마다 독립적으로 메모리 공간을 할당 받습니다.&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;스크린샷 2022-04-14 오전 11.30.34.png&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;433&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBiPum/btrznAMOMAy/GNOkVWZithXKHdw63kylIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBiPum/btrznAMOMAy/GNOkVWZithXKHdw63kylIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBiPum/btrznAMOMAy/GNOkVWZithXKHdw63kylIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBiPum%2FbtrznAMOMAy%2FGNOkVWZithXKHdw63kylIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;623&quot; height=&quot;433&quot; data-filename=&quot;스크린샷 2022-04-14 오전 11.30.34.png&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;433&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 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Code 영역&amp;nbsp;&lt;/b&gt;(Text)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 실행한 프로그램의 코드가 저장되는 메모리 영역&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Data 영역&amp;nbsp;&lt;/b&gt;(Bss, GVAR)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역변수 또는 static 변수가 저장되는 메모리 영역&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Heap 영역&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래머가 동적으로 공간을 할당하거나 해제하는 메모리 영역 , runtime에 메모리 영역의 크기가 결정된다.&lt;/p&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;b&gt;Stack 영역&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 호출시 생성되는 데이터 (지역변수,매개변수, 리턴값)가&amp;nbsp; 저장되는 임시 메모리 영역&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/91</guid>
      <comments>https://dding9code.tistory.com/91#entry91comment</comments>
      <pubDate>Wed, 13 Apr 2022 18:47:58 +0900</pubDate>
    </item>
    <item>
      <title>Object 클래스 - JAVA</title>
      <link>https://dding9code.tistory.com/90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java.lang 패키지 중에서도 가장 많이 사용되는 클래스는 바로 Obecjt이다. &lt;b&gt;Obejct 클래스는 모든 클래스의 최고 조상&lt;/b&gt;이기 때문에 해당 멤버들은 모든 클래스에서 바로 사용이 가능합니다. 멤버변수는 없고 11개의 메서드만 가지고 있습니다. 해당 포스터에서는 5가지만 정리하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;equals(Object obj)&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개변수로 객체의 참조변수를 받아 비교하여 boolean 값으로 return 합니다.&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;스크린샷 2022-04-12 오후 10.57.17.png&quot; data-origin-width=&quot;293&quot; data-origin-height=&quot;72&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kyGTE/btrzdwdBW2q/ZRiSl3fFzal4nXqDdr5SPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kyGTE/btrzdwdBW2q/ZRiSl3fFzal4nXqDdr5SPk/img.png&quot; data-alt=&quot;Object.java 에 equals&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kyGTE/btrzdwdBW2q/ZRiSl3fFzal4nXqDdr5SPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkyGTE%2FbtrzdwdBW2q%2FZRiSl3fFzal4nXqDdr5SPk%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;293&quot; height=&quot;72&quot; data-filename=&quot;스크린샷 2022-04-12 오후 10.57.17.png&quot; data-origin-width=&quot;293&quot; data-origin-height=&quot;72&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Object.java 에 equals&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;두 객체의 같고 다름을 참조변수의 값으로 판단합니다. 그래서 두 객체가 다르면 항상 false를 반환하게 됩니다.&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;pre id=&quot;code_1649772182941&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;

public class Example {

    public static void main(String[] args) throws FileNotFoundException {
        Value num1 = new Value(10);
        Value num2 = new Value(10);
        String a = new String(&quot;abc&quot;);
        String b = new String(&quot;abc&quot;);


        System.out.println(&quot;Value 객체 결과 =&amp;gt;&quot; + num1.equals(num2));
        System.out.println(&quot;String 결과 =&amp;gt;&quot; + a.equals(b));
    }

    static class Value{
        int x;

        public Value(int x) {
            this.x = x;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.03.16.png&quot; data-origin-width=&quot;186&quot; data-origin-height=&quot;49&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MBEbp/btrzbGayqK7/pZn00KOdWIzLu7xPiSzS4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MBEbp/btrzbGayqK7/pZn00KOdWIzLu7xPiSzS4k/img.png&quot; data-alt=&quot;출력 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MBEbp/btrzbGayqK7/pZn00KOdWIzLu7xPiSzS4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMBEbp%2FbtrzbGayqK7%2FpZn00KOdWIzLu7xPiSzS4k%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;186&quot; height=&quot;49&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.03.16.png&quot; data-origin-width=&quot;186&quot; data-origin-height=&quot;49&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출력 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분명 Value의 인스턴스인 num1, num2 의 값은 같은데 false를 출력하고, String a, b 의 값은 같은데 왜 true라는 다른 결과가 나왔을까요? 그 이유는 Value의 equals는 실제 인스턴스 주소를 비교를 하기 때문에 값이 10으로 같더라도 주소값이 달라서 false를 반환합니다. String클래스의 equals는 오버라이딩을 통해 재정의 되었으며, 주소값이 아닌 실제 문자열을 비교하기 때문에 true가 반환됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.06.29.png&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/njQ5s/btrzdqkryRK/kX01287ah9h5Ngs5QpDr80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/njQ5s/btrzdqkryRK/kX01287ah9h5Ngs5QpDr80/img.png&quot; data-alt=&quot;String.java 의 equlas&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/njQ5s/btrzdqkryRK/kX01287ah9h5Ngs5QpDr80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnjQ5s%2FbtrzdqkryRK%2FkX01287ah9h5Ngs5QpDr80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;497&quot; height=&quot;263&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.06.29.png&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;String.java 의 equlas&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 객체에 대한 어떤 값을 비교하고자 하면 오버라이딩을 통하여 equals 를 재정의 하여 사용하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*String 클래스뿐만 아니라 Date, File, wrapper클래스(Integer, Double 등)의 equals 메서드도 주소값이 아닌 내용을 비교하도록 오버라이딩 되어있다. 의외로 StringBuffer, Builder 클래스는 오버라이딩되어 있지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;hashCode( )&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 메서드는 해싱기법에 사용되는 해시함수를 구현한 것입니다. 해시함수는 찾고자 하는 값을 입력하면 그 값이 저장된 위치를 알려주는 해시코드를 반환합니다. Object의 hashCode 는 객체의 주소값을 이용해 해시코드를 만들어 반환하기 때문에 서로 다른 두 객체는 결코 같은 해시코드를 가질 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1649772796359&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;

public class Example {

    public static void main(String[] args) throws FileNotFoundException {
        Value num1 = new Value(10);
        Value num2 = new Value(10);
        String a = new String(&quot;abc&quot;);
        String b = new String(&quot;abc&quot;);


        System.out.println(&quot;Value num1 해시코드 결과 =&amp;gt;&quot; + num1.hashCode());
        System.out.println(&quot;Value num1 해시코드 결과 =&amp;gt;&quot; + num2.hashCode());
        System.out.println(&quot;String a 해시코드 결과 =&amp;gt;&quot; + a.hashCode());
        System.out.println(&quot;String b 해시코드 결과 =&amp;gt;&quot; + b.hashCode());
    }

    static class Value{
        int x;

        public Value(int x) {
            this.x = x;
        }

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.13.34.png&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYXGbj/btrzdNT2Rwx/wdsK9WheeHPDOLHENKnXBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYXGbj/btrzdNT2Rwx/wdsK9WheeHPDOLHENKnXBk/img.png&quot; data-alt=&quot;출력 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYXGbj/btrzdNT2Rwx/wdsK9WheeHPDOLHENKnXBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYXGbj%2FbtrzdNT2Rwx%2FwdsK9WheeHPDOLHENKnXBk%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;272&quot; height=&quot;94&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.13.34.png&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출력 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과를 보고 눈치를 채셨을 것입니다. Value 클래스로 생성된 인스턴스는 '다른 객체' 이기에 다른 해시코드값을 반환을 하였고, String 클래스로 생성된 인스턴스는 hashCode가 오버라이딩 되어있기 때문에 같은 해시코드를 반환하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;toString( )&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 메서드는 인스턴스에 대한 정보를 문자열(String)로 제공할 목적으로 정의한 것입니다. 인스턴스 변수에 저장된 값들을 문자열로 표현한다는 뜻입니다.&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;스크린샷 2022-04-12 오후 11.22.35.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;71&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bt5xKN/btrze0ehjEI/eduXvXOgow4OIKe39jPRZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bt5xKN/btrze0ehjEI/eduXvXOgow4OIKe39jPRZ1/img.png&quot; data-alt=&quot;Object.java 의 toSting&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bt5xKN/btrze0ehjEI/eduXvXOgow4OIKe39jPRZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbt5xKN%2Fbtrze0ehjEI%2FeduXvXOgow4OIKe39jPRZ1%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;580&quot; height=&quot;71&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.22.35.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;71&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Object.java 의 toSting&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 Obejct 클래스의 내부를 보면 16진수의 해시코드를 얻기 때문에 오버라이딩을 하여 사용을 해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;오버라이딩 사용X 코드&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1649773497606&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;

public class Example {

    public static void main(String[] args) throws FileNotFoundException {
        Value num1 = new Value(10);
        Value num2 = new Value(10);

        System.out.println(&quot;Value num1 해시코드 결과 =&amp;gt;&quot; + num1.toString());
        System.out.println(&quot;Value num2 해시코드 결과 =&amp;gt;&quot; + num2.toString());
    }

    static class Value{
        int x;

        public Value(int x) {
            this.x = x;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.25.18.png&quot; data-origin-width=&quot;392&quot; data-origin-height=&quot;52&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKUBma/btrzfATYdPE/XF6xoISSrKQJfxAqIC1IY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKUBma/btrzfATYdPE/XF6xoISSrKQJfxAqIC1IY0/img.png&quot; data-alt=&quot;오버라이딩 사용x 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKUBma/btrzfATYdPE/XF6xoISSrKQJfxAqIC1IY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKUBma%2FbtrzfATYdPE%2FXF6xoISSrKQJfxAqIC1IY0%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;392&quot; height=&quot;52&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.25.18.png&quot; data-origin-width=&quot;392&quot; data-origin-height=&quot;52&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;오버라이딩 사용x 결과&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;오버라이딩을 사용하지 않으면 실제로 Value클래스의 16진수 해시값을 반환하는 결과를 얻게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;오버라이딩 사용한 코드&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1649773622682&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;

public class Example {

    public static void main(String[] args) throws FileNotFoundException {
        Value num1 = new Value(10);
        Value num2 = new Value(10);

        System.out.println(&quot;Value num1 toString 결과 =&amp;gt;&quot; + num1.toString());
        System.out.println(&quot;Value num2 toString 결과 =&amp;gt;&quot; + num2.toString());
    }

    static class Value{
        int x;

        public Value(int x) {
            this.x = x;
        }

        @Override
        public String toString() {
            return &quot;Value{&quot; +
                    &quot;x=&quot; + x +
                    '}';
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.27.51.png&quot; data-origin-width=&quot;313&quot; data-origin-height=&quot;52&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDTieZ/btrzfAsS6l1/2rtMQk8b9LZikr5Basm3J0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDTieZ/btrzfAsS6l1/2rtMQk8b9LZikr5Basm3J0/img.png&quot; data-alt=&quot;오버라이딩 사용 출력 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDTieZ/btrzfAsS6l1/2rtMQk8b9LZikr5Basm3J0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDTieZ%2FbtrzfAsS6l1%2F2rtMQk8b9LZikr5Basm3J0%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;313&quot; height=&quot;52&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.27.51.png&quot; data-origin-width=&quot;313&quot; data-origin-height=&quot;52&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;오버라이딩 사용 출력 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;clone( )&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자신을 복제하여 새로운 인스턴스를 생성한다. 단순히 인스턴스 변수의 값만을 복사하기 때문에 참조 타입의 인스턴스 변수가 있는 클래스는 완전한 인스턴스가 복제가 되지 않습니다. 즉 주소를 복사하는 얕은 복사가 이루어져 복사본을 수정해도 같은 주소값을 가지기 때문에 원본도 같이 수정이 됩니다. 그래서 오버라이딩을 통하여 해결을 해야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 clone을 오버라이딩해서 사용하려면 Cloneable 인터페이스를 구현을 해야 합니다. 이유는 Cloneable 인터페이스를 구현을 하지 않으면 예외가 발생할 뿐만 아니라, 인스턴스의 데이터를 보호하기 위해서입니다. 해당 인터페이스가 구현되어 있다는 것은 클래스 작성자가 복제를 허용한다는 의미입니다.&lt;/p&gt;
&lt;p data-ke-size=&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;pre id=&quot;code_1649774354675&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.ArrayList;

public class Example {

    public static void main(String[] args) throws FileNotFoundException {
        ArrayList&amp;lt;Integer&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();
        for (int i = 0; i &amp;lt; 5; i++) {
            list.add(i);
        }

        ArrayList&amp;lt;Integer&amp;gt; cloneList = (ArrayList&amp;lt;Integer&amp;gt;) list.clone();
        cloneList.remove(2);

        System.out.println(&quot;원본 =&quot; + list.toString());
        System.out.println(&quot;사본 =&quot; + cloneList.toString());

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.39.18.png&quot; data-origin-width=&quot;313&quot; data-origin-height=&quot;52&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQ40HL/btrzd9JfbY4/qHKVrNrcGT4YKcDovWpyE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQ40HL/btrzd9JfbY4/qHKVrNrcGT4YKcDovWpyE1/img.png&quot; data-alt=&quot;출력 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ40HL/btrzd9JfbY4/qHKVrNrcGT4YKcDovWpyE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ40HL%2Fbtrzd9JfbY4%2FqHKVrNrcGT4YKcDovWpyE1%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;313&quot; height=&quot;52&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.39.18.png&quot; data-origin-width=&quot;313&quot; data-origin-height=&quot;52&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출력 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clone()을 사용하여 ArrayList를 복사를 해봤습니다. &lt;b&gt;ArrayList도 객체&lt;/b&gt;이기 때문에 Object클래스를 상속받으며 동시에 Cloneable인터페이스와 Serializable인터페이스가 구현이 되어 있습니다. 그래서 Obejct의 클래스 멤버들을 모두 상속받으며, public으로 오버라이딩 해서 직접 호출이 가능하고 반환값이 Obejct 이기 때문에 형변환을 해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.43.22.png&quot; data-origin-width=&quot;579&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZF70r/btrzcQ435pC/oZug52n8RTHHk4rVAdqiiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZF70r/btrzcQ435pC/oZug52n8RTHHk4rVAdqiiK/img.png&quot; data-alt=&quot;Cloneable, Serializable 상속&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZF70r/btrzcQ435pC/oZug52n8RTHHk4rVAdqiiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZF70r%2FbtrzcQ435pC%2FoZug52n8RTHHk4rVAdqiiK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;579&quot; height=&quot;66&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.43.22.png&quot; data-origin-width=&quot;579&quot; data-origin-height=&quot;66&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Cloneable, Serializable 상속&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.43.13.png&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oR30g/btrzbe6pRxY/yI3KU6CXb2DkbEQcbJMER0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oR30g/btrzbe6pRxY/yI3KU6CXb2DkbEQcbJMER0/img.png&quot; data-alt=&quot;ArrayList.java 의 clone&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oR30g/btrzbe6pRxY/yI3KU6CXb2DkbEQcbJMER0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoR30g%2Fbtrzbe6pRxY%2FyI3KU6CXb2DkbEQcbJMER0%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;597&quot; height=&quot;286&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.43.13.png&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;286&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ArrayList.java 의 clone&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;ArrayList뿐만 아니라 Vector, LinkedList, HashSet, TreeSet, HashMap, TreeMap, Calendar, Date와 같은 클래스들이 이와 같은 방식으로 복제가 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;getClass( )&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 메서드는 자신이 속한 클래스의 Class 객체를 반환하는 메서드 입니다. Class객체는 클래스의 모든 정보를 담고 있으며, 클래스당 오직 1개만 존재합니다. 클래스 파일이 '클래스 로더(ClassLodaer)` 에 의해서 메모리에 올라갈 때 자동 생성됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class객체를 이용하면 클래스에 모든 정보를 얻을 수 있기 때문에 동적으로 코드 작성이 가능한데 여기서는 생략을 하겠습니다 '리플렉션 API' 를 검색하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1649775430455&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;

public class Example {

    public static void main(String[] args) throws FileNotFoundException {
        Value num1 = new Value(10);
        Value num2 = new ValueChild(10);
        String a = new String(&quot;abc&quot;);

        System.out.println(&quot;Value num1 getClass 결과 =&amp;gt;&quot; + num1.getClass());
        System.out.println(&quot;Value num2 getClass 결과 =&amp;gt;&quot; + num2.getClass());
        System.out.println(&quot;String a getClass 결과 =&amp;gt;&quot; + a.getClass());
    }

    static class Value{
        int x;

        public Value(int x) {
            this.x = x;
        }
    }

    static class ValueChild extends Value{

        public ValueChild(int x) {
            super(x);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.57.17.png&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;75&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kKZjM/btrzdNGw7gc/0CjaETnLlPHVvD9Eps3W8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kKZjM/btrzdNGw7gc/0CjaETnLlPHVvD9Eps3W8k/img.png&quot; data-alt=&quot;출력결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kKZjM/btrzdNGw7gc/0CjaETnLlPHVvD9Eps3W8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkKZjM%2FbtrzdNGw7gc%2F0CjaETnLlPHVvD9Eps3W8k%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;404&quot; height=&quot;75&quot; data-filename=&quot;스크린샷 2022-04-12 오후 11.57.17.png&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;75&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출력결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>자바 (ref. 자바의정석)</category>
      <category>Obejct클래스</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/90</guid>
      <comments>https://dding9code.tistory.com/90#entry90comment</comments>
      <pubDate>Mon, 11 Apr 2022 21:31:03 +0900</pubDate>
    </item>
    <item>
      <title>[백준 2688] - 줄어들지 않아(JAVA)</title>
      <link>https://dding9code.tistory.com/89</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2688&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/2688&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1649680354499&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;2688번: 줄어들지 않아&quot; data-og-description=&quot;첫째 줄에 테스트 케이스의 개수 T(1 &amp;lt;= T &amp;lt;= 1,000)이 주어진다. 각 테스트 케이스는 숫자 하나 n으로 이루어져 있다. (1 &amp;lt;= n &amp;lt;= 64)&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/2688&quot; data-og-url=&quot;https://www.acmicpc.net/problem/2688&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c1QWzg/hyN1wIlIRq/4IWdK4LrYdYdSgCUoNwHU1/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2688&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/2688&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c1QWzg/hyN1wIlIRq/4IWdK4LrYdYdSgCUoNwHU1/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;2688번: 줄어들지 않아&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 테스트 케이스의 개수 T(1 &amp;lt;= T &amp;lt;= 1,000)이 주어진다. 각 테스트 케이스는 숫자 하나 n으로 이루어져 있다. (1 &amp;lt;= n &amp;lt;= 64)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-11 오후 9.32.41.png&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;717&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2ihK8/btry6u8oEd0/JuIY68tjdxK8GZN5cagbKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2ihK8/btry6u8oEd0/JuIY68tjdxK8GZN5cagbKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2ihK8/btry6u8oEd0/JuIY68tjdxK8GZN5cagbKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2ihK8%2Fbtry6u8oEd0%2FJuIY68tjdxK8GZN5cagbKK%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;1154&quot; height=&quot;717&quot; data-filename=&quot;스크린샷 2022-04-11 오후 9.32.41.png&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;717&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제풀이 전]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플레티넘급의 dp문제를 풀어본적은 없지만 항상 문제를 잘 읽어 제한조건과 요구하는 정답을 보고, 규칙을 빠르게 파악하여 dp테이블을 만들 수 있도록 하는게 중요하다고 생각이 든다.&amp;nbsp;답을 찾아 보면 쉬운데, 그 풀이를 얻는 과정이 조금 어렵다고 생각하기 때문에 시간이 좀 걸리는 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제풀이]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 줄어들지 않는 n자리 수의 개수를 구하는 프로그램을 요구한다. 줄어들지 않는 수는 주어진대로 각 자리 수 보다 그 왼쪽 자리 수가 작거나 같을 때 인데, 0000, 0001, 0111 , 0234 등 이렇게 이루어진다. 그래서 손으로 계산하기 쉬운 한자리수부터 직접 계산을 해서 규칙을 발견을 해보면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 한 자리수를 만들어보면 0, 1, 2, 3, 4 ... 9 로 모두 10개로 구성이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 자리수는 00, 01, 02, ... 11, 12, 13 ..... 55, 56, 57 ..... 88, 89, 99 로 이루어지는데 이전 자리수와의 규칙성을 발견할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0로 시작하는 두 자리수는 00,01,02... 09 로 10개&amp;nbsp; &amp;nbsp; ---&amp;gt; 이전 자리수의 0 ~ 9 까지의 개수의 합&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1로 시작하는 두 자리수는 11,12,13... 19로 총 9개&amp;nbsp; &amp;nbsp; &amp;nbsp; ---&amp;gt; 이전 자리수의 1 ~ 9 까지의 개수의 합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2로 시작하는 두 자리수는 22,23,24... 29로 총 8개 &amp;nbsp; ---&amp;gt; 이전 자리수의 2 ~ 9 까지의 개수의 합&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;9로 시작하는 두 자리수는 99로 총 1개 &lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;---&amp;gt; 이전 자리수의&amp;nbsp; 9 ~ 9 까지의 개수의 합&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dp[i][j] = dp[i-1][j] + dp[i-1][j+1] ...&amp;nbsp; + dp[i-1][8] + dp[i-1][9] 라는 식을 구할 수 있습니다. [ i = 자리수(1 ~ 64) ,&amp;nbsp; j = 숫자( 0 ~ 9)]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한자리수는 모두 1로 구성되어있어 미리 초기화를 시켜주며, 이 문제는 참고로 테스트 케이스가 있는데 매번 테스트 케이스마다 이 값들을 구할 필요없이 미리 dp테이블을 완성시켜, 테스트케이스안에서는 단순 원하는 자리수의 값만 구하여 출력하게 만들면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 더하는 값이 너무 커져 오버플로우가 일어날 수 있으니 테이블은 int 가 아닌 long을 써주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[소스코드]&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1649680433949&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();

        long[][] d = new long[65][10]; //자리수 max 64 , 숫자 1~9
        

        for (int i = 0; i &amp;lt;= 9; i++) {
            d[1][i] = 1;
        }

        //미리 dp테이블 완성하기, while 불필요한 작업X
        for (int k = 2; k &amp;lt;= 64; k++) {
            for (int i = 0; i &amp;lt;= 9; i++) {
                for (int j = i; j &amp;lt;= 9; j++) {
                    d[k][i] += d[k - 1][j];
                }
            }
        }

        int t = Integer.parseInt(br.readLine());


        while (t-- &amp;gt; 0) {
            int n = Integer.parseInt(br.readLine());
            long ans = 0;

            for (int i = 0; i &amp;lt;= 9; i++) {
                ans += d[n][i];
            }

            sb.append(ans + &quot;\n&quot;);
        }

        System.out.println(sb);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준 문제풀이</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/89</guid>
      <comments>https://dding9code.tistory.com/89#entry89comment</comments>
      <pubDate>Sun, 10 Apr 2022 23:43:34 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스 Level3] 여행경로 (JAVA)</title>
      <link>https://dding9code.tistory.com/88</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/43164?language=java&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/43164?language=java&lt;/a&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1649407329369&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 여행경로&quot; data-og-description=&quot;[[&amp;quot;ICN&amp;quot;, &amp;quot;SFO&amp;quot;], [&amp;quot;ICN&amp;quot;, &amp;quot;ATL&amp;quot;], [&amp;quot;SFO&amp;quot;, &amp;quot;ATL&amp;quot;], [&amp;quot;ATL&amp;quot;, &amp;quot;ICN&amp;quot;], [&amp;quot;ATL&amp;quot;,&amp;quot;SFO&amp;quot;]] [&amp;quot;ICN&amp;quot;, &amp;quot;ATL&amp;quot;, &amp;quot;ICN&amp;quot;, &amp;quot;SFO&amp;quot;, &amp;quot;ATL&amp;quot;, &amp;quot;SFO&amp;quot;]&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/43164?language=java&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/43164?language=java&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PHf5y/hyNXnGDLvQ/Lq9BkHyHhKNJLmv5hK0TeK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/bvj5rz/hyNXusgUvA/P0W0kkuOG9a0siMVzUWihK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/43164?language=java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/43164?language=java&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PHf5y/hyNXnGDLvQ/Lq9BkHyHhKNJLmv5hK0TeK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/bvj5rz/hyNXusgUvA/P0W0kkuOG9a0siMVzUWihK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 여행경로&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[[&quot;ICN&quot;, &quot;SFO&quot;], [&quot;ICN&quot;, &quot;ATL&quot;], [&quot;SFO&quot;, &quot;ATL&quot;], [&quot;ATL&quot;, &quot;ICN&quot;], [&quot;ATL&quot;,&quot;SFO&quot;]] [&quot;ICN&quot;, &quot;ATL&quot;, &quot;ICN&quot;, &quot;SFO&quot;, &quot;ATL&quot;, &quot;SFO&quot;]&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-08 오후 5.41.16.png&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tDSWh/btryP8wHiMV/dh0ntAALboIB8u6PXL9xIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tDSWh/btryP8wHiMV/dh0ntAALboIB8u6PXL9xIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tDSWh/btryP8wHiMV/dh0ntAALboIB8u6PXL9xIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtDSWh%2FbtryP8wHiMV%2Fdh0ntAALboIB8u6PXL9xIk%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;800&quot; data-filename=&quot;스크린샷 2022-04-08 오후 5.41.16.png&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제 풀기 전]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;갈수있는 모든 경로를 탐색하여 알파벳 순서가 앞서는 경로를 반환하면 정답이 되는 문제입니다. 경로가 선택되는 순서에 따라 답이 달라지므로 순열을 사용하여 모든 경우를 만들어 보면 됩니다. 문자열을 다루어야 하는 점에서 어려워 힌트를 봤지만 풀고나니 좋은 문제다 라고 느낀 문제였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제 풀이]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서말했듯이 갈수있는 모든 여행지를 만들어야합니다. 이 여행지를 나중에 알파벳 순서가 앞서는 경로를 반환해야하는데 이를 위해 ArrayList&amp;lt;String&amp;gt; 을 만들어서 경로를 담아 줄 것이고, 해당 티켓을 사용했는지 안했는지 판단하는 Boolean 배열도 필요합니다. &lt;b&gt;DFS 탐색&lt;/b&gt;을 통하여 모든 여행지를 만들건데&lt;b&gt; 매개변수 설정이 중요&lt;/b&gt;합니다. 제일 중요한 &lt;b&gt;depth&lt;/b&gt;  와, &lt;b&gt;현재 위치&lt;/b&gt;, &lt;b&gt;방문한 여행 경로&lt;/b&gt;, 문제에 주어진&lt;b&gt; tickets배열&lt;/b&gt;을 넘겨줄 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 처음 시작은 &quot;ICN&quot; 로 시작하니 현재위치와 방문한 여행경로에 넣어주면서면서 탐색을 시작하게 됩니다. 해당 티켓이 사용이 됐는지, 그리고 현재 위치랑 다음 가야할 곳의 출발지를 비교하여 탐색을 하여 depth가 티켓의 수가 같아지면 해당 여행경로를 ArrayList에 담아줍니다. 탐색이 끝나면 list에는 모든 여행경로가 담겨져 있을 겁니다. 리스트를 정렬을 하면 알파벳 순서가 앞서는 경로가 인덱스 0번째에 위치하게 됩니다. 해당 인덱스의 여행경로를 배열로 담아 리턴을 하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[소스 코드]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1649407711242&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {

    static ArrayList&amp;lt;String&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();
    static boolean useTickets[];

    public String[] solution(String[][] tickets) {
        useTickets = new boolean[tickets.length];

        dfs(0, &quot;ICN&quot;, &quot;ICN&quot;, tickets);

        Collections.sort(list);

        return list.get(0).split(&quot; &quot;);
    }

    static void dfs(int depth, String now, String path, String[][] tickets){
        if (depth == tickets.length) {
            list.add(path);
            return;
        }

        for (int i = 0; i &amp;lt; useTickets.length; i++) {
            if (!useTickets[i] &amp;amp;&amp;amp; now.equals(tickets[i][0])) {
                useTickets[i] = true;
                dfs(depth+1, tickets[i][1], path + &quot; &quot; +tickets[i][1], tickets);
                useTickets[i] = false;
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래머스</category>
      <category>여행경로</category>
      <category>프로그래머스</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/88</guid>
      <comments>https://dding9code.tistory.com/88#entry88comment</comments>
      <pubDate>Fri, 8 Apr 2022 18:02:39 +0900</pubDate>
    </item>
    <item>
      <title>제어자(modifier) , 추상클래스  - JAVA</title>
      <link>https://dding9code.tistory.com/87</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;제어자란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스, 변수 또는 메서드 선언부와 함께 사용되어 부가적인 의미를 부여한다. 크게&lt;b&gt; 접근제어자&lt;/b&gt;와 &lt;b&gt;그 외의 제어자&lt;/b&gt;로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;접근제어자&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근제어자란 외부에서 접근하지 못하도록 제한하는 역할을 한다. 클래스, 멤버변수, 메서드, 생성자에 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 92px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; text-align: center; height: 20px;&quot;&gt;이름&lt;/td&gt;
&lt;td style=&quot;width: 71.3953%; text-align: center; height: 20px;&quot;&gt;기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;public&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 71.3953%; height: 18px;&quot;&gt;접근 제한이 없다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;protected&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 71.3953%; height: 18px;&quot;&gt;같은 패키지 내에서, 다른 패키지의 자손클래스에서 접근 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;default&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 71.3953%; height: 18px;&quot;&gt;같은 패키지 내에서만 접근 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 28.6047%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;private&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 71.3953%; height: 18px;&quot;&gt;같은 클래스 내에서만 접근 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;접근 범위는 public -&amp;gt; proteced -&amp;gt; (default) -&amp;gt; private 으로 오른쪽으로 갈 수록 범위가 좁아진다.&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;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;접근 제어자를 사용하는 이유?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정보은닉을 위해서, 즉 캡슐화를 하기 위함이다. 외부에게 불필요한 부분이 노출되는 것을 막고, 외부에서 잘못된 사용으로 객체의 손상, 오용을 막아 유지보수나 확장시 오류를 최소화 하기 위해서 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;pre id=&quot;code_1649296667853&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class People{
    int gamePoint = 5000;

    public void usePoint(int gamePoint) {
        this.gamePoint -= gamePoint;
    }

    public int getGamePoint() {
        return gamePoint;
    }
}

public class Example {

    public static void main(String[] args) {
        People user1 = new People();

        user1.gamePoint = 100000; 
        user1.usePoint(50);

        System.out.println(user1.getGamePoint());
    }
}&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;People 클래스에는 게임포인트라는 멤버변수가 있습니다.&lt;b&gt; 접근 제어자를 default로 설정&lt;/b&gt;하였기 때문에 같은 패키지내에서 gamePoint라는 인스턴스 변수에 접근이 가능합니다. &lt;b&gt;외부에 노출되어 있는 상태&lt;/b&gt;이죠. 그래서 user1 이라는 인스턴스를 생성하고 게임 포인트를 마음대로 외부에서 조작이 가능하게 됩니다. 이러면 운영에 있어서 큰 문제가 발생하겠죠?&lt;/p&gt;
&lt;p data-ke-size=&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;해결방법은 방금 배운 접근제어자인 private를 써서 접근을 제한하면 위의 문제가 해결됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1649296589061&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class People{
   private int gamePoint = 5000;

    public void usePoint(int gamePoint) {
        this.gamePoint -= gamePoint;
    }

    public int getGamePoint() {
        return gamePoint;
    }
}

public class Example {

    public static void main(String[] args) {
        People user1 = new People();

//        user1.gamePoint = 100000; 에러! 접근 불가
        user1.usePoint(50);

        System.out.println(user1.getGamePoint());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근 제어자를 private로 설정하여 외부에서 접근이 불가하도록 막았습니다. 이제 게임포인트에 직접 접근할 수 없는 상태입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생성자의 접근제어자 &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자에도 접근제어자를 사용할 수 있습니다. 접근제어자를 사용하면 &lt;b&gt;인스턴스의 생성을 제한&lt;/b&gt; 할 수 있습니다. 보통은 생성자의 접근 제어자는 해당 클래스와 같지만 다르게도 설정이 가능합니다. &lt;b&gt;싱글톤 패턴에 활용&lt;/b&gt;이 되고, &lt;b&gt;생성자가 private이면 다른 클래스의 부모가 될 수 없습니다.&lt;/b&gt; 왜냐하면 상속받은 자식 클래스가 부모클래스의 생성자를 호출할 수 없기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 상속할 수 없는 클래스같은 경우에는 final 같은 제어자를 추가하여 상속할 수 없는 클래스라는 것을 알리는게 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&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;b&gt;그 외 제어자&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static, final, abstract, native, trasient 등등이 있지만 static, final, abstract 정도만 정리를 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;static - 클래스의, 공통적인&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static 은 '클래스의' or '공통적인' 이라는 의미를 가지고 있으며 멤버변수, 메서드, 초기화 블럭에 사용이 가능합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 50px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 15.1937%; height: 18px; text-align: center;&quot;&gt;제어자&lt;/td&gt;
&lt;td style=&quot;width: 21.5892%; height: 18px; text-align: center;&quot;&gt;대상&lt;/td&gt;
&lt;td style=&quot;width: 63.217%; height: 18px; text-align: center;&quot;&gt;의미&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 14px;&quot;&gt;
&lt;td style=&quot;width: 15.1937%; height: 32px; text-align: center;&quot; rowspan=&quot;2&quot;&gt;&lt;b&gt;static&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 21.5892%; height: 14px; text-align: center;&quot;&gt;&lt;b&gt;멤버변수&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.217%; height: 14px;&quot;&gt;- 모든 인스턴스에 공통적으로 사용되는 클래스변수가 된다.&lt;br /&gt;- 클래스 변수는 인스턴스 생성없이 사용이 가능하다.&lt;br /&gt;- 클래스가 메모리에 로드될 때 생성이 됨.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 21.5892%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;메서드&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.217%; height: 18px;&quot;&gt;- 인스턴스를 생성하지 않고도 호출이 가능한 static메서드가 된다.&amp;nbsp;&lt;br /&gt;- static 메서드 내에서는 인스턴스멤버들을 직접 사용이 불가 &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-&amp;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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;final - 마지막의, 변경될 수 없는&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;final은 '마지막의' 또는 '변경될 수 없는' 의미를 가지고 있으며 클래스, 메서드, 멤버변수, 지역변수에 사용이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 88px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 16.8216%; height: 20px; text-align: center;&quot;&gt;제어자&lt;/td&gt;
&lt;td style=&quot;width: 20.0775%; height: 20px; text-align: center;&quot;&gt;대상&lt;/td&gt;
&lt;td style=&quot;width: 63.1008%; height: 20px; text-align: center;&quot;&gt;의미&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 16.8216%; height: 68px; text-align: center;&quot; rowspan=&quot;4&quot;&gt;&lt;b&gt;final&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.0775%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;클래스&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.1008%; height: 20px;&quot;&gt;- 변경불가 클래스, 확장될 수 없는 클래스&lt;br /&gt;- 다른 클래스의 부모가 될 수 없다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 20.0775%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;메서드&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.1008%; height: 20px;&quot;&gt;- 변경불가 메서드, final로 지정된 메서드는 오버라이딩을 통한 재정의가 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 20.0775%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;멤버변수&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.1008%; height: 18px;&quot; rowspan=&quot;2&quot;&gt;- 변수 앞에 사용이 되면, 값을 변경할 수 없는 상수가 된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 20.0775%; height: 10px; text-align: center;&quot;&gt;&lt;b&gt;지역변수&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* &lt;b&gt;final 이 붙은 변수는 상수&lt;/b&gt;이기 때문에 일반적으로 선언과 동시에 초기화를 하지만 &lt;b&gt;인스턴스 변수의 경우 생성자에서 초기화 될 수 있게 한다&lt;/b&gt;. 그래서 &lt;b&gt;각 인스턴스마다&lt;/b&gt; final 이 붙은 멤버변수가 &lt;b&gt;다른 값&lt;/b&gt;을 가질 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1649298845141&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class People{
    private final int gamePoint;

// 에러가 발생한다. final 이 붙은 변수를 변경하려고 했기 때문이다.
//    public void usePoint(int gamePoint) {
//        this.gamePoint -= gamePoint;   
//    }

    public int getGamePoint() {
        return gamePoint;
    }
}

public class Example {

    public static void main(String[] args) {
        People user1 = new People(5000);
        People user2 = new People(700);
        People user3 = new People(9820);

        System.out.println(user1.getGamePoint());
        System.out.println(user2.getGamePoint());
        System.out.println(user3.getGamePoint());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-07 오전 11.35.06.png&quot; data-origin-width=&quot;166&quot; data-origin-height=&quot;72&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beE7Pl/btryCDrvs6b/5PERXdg0FuJIcmzB44YIJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beE7Pl/btryCDrvs6b/5PERXdg0FuJIcmzB44YIJk/img.png&quot; data-alt=&quot;출력 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beE7Pl/btryCDrvs6b/5PERXdg0FuJIcmzB44YIJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeE7Pl%2FbtryCDrvs6b%2F5PERXdg0FuJIcmzB44YIJk%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;166&quot; height=&quot;72&quot; data-filename=&quot;스크린샷 2022-04-07 오전 11.35.06.png&quot; data-origin-width=&quot;166&quot; data-origin-height=&quot;72&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출력 결과&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;abstract - 추상의, 미완성의&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;abstract 는 '미완성' 의 의미를 가지고 있으며 클래스, 메서드에 사용이 됩니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.4728%; text-align: center;&quot;&gt;제어자&lt;/td&gt;
&lt;td style=&quot;width: 21.2403%; text-align: center;&quot;&gt;대상&lt;/td&gt;
&lt;td style=&quot;width: 57.2868%; text-align: center;&quot;&gt;의미&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.4728%; text-align: center;&quot; rowspan=&quot;2&quot;&gt;&lt;b&gt;abstract&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 21.2403%; text-align: center;&quot;&gt;&lt;b&gt;클래스&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 57.2868%;&quot;&gt;- 클래스 내에 추상 메서드가 선언되어 있음을 의미&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.2403%; text-align: center;&quot;&gt;&lt;b&gt;메서드&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 57.2868%;&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;추상클래스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;미완성 설계도&lt;/b&gt;에 비유할 수 있다. &lt;b&gt;추상클래스로는 인스턴스 생성이 불가&lt;/b&gt;하며, &lt;b&gt;상속을 통하여 자식클래스에서 완성&lt;/b&gt;(구체화)이 가능하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 새로운 클래스를 작성하는데 &lt;b&gt;공통부분을 가지는 틀&lt;/b&gt;이 될 수 있다. 즉 효율적으로 새로운 클래스를 작성할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;추상화 :&lt;/b&gt; 클래스 간의 공통점을 찾아내 공통의 부모로 만드는 작업&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구체화&lt;/b&gt; &lt;b&gt;:&lt;/b&gt; 상속을 통해 클래스를 구현, 확장하는 작업&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;추상메서드&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선언부만 작성하고 구현부는 작성하지 않는다. 이유는 상속받는 클래스에 따라 기능이 달라질 수 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현부가 없는 메서드가 뭐가 좋고, 어떤 의미를 가지냐고 생각 할 수 있지만, 메서드의 이름과 매개변수, 리턴값을 정하는 것은 쉽지 않다. 이 선언부만 알고 있으면 내용이 없을 지라도 코드작성이 가능하며, 실제로는 자식클래스에 구현된 완성된 메서드가 호출되도록 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추상 클래스, 메서드 사용 예)&lt;/p&gt;
&lt;pre id=&quot;code_1649300310217&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;abstract class Item{
    abstract void buyItem(int quantity);
}

class Book extends Item{
    private static int stockQuantity = 1000;

    @Override
    void buyItem(int quantity) {
        this.stockQuantity -= quantity;
    }

    public int getStockQuantity() {
        return stockQuantity;
    }
}

public class Example {

    public static void main(String[] args) {
//        Item item = new Item(); //인스턴스 생성 부락
        Book book = new Book();
        book.buyItem(50);

        System.out.println(&quot;남은 재고 = &quot; + book.getStockQuantity() + &quot; 개&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-07 오전 11.58.48.png&quot; data-origin-width=&quot;130&quot; data-origin-height=&quot;23&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmhbsu/btryCPe0Xub/lkTSevbkbwkKRCBZive4D1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmhbsu/btryCPe0Xub/lkTSevbkbwkKRCBZive4D1/img.png&quot; data-alt=&quot;출력 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmhbsu/btryCPe0Xub/lkTSevbkbwkKRCBZive4D1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcmhbsu%2FbtryCPe0Xub%2FlkTSevbkbwkKRCBZive4D1%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;130&quot; height=&quot;23&quot; data-filename=&quot;스크린샷 2022-04-07 오전 11.58.48.png&quot; data-origin-width=&quot;130&quot; data-origin-height=&quot;23&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출력 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제에서는 Book 클래스만 구현을 했는데, 재고가 쌓일만한 어떠한 물건이라도 클래스를 만들어 해당 물건을 몇개만큼 구입을 하면 남은 재고를 출력할 수 있도록 만들 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;긴글 읽어주셔서 감사합니다. 예제가 잘못되었거나 질문이 있으시면 언제든 댓글달아주시면 빠르게 답변하도록 하겠습니다.&lt;/p&gt;</description>
      <category>자바 (ref. 자바의정석)</category>
      <category>제어자</category>
      <category>추상클래스</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/87</guid>
      <comments>https://dding9code.tistory.com/87#entry87comment</comments>
      <pubDate>Wed, 6 Apr 2022 20:18:55 +0900</pubDate>
    </item>
    <item>
      <title>기본형 매개변수와 참조형 매개변수 - JAVA</title>
      <link>https://dding9code.tistory.com/86</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서 많이 사용되는 메서드는 &lt;b&gt;'반환타입 메서드이름 ( 매개변수 선언 ) { }'&lt;/b&gt; 구조로 이루어져 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드를 호출할 때 매개변수로 지정한 값을 메서드의 매개변수에 복사해서 넘겨주는데 매개변수의 타입에 따라서 다릅니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;기본형(primitive type) 매개변수 : 기본형 값이 복사, 변수의 값을 읽기만 할 수 있다. (read only)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;참조형(reference type) 매개면수 : 변수의 값을 읽고 변경할 수 있다.(read &amp;amp; write)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무슨 차이가 있는지 예제를 통하여 보여드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 기본형&lt;/b&gt;&amp;nbsp;&lt;b&gt;매개변수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1649121971295&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Data{
    int x;
}

public class Example {

    public static void main(String[] args) {
        Data data = new Data();
        data.x = 20;
        System.out.println(&quot;Before data(data.x): &quot; + data.x);

        change(data.x);

        System.out.println(&quot;After Change(data.x): &quot; + data.x);
    }

    static void change(int x) {
        x = 50;
        System.out.println(&quot;change func() : x = &quot; + x);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-05 오전 10.26.19.png&quot; data-origin-width=&quot;215&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwEwe7/btrytkETYm1/y9iiuz5I8Oii3O8dQ3LyU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwEwe7/btrytkETYm1/y9iiuz5I8Oii3O8dQ3LyU0/img.png&quot; data-alt=&quot;출력 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwEwe7/btrytkETYm1/y9iiuz5I8Oii3O8dQ3LyU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwEwe7%2FbtrytkETYm1%2Fy9iiuz5I8Oii3O8dQ3LyU0%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;215&quot; height=&quot;66&quot; data-filename=&quot;스크린샷 2022-04-05 오전 10.26.19.png&quot; data-origin-width=&quot;215&quot; data-origin-height=&quot;66&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출력 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;change 메서드를 통하여 data.x 를&amp;nbsp; 매개변수로 받아 값을 50으로 바꿨지만 main문에서는 값이 변하지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data.x의 값이 변경된 것이 아닌, change메서드의 매개변수 x의 값만 변경이 되고 x는 메서드 종료와 함께 제거가 됐기 때문입니다. &lt;b&gt;원본이 아닌 복사본이 변경된 것이기 때문에 원본에는 아무런 영향을 미치지 못했습니다&lt;/b&gt;. 이렇게 기본형 매개변수는 값을 읽을 수 있고 변경은 불가합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 어떻게 기본형 매개변수로 값을 사용하여 값을 변경하나요? 변경된 값을 반환하여 원본에 대입하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1649122351985&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Data{
    int x;
}

public class Example {

    public static void main(String[] args) {
        Data data = new Data();
        data.x = 20;
        System.out.println(&quot;Before data(data.x): &quot; + data.x);

        data.x = change(data.x);

        System.out.println(&quot;After Change(data.x): &quot; + data.x);
    }

    static int change(int x) {
        x = 50;
        System.out.println(&quot;change func() : x = &quot; + x);
        return x;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-05 오전 10.32.39.png&quot; data-origin-width=&quot;215&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qtlJA/btryvaoffBo/xwKGnvCYdz8iQHMUolScak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qtlJA/btryvaoffBo/xwKGnvCYdz8iQHMUolScak/img.png&quot; data-alt=&quot;출력 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qtlJA/btryvaoffBo/xwKGnvCYdz8iQHMUolScak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqtlJA%2FbtryvaoffBo%2FxwKGnvCYdz8iQHMUolScak%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;215&quot; height=&quot;66&quot; data-filename=&quot;스크린샷 2022-04-05 오전 10.32.39.png&quot; data-origin-width=&quot;215&quot; data-origin-height=&quot;66&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출력 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 참조형 매개변수&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1649122616826&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Data{
    int x;
}

public class Example {

    public static void main(String[] args) {
        Data data = new Data();
        data.x = 20;
        System.out.println(&quot;Before data(data.x): &quot; + data.x);

        change(data);

        System.out.println(&quot;After Change(data.x): &quot; + data.x);
    }

    static void change(Data data) {
        data.x = 50;
        System.out.println(&quot;change func() : x = &quot; + data.x);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-05 오전 10.32.39.png&quot; data-origin-width=&quot;215&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/60ZDg/btrytimghwE/iYwkfBRve3HorF8BxXiLB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/60ZDg/btrytimghwE/iYwkfBRve3HorF8BxXiLB0/img.png&quot; data-alt=&quot;출력 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/60ZDg/btrytimghwE/iYwkfBRve3HorF8BxXiLB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F60ZDg%2FbtrytimghwE%2FiYwkfBRve3HorF8BxXiLB0%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;215&quot; height=&quot;66&quot; data-filename=&quot;스크린샷 2022-04-05 오전 10.32.39.png&quot; data-origin-width=&quot;215&quot; data-origin-height=&quot;66&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출력 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본형과 다르게 매개변수로 참조형을 사용했는데 이전 예제와 결과가 다른 이유는 참조형은 값이 아닌 '값이 저장된 주소' 를 넘겨주기 때문입니다. 그래서 해당 주소의 값을 변경하게 되면, 원본이 가리키고 있는 주소의 값이 변경된 것이기 때문에 값이 변하게 됩니다. 즉 값을 읽어오는 것뿐만 아니라 변경도 가능하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 배열을 매개변수로 넘겨주었을 때 원본까지 바뀌는 경험을 하셨을 수도 있을겁니다. 그 이유가 배열도 객체와 같이 참조 변수를 통해 데이터가 저장된 공간에 접근하기 때문에 주소 값을 넘겨 원본까지 바뀌게 되는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>자바 (ref. 자바의정석)</category>
      <category>기본형</category>
      <category>매개변수</category>
      <category>참조형</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/86</guid>
      <comments>https://dding9code.tistory.com/86#entry86comment</comments>
      <pubDate>Mon, 4 Apr 2022 23:07:37 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스 Level2] 메뉴 리뉴얼(JAVA) - 2021 카카오</title>
      <link>https://dding9code.tistory.com/85</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/72411?language=java&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/72411?language=java&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1648729321152&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 메뉴 리뉴얼&quot; data-og-description=&quot;레스토랑을 운영하던 스카피는 코로나19로 인한 불경기를 극복하고자 메뉴를 새로 구성하려고 고민하고 있습니다. 기존에는 단품으로만 제공하던 메뉴를 조합해서 코스요리 형태로 재구성해서&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/72411?language=java&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/72411?language=java&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cdIf8Z/hyNRZZWZGq/61NnXo6ya3BySDbzj67QMK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/dxcAHV/hyNTkVGSa3/vOEVBOYQaaH5YM4tNpozw1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/72411?language=java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/72411?language=java&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cdIf8Z/hyNRZZWZGq/61NnXo6ya3BySDbzj67QMK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/dxcAHV/hyNTkVGSa3/vOEVBOYQaaH5YM4tNpozw1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 메뉴 리뉴얼&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;레스토랑을 운영하던 스카피는 코로나19로 인한 불경기를 극복하고자 메뉴를 새로 구성하려고 고민하고 있습니다. 기존에는 단품으로만 제공하던 메뉴를 조합해서 코스요리 형태로 재구성해서&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제의 내용이 길어 생략했습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제 풀기 전]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오 문제는 항상 문제를 잘 읽는것은 기본이고, 2레벨 정도 난이도는 어설프게 자료구조를 알고있으면 풀 수 없는 것 같다. 문제가 길 뿐이지 생각보다 구현한 코드를 보면 그렇게 길지도 않고 엄청 어렵다 느낌은 들지 않는다. HashMap 에 대하여 좀 더 정확한 개념과 메서드를 익숙하게 다루는게 중요한 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제 풀이]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 메뉴별로 만들 수 있는 조합을 만들면 된다. 선택하고 안하고의 방식을 사용할 것인데 왜냐하면 순서와 상관없이 결과는 같기 때문입니다.(XY = YX ) 그런데 이 문제에서 결과를 오름차순 형태로 배열에 담겨있어야하니 정렬을 미리 해두면 편하게 코드를 구현할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;course 배열에 담긴 수 만큼 코스요리를 만들어야 하니 각각 요소의 개수가 되면 탈출하도록 dfs를 구현 할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 course의 수만큼 반복을 해야하고 HashMap&amp;lt;요리조합, 주문된 수&amp;gt; 의 형태로 보관을 할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 HashMap이 완성이 되었으면 이 해시맵이 비어있지 않다면 max값을 찾을 건데 이 값을 찾기 쉽게 List에 옮겨 Collections.max 를 활용하여 max값을 찾으면 됩니다. 그리고 2개이상 주문 되어야 코스요리가 되기 때문에 max &amp;gt; 1 의 조건을 담고 중복이 허용되니 max 값이랑 일치하는 모든 키를 정렬한 뒤 배열에 담으면 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[소스 코드]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1648777786271&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    
    static HashMap&amp;lt;String, Integer&amp;gt; hm = new HashMap&amp;lt;&amp;gt;();
    static ArrayList&amp;lt;String&amp;gt; answerList = new ArrayList&amp;lt;&amp;gt;();
    
    public String[] solution(String[] orders, int[] course) {
        String[] answer = {};

        for (int i : course) {
            for (String order : orders) {
                char[] chars = order.toCharArray();
                Arrays.sort(chars);

                dfs(0, &quot;&quot;, chars, i);
            }

            if (!hm.isEmpty()) {
                List&amp;lt;Integer&amp;gt; countList = new ArrayList&amp;lt;&amp;gt;(hm.values());
                int max = Collections.max(countList);

                if (max &amp;gt; 1) {
                    for (String key : hm.keySet()) {
                        if (hm.get(key) == max) {
                            answerList.add(key);
                        }
                    }
                }
            }
            hm.clear();
        }

        Collections.sort(answerList);
        answer = new String[answerList.size()];

        for (int i = 0; i &amp;lt; answer.length; i++) {
            answer[i] = answerList.get(i);
        }

        return answer;
    }

    static void dfs(int depth, String course, char[] chars, int i) {
        if (course.length() == i) {
            if (hm.containsKey(course)) {
                hm.put(course, hm.get(course) + 1);
            }else{
                hm.put(course, 1);
            }
            return;
        }

        if (depth &amp;gt;= chars.length) {
            return;
        }

        dfs(depth + 1, course + chars[depth], chars, i);
        dfs(depth + 1, course, chars, i);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/85</guid>
      <comments>https://dding9code.tistory.com/85#entry85comment</comments>
      <pubDate>Thu, 31 Mar 2022 21:22:27 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스 Level2] 순위 검색(JAVA) - 2021 카카오</title>
      <link>https://dding9code.tistory.com/84</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/72412&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/72412&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1648647998108&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 순위 검색&quot; data-og-description=&quot;[&amp;quot;java backend junior pizza 150&amp;quot;,&amp;quot;python frontend senior chicken 210&amp;quot;,&amp;quot;python frontend senior chicken 150&amp;quot;,&amp;quot;cpp backend senior pizza 260&amp;quot;,&amp;quot;java backend junior chicken 80&amp;quot;,&amp;quot;python backend senior chicken 50&amp;quot;] [&amp;quot;java and backend and junior and pizza 100&amp;quot;,&amp;quot;pyt&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/72412&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/72412&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sxXCG/hyNRZYUhvD/RyCKag7QRNTsXCcf3Wy91k/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/ASstT/hyNQ9B11Tt/RoQ4Rmkmkut5ssobkIEpq1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/72412&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/72412&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sxXCG/hyNRZYUhvD/RyCKag7QRNTsXCcf3Wy91k/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/ASstT/hyNQ9B11Tt/RoQ4Rmkmkut5ssobkIEpq1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 순위 검색&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[&quot;java backend junior pizza 150&quot;,&quot;python frontend senior chicken 210&quot;,&quot;python frontend senior chicken 150&quot;,&quot;cpp backend senior pizza 260&quot;,&quot;java backend junior chicken 80&quot;,&quot;python backend senior chicken 50&quot;] [&quot;java and backend and junior and pizza 100&quot;,&quot;pyt&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제가 길어서 생략하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제 풀기 전]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 효율성 처리를 할 방법이 도저히 생각이 나지 않아 정확성이라도 맞추자 하는 심정으로 문제를 풀었습니다. 정확성으로 푼 방법은 쿼리의 개수만큼 반복하는데 쿼리를 split 하여 info에서 찾도록 아주 무식한 방법으로 풀었습니다. 역시 효율성은 당연히 떨어졌습니다. 그래서 답을 좀 이곳저곳 찾아봤는데 기본기가 정말 탄탄해야 풀 수 있도록 설계가 된 문제였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제 풀이]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;우선 info가 만들 수 있는 모든 경우를 HashMap 으로 만들어야 합니다.&lt;/b&gt; 왜 해시맵인가 하면 해시 특성상 key가 주어지면 O(1)의 속도로 찾을 수 있기 때문에, query에 따라 모든 정보를 하나하나 찾지 않아도 됩니다. 만약 효율성이 틀렸으면 이렇게 query에 따라 info를 하나하나씩 다 찾게 했을 텐데 info와 query의 크기가 5만 , 10만 크기라서&amp;nbsp; 아주 큰 시간 복잡도를 가져 시간 초과가 날 수밖에 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;해시맵은 한번 만들 때, 만들고 나서 해시 맵을 바꿀 일이 없게 완벽하게 구현&lt;/b&gt;을 해야합니다. 만약 &lt;b&gt;쿼리를 할 때마다 뭔가 연산이 추가가 된다면 검색을 할 때마다 느려진다는 것을 의미&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시맵은 &amp;lt;String, ArrayList&amp;lt;Integer&amp;gt;&amp;gt;의 형태로 만들어지게 됩니다.&amp;nbsp; 예를 들어 문제 기준으로 ----이라는 키가 만들어지면 해당 키는 전체를 의미하기 때문에 150,260,150,210,80,50이라는 값이 들어가게 되어 List의 형태로 관리를 해줘야 합니다. 그리고 만들어진 &lt;b&gt;List는 정렬을 해줘야 합니다.&amp;nbsp;&lt;/b&gt;만약 정렬을 하지 않으면 특정 값 이상의 개수를 찾으려면 for문으로 하나하나 찾아가는게 최악의 경우가 이 또한 5만 * 10만 이 되겠죠. &lt;b&gt;정렬이 되었으니 이분탐색&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;이 내용을 기반으로 그대로 코드를 구현하면 원하는 답을 얻을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[소스 코드]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1648694090423&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {

    static HashMap&amp;lt;String, ArrayList&amp;lt;Integer&amp;gt;&amp;gt; hashMap = new HashMap&amp;lt;&amp;gt;();
    static ArrayList&amp;lt;Integer&amp;gt; score = new ArrayList&amp;lt;&amp;gt;();

    public int[] solution(String[] info, String[] query) {
        int[] answer = {};

        //모든 경우의 해시맵 만들기
        for (String i : info) {
            dfs(0, &quot;&quot;, i.split(&quot; &quot;));
        }

        //해시맵의 리스트들을 정렬
        for (ArrayList&amp;lt;Integer&amp;gt; list : hashMap.values()) {
            Collections.sort(list);
        }

        answer = new int[query.length];
        int i = 0; //쿼리반복횟수 및 answer[i] 
        for (String q : query) {
            String[] data = q.split(&quot; and &quot;);

            String[] s = data[3].split(&quot; &quot;);
            int target = Integer.parseInt(s[1]); //찾아야할 값
            data[3] = s[0];

            String key = String.join(&quot;&quot;, data);

            if (hashMap.containsKey(key)) {
                ArrayList&amp;lt;Integer&amp;gt; list = hashMap.get(key);
                int start = 0;
                int end = list.size() - 1;

                while (start &amp;lt;= end) {
                    int mid = (start + end) / 2;

                    if (list.get(mid) &amp;lt; target) {
                        start = mid + 1;
                    }else{
                        end = mid - 1;
                    }
                }

                answer[i] = list.size() - start;
            }
            i++;
        }
        return answer;
    }

    static void dfs(int depth, String query, String[] info) {
        if(depth == 4){
            if (!hashMap.containsKey(query)) {
                score = new ArrayList&amp;lt;&amp;gt;();
                score.add(Integer.parseInt(info[4]));
                hashMap.put(query, score);
            }else{
                hashMap.get(query).add(Integer.parseInt(info[4]));
            }
            return;
        }

        dfs(depth + 1, query + &quot;-&quot;, info);
        dfs(depth + 1, query + info[depth], info);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래머스</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/84</guid>
      <comments>https://dding9code.tistory.com/84#entry84comment</comments>
      <pubDate>Wed, 30 Mar 2022 22:50:46 +0900</pubDate>
    </item>
    <item>
      <title>기본형(Primtive Type) - JAVA</title>
      <link>https://dding9code.tistory.com/83</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dding9code.tistory.com/45?category=1258691&quot;&gt;https://dding9code.tistory.com/45?category=1258691&lt;/a&gt; 변수 포스팅을 했었는데 그중 기본형에 대하여 내용이 부실하여 추가로 글을 쓰게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;기본형이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 값(data)을 저장하는 데이터 타입으로 논리형, 문자형, 정수형, 실수형 으로 나누어 집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;논리형 (boolean)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;논리형은&lt;/b&gt; &lt;b&gt;boolean 하나만 존재&lt;/b&gt;하며, boolean &lt;b&gt;변수는 true, false&lt;/b&gt; 밖에 저장을 할 수 없다. &lt;b&gt;기본(default)는 false&lt;/b&gt; 이다. 주로 대답(yes/no), 스위치(on/off), 플래그 등의 &lt;b&gt;논리구현에 주로 사용&lt;/b&gt;된다. true, false 만을 사용하기에 1bit 로 충분하지만 자바에서 데이터를 다루는 최소 단위는 byte이다. 그래서 &lt;b&gt;boolean의 크기는 1 byte&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문자형 (char)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 문자형은 char 하나만 존재하며, 단 하나의 문자만을 저장합니다. 문자를 저장한다해서 문자가 메모리에 저장이 될 것 같지만, 컴퓨터는 숫자밖에 모르기 때문에 모든 데이터는 숫자로 저장이 됩니다. 실제로는 '문자의 유니코드' 가 저장이 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1648469340250&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;char ch = 'A' // 실제는 A의 유니코드 65가 저장
char ch = '' //빈 문자열 저장 X&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;char 타입의 크기는 2byte(16bit)로 16자리의 2진수로 표현할 수 있는 정수의 개수(65536)를 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;컴퓨터는 숫자밖에 모르기때문에 유니코드라는 표준을 지정하게 되었다!&lt;br /&gt;* 유니코드? 전 세계의 모든 문자를 컴퓨터에서 일관되게 표현하고 다룰 수 있도록 설계된 산업 표준&lt;br /&gt;&lt;br /&gt;'A' - &amp;gt; 65&amp;nbsp; =&amp;gt; 인코딩(encoding)&lt;br /&gt;65 - &amp;gt; 'A'&amp;nbsp; =&amp;gt; 디코딩(decoding)&lt;br /&gt;&lt;br /&gt;유니코드는 먼저 유니코드에 포함시키고자 하는 문자들의 집합을 정의하였는데 이것을 '유니코드 문자 셋' 이라고 한다.&lt;br /&gt;그리고 이 문자 셋에 번호를 붙인 것이 '유니코드 인코딩' 이며 흔히 들어본 UTF-8, UTF-16, UTF-32 등이 있다.&lt;br /&gt;자바에서는 UTF-16 을 사용하며 모든 문자를 2byte의 고정크기로 표현한다.&lt;br /&gt;&lt;br /&gt;UTF-8은 1~4byte 가변 크기로 요즘 해당 인코딩으로 작성된 웹 문서가 많은데 영문,숫자는 1byte로 UTF-16을 사용하면 크기가 커져 용량이 커지는 단점이 있다. 따라서 전송속도가 중요한 인터넷에서 UTF-8을 많이 사용하고 있다.&lt;/blockquote&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;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;정수형 (byte, short, int, long)&lt;/b&gt;&lt;/h2&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개의 자료형이 있으며 각 자료형이 저장할 수 있는 값의 범위가 다르다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;byte : 1byte&lt;/li&gt;
&lt;li&gt;short : 2byte&lt;/li&gt;
&lt;li&gt;&lt;b&gt;int : 4byte - 기본 자료형(default date type)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;long : 8byte&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;우선 int 가 기본자료형이다. 왜그럴까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이유는 cpu가 가장 효율적으로 다룰 수 있는 정수형 인것도 있지만 JVM의 피연산자 스택이 피연산자를 4byte단위로 저장을 하기 때문에 이보다 작으면 변환연산을 수행하게 된다. 그래서 int를 사용하는게 효율적이다.&amp;nbsp; (int 범위 넘어가면 long 사용)&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;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정수형의 표현형식과 범위&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 어떤 진법의 리터럴을 변수에 저장해도 실제로는 2진수로 바뀌어 저장이 된다. 2진수로 저장되는 형식은 크게 정수형과 실수형이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 63.1395%; height: 37px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.5116%; text-align: center;&quot;&gt;&lt;b&gt;S&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 88.4884%; text-align: center;&quot;&gt;&lt;b&gt;n - 1 bit&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;S(sign bit) : 부호 비트(양수는 0, 음수는 1)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;n : 타입의 크기 (단위: bit)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 정수형은 부호있는 정수 이므로 왼쪽 첫번째에 부호비트를 사용하고 나머지는 값을 표현을 합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;n비트로 표현할 수 있는 정수의 개수: 2^n개 ( 2^n-1 + 2^n-1개)&lt;/b&gt;&lt;br /&gt;&lt;b&gt;n비트로 표현할 수 있는 부호있는 정수의 범위: -2^n ~ 2^n - 1&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) int =&amp;gt; 4byte =&amp;gt; 32bit =&amp;gt; -2^31 ~ 2^31 - 1 // (-1은 범위에 0이 포함되었기 때문에, 0~15 = &amp;gt; 16개)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;만약의 타입이 표현할 수 있는 범위를 넘어서면 어떻게 될까? 오버플로우&lt;/b&gt;가 일어나게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동차 km 표시기를 생각하면 쉬울 것 같습니다. 간단하게 '0000 ~ 9999' 4자리리를 표시할 수 있는 계기판이 있는데 '9999' 에서 1을 더하면 원래는 '10000'이 되어야하지만 5자리를 표시를 할 수 없어 앞에 1이 버려져 '0000'이 됩니다. 그럼 '0000'에서 -1을 빼면 어떻게 될까요? 0에서 1을 뺄 수 없어 앞에 저장되지 않은 1이 있다 생각하고 계산을 하여 네자리로 표현할 수 있는 최대값 '9999'가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;최대값 + 1 ---&amp;gt; 최소값&lt;/b&gt;&lt;br /&gt;&lt;b&gt;최소값 - 1 ---&amp;gt; 최대값&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;실수형 (float, double)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실수형은 실수를 저장하기 위한 타입으로 2가지가 있습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 56px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 17.093%; height: 20px; text-align: center;&quot;&gt;타입&lt;/td&gt;
&lt;td style=&quot;width: 51.0465%; height: 20px; text-align: center;&quot;&gt;저장 가능한 값의 범위(양수)&lt;/td&gt;
&lt;td style=&quot;width: 15.2326%; height: 20px; text-align: center;&quot;&gt;정밀도&lt;/td&gt;
&lt;td style=&quot;width: 16.6279%; height: 20px; text-align: center;&quot;&gt;크기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 17.093%; height: 18px; text-align: center;&quot;&gt;float&lt;/td&gt;
&lt;td style=&quot;width: 51.0465%; height: 18px; text-align: center;&quot;&gt;1.4 x 10^-45 ~ 3.4 x 10^38&lt;/td&gt;
&lt;td style=&quot;width: 15.2326%; height: 18px; text-align: center;&quot;&gt;7자리&lt;/td&gt;
&lt;td style=&quot;width: 16.6279%; height: 18px; text-align: center;&quot;&gt;4byte(32bit)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 17.093%; height: 18px; text-align: center;&quot;&gt;double&lt;/td&gt;
&lt;td style=&quot;width: 51.0465%; height: 18px; text-align: center;&quot;&gt;4.9 x 10^-324 ~ 1.8 x 10^308&lt;/td&gt;
&lt;td style=&quot;width: 15.2326%; height: 18px; text-align: center;&quot;&gt;15자리&lt;/td&gt;
&lt;td style=&quot;width: 16.6279%; height: 18px; text-align: center;&quot;&gt;8byte(64bit)&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;b&gt;얼마나 큰 값을 표현할 수 있는가'&lt;/b&gt; 뿐만아니라 '&lt;b&gt;얼마나 0에 가깝게 표현할 수 있는가&lt;/b&gt;' 도 중요합니다. 표에 '정밀도' 라는게 써져있는데 정밀도는 10진수를 오차없이 저장가능한 자리수를 나타냅니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어 '&lt;b&gt;123456789012345678901234&lt;/b&gt;' 라는 수가 있는데 float 형태는 &lt;b&gt;9.123456&lt;/b&gt;95495605500000 이라는 형태 &lt;span&gt;소수점 6자리 이후부터&lt;/span&gt;로 오차가 발생하고 dobule형은 &lt;b&gt;9.12345678901234&lt;/b&gt;600000 으로 소수점 14자리까지 오차없이 저장이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그래서 더 많은 값의 범위나 높은 정확도를 요구하면 'double' 형을 사용&lt;/b&gt;해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실수형은 정수형과 달리 표현범위를 벗어나게 되면 '오버플로우'가 발생을 하지만 최소값으로 돌아가는게 아닌 무한대로 나타나게 됩니다. 그리고 정수형에는 없는 '언더플로우' 가 있는데 실수형으로 표현할 수 없는 아주 작은 값으로, 최소값보다 작은 값이 되는 경우를 말합니다. 이때 변수의 값은 0 이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&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>자바 (ref. 자바의정석)</category>
      <category>기본형</category>
      <category>자바</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/83</guid>
      <comments>https://dding9code.tistory.com/83#entry83comment</comments>
      <pubDate>Mon, 28 Mar 2022 21:54:41 +0900</pubDate>
    </item>
    <item>
      <title>스프링(Spring)은 왜 사용할까?</title>
      <link>https://dding9code.tistory.com/82</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링이라는 기술을 배우고, 사용하는데 왜 사용하는지도 모르고 쓰는거 같아서 이렇게 정리를 하게되었습니다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;스프링이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 스프링은 왜 만들어 졌을까요? 스프링이라는 기술의 핵심 컨셉은 무엇인지 생각해보신 적이 있으신가요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스프링은 자바언어 기반의 프레임워크&lt;/b&gt;입니다. 자바언어 기반이니 자바의 가장 큰 특징은 무엇일까요. 바로 객체지향언어 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 객체지향언어가 가진 특성(추상화, 상속, 캡슐화, 다형성)을 살려내는 프레임워크 라고 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉. &lt;b&gt;스프링은 좋은 객체지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 왜 사용하는지도 답이 자연스럽게 나오게 됩니다. 스프링이 지원하는 기술 DI(Dependency Injection), DI 컨테이너 제공을 통하여 다형성과 OCP(Open Closed Principle), DIP(Dependency inversion principle) 를 가능하게 지원을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 클라이언트의 코드 변경없이 기능을 확장이 가능하고, 프로그램을 마치 부품 교체하듯이 개발이 가능하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론은 좋은 객체 지향 개발을 하려고 OCP, DIP 원칙을 지키면서 개발을 하려고 보니 할일이 많아 결국 프레임워크로 만들어 지게 된게 스프링이라, 스프링을 사용하면 좋은 객체 지향 개발을 할 수 있게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;다형성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 객체지향프로그래밍의 핵심인 &lt;b&gt;다형성&lt;/b&gt;에 대해서 간단히 정리를 간단하게 하겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다형성은 하나의 객체가 여러타입을 가질 수 있다. 라고 말할 수 있지만 여기서는 실세계에 비유하여 &lt;b&gt;역할&lt;/b&gt; 과 &lt;b&gt;구현&amp;nbsp;&lt;/b&gt;으로 나누어 그림을 통해 설명을 드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-03-25 오후 10.46.14.png&quot; data-origin-width=&quot;1888&quot; data-origin-height=&quot;936&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/URp50/btrxkMhVbXr/6wYFgLphx0ga0j2mp7QNv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/URp50/btrxkMhVbXr/6wYFgLphx0ga0j2mp7QNv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/URp50/btrxkMhVbXr/6wYFgLphx0ga0j2mp7QNv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FURp50%2FbtrxkMhVbXr%2F6wYFgLphx0ga0j2mp7QNv1%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;582&quot; height=&quot;288&quot; data-filename=&quot;스크린샷 2022-03-25 오후 10.46.14.png&quot; data-origin-width=&quot;1888&quot; data-origin-height=&quot;936&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;운전자 역할(클라이언트) 와 자동차 역할(인터페이스) 가 있습니다. 실세계에서 운전자는 운전방법만 안다면 차량이 K3, 아반떼, 테슬라와 관계없이 모두 운전이 가능합니다. 심지어 새로운 차량이 출시가 되어도 해당 차량을 운전할 수 있습니다. 이게 바로 다형성입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트는 대상의 역할만 알면 됩니다. 구현 대상의 내부 구조를 몰라도 되고, 그 구조가 변경되어도 영향을 받지 않습니다. 심지어 대상 자체를 변경해도 영향을 받지 않습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;역할과 구현을 철저하게 분리하자!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다형성의 본질&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경할 수 있습니다.&lt;/li&gt;
&lt;li&gt;클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;한계&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&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;p data-ke-size=&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>스프링</category>
      <category>다형성</category>
      <category>스프링</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/82</guid>
      <comments>https://dding9code.tistory.com/82#entry82comment</comments>
      <pubDate>Fri, 25 Mar 2022 22:56:48 +0900</pubDate>
    </item>
    <item>
      <title>다익스트라 알고리즘(Dijkstra Algorithm) - JAVA</title>
      <link>https://dding9code.tistory.com/81</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;다익스트라 알고리즘 이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프에서 여러 개의 노드가 있을 때, 특정한 한 정점(=노드)에서 출발하여 다른 모든 정점으로 가는 최단 경로를 구하는 알고리즘입니다. 다익스트라 최단 경로 알고리즘은 '음의 간선' 즉, 가중치가 0보다 작은 값이 아닌 경우에 때 정상 동작합니다. 현실 세계에서의 길(간선) 음의 간선으로 표현되지 않아 다익스트라 알고리즘은 실제로 인공위성 GPS 소프트웨어 등에서 가장 많이 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다익스트라 최단 경로 알고리즘은 기본적으로 그리디 알고리즘으로 분류됩니다. 왜냐하면 매번 '가장 비용이 적은 노드'를 선택해서 임의의 과정을 반복합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;동작과정&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;&amp;nbsp;출발 노드를 설정&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;nbsp;최단 거리 테이블 초기화&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;nbsp;방문하지 않은 노드 중에서 최단 거리(가중치)가 가장 짧은 노드 선택&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;nbsp;해당 노드를 거쳐 다른 노드로 가는 비용을 계산하여 최단 거리 테이블 갱신&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;nbsp;위 과정에서 3, 4번 반복&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최단 경로를 구하는 과정에서 각 노드에 대한 현재까지의 최단 거리 정보를 항상 1차원의 리스트에 저장하며 리스트를 계속 갱신하는 특징이 있다.&amp;nbsp; 매번 현재 처리하고 있는 노드를 기준으로 주변 간선을 확인하고, 나중에 현재 처리하고 있는 노드와 인접한 노드로 도달하는 더 짧은 경로를 찾으면 갱신을 합니다. 쉽게 구현하면 매번 최단 거리 테이블을 선형적으로(모든 원소를 앞에서부터) 탐색을 하는 방법이 있지만, 최단 거리가 가장 짧은 노드를 찾기 위해 우선순위 큐 사용하면 단순 탐색보다 시간 복잡도를 줄일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;선형 탐색)&lt;/b&gt; 시간 복잡도 O(V&amp;sup2;) 에서&amp;nbsp; &amp;nbsp;-&amp;gt; &lt;b&gt;우선순위 큐)&lt;/b&gt; 시간 복잡도 O(ElogV) 로 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1753&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/1753&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1648002720811&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;1753번: 최단경로&quot; data-og-description=&quot;첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1 &amp;le; V &amp;le; 20,000, 1 &amp;le; E &amp;le; 300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘째 줄에는 시작 정점의 번호 K(1 &amp;le; K &amp;le; V)가 &quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/1753&quot; data-og-url=&quot;https://www.acmicpc.net/problem/1753&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/BN7p3/hyNNurshP1/9xPpKNzkJ9BtJwBe7qVgR1/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1753&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/1753&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/BN7p3/hyNNurshP1/9xPpKNzkJ9BtJwBe7qVgR1/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;1753번: 최단경로&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1 &amp;le; V &amp;le; 20,000, 1 &amp;le; E &amp;le; 300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘째 줄에는 시작 정점의 번호 K(1 &amp;le; K &amp;le; V)가&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준 1753 최단경로 문제인데 다익스트라를 구현하는 기초 문제입니다. 위에서 배운 내용을 토대로 코드를 구현해보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-03-23 오후 12.12.03.png&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dYoSCp/btrw2NHSZ0C/pzaYpT42H8pI3VRydHuet0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dYoSCp/btrw2NHSZ0C/pzaYpT42H8pI3VRydHuet0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dYoSCp/btrw2NHSZ0C/pzaYpT42H8pI3VRydHuet0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdYoSCp%2Fbtrw2NHSZ0C%2FpzaYpT42H8pI3VRydHuet0%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;465&quot; height=&quot;425&quot; data-filename=&quot;스크린샷 2022-03-23 오후 12.12.03.png&quot; data-origin-width=&quot;465&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 주어진 테스트 케이스의 그래프의 형태입니다. 단계별로 풀어내 보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.&lt;/b&gt; 먼저 출발 지점의 노드가 1로 주어져 우선순위 큐에 넣습니다. 출발 노드에서 출발 노드로의 거리는 0이니 0으로 초기화가 됐습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 51px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;노드 번호&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4419%; height: 20px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 18.3721%; height: 20px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 18.4883%; height: 20px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 18.2557%; height: 20px;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 18.7211%;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 13px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 13px; text-align: center;&quot;&gt;&lt;b&gt;가중치&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4419%; height: 13px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 18.3721%; height: 13px;&quot;&gt;MAXVALUE(=무한)&lt;/td&gt;
&lt;td style=&quot;width: 18.4883%; height: 13px;&quot;&gt;MAXVALUE(=무한)&lt;/td&gt;
&lt;td style=&quot;width: 18.2557%; height: 13px;&quot;&gt;MAXVALUE(=무한)&lt;/td&gt;
&lt;td style=&quot;width: 18.7211%;&quot;&gt;MAXVALUE(=무한)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 18px; width: 13.7209%;&quot;&gt;&lt;b&gt;우선순위 큐&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 18px; width: 86.2791%;&quot; colspan=&quot;5&quot;&gt;(거리: 0, 노드 1)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.&lt;/b&gt; 우선순위 큐를 사용하기 때문에 거리가 가장 짧은 노드를 선택하기 위해서는 단순히 큐에서 노드를 꺼내면 됩니다. 해당 노드를 이미 처리한 적이 있으면 무시하고 처리하지 않은 노드에 대해서만 처리하면 됩니다. 1번까지 가는 최단거리가 0이므로, 1번 노드를 거쳐 연결된 2번 3번까지 가는 최소 비용을 계산합니다. =&amp;gt; 2(0+2) , 3(0+3)&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;size14&quot;&gt;꺼낸 원소: (거리 0, 노드 1)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 51px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 20px;&quot;&gt;&lt;b&gt;노드 번호&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4419%; height: 20px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 18.3721%; height: 20px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 18.4883%; height: 20px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 18.2557%; height: 20px;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 18.7211%;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 13px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 13px;&quot;&gt;&lt;b&gt;가중치&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4419%; height: 13px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 18.3721%; height: 13px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 18.4883%; height: 13px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 18.2557%; height: 13px;&quot;&gt;MAXVALUE(=무한)&lt;/td&gt;
&lt;td style=&quot;width: 18.7211%;&quot;&gt;MAXVALUE(=무한)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 18px;&quot;&gt;&lt;b&gt;우선순위 큐&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 86.2791%; height: 18px;&quot; colspan=&quot;5&quot;&gt;(거리: 2, 노드 2), (거리: 3, 노드 3)&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;b&gt;3.&lt;/b&gt; 이어서 다시 우선순위 큐에서 원소를 꺼내서 동일한 과정을 반복합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;꺼낸 원소: (거리 2, 노드 2)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 51px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 20px;&quot;&gt;&lt;b&gt;노드 번호&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4419%; height: 20px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 18.3721%; height: 20px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 18.4883%; height: 20px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 18.2557%; height: 20px;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 18.7211%;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 13px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 13px;&quot;&gt;&lt;b&gt;가중치&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4419%; height: 13px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 18.3721%; height: 13px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 18.4883%; height: 13px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 18.2557%; height: 13px;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;width: 18.7211%;&quot;&gt;MAXVALUE(=무한)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 18px;&quot;&gt;&lt;b&gt;우선순위 큐&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 86.2791%; height: 18px;&quot; colspan=&quot;5&quot;&gt;(거리: 3, 노드 3) , (거리: 7, 노드 4)&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;b&gt;4.&lt;/b&gt; 3번 노드에서 4번 노드로 가는 가중치가 6이라&amp;nbsp; ( 3+6 &amp;gt; 7) 이 되어 4번으로 가는 최단 경로는 갱신이 되지 않고 넘어가게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;꺼낸 원소: (거리 3, 노드 3)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 51px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 20px;&quot;&gt;&lt;b&gt;노드 번호&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4419%; height: 20px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 18.3721%; height: 20px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 18.4883%; height: 20px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 18.2557%; height: 20px;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 18.7211%;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 13px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 13px;&quot;&gt;&lt;b&gt;가중치&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4419%; height: 13px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 18.3721%; height: 13px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 18.4883%; height: 13px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 18.2557%; height: 13px;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;width: 18.7211%;&quot;&gt;MAXVALUE(=무한)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 18px;&quot;&gt;&lt;b&gt;우선순위 큐&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 86.2791%; height: 18px;&quot; colspan=&quot;5&quot;&gt;(거리: 7, 노드 4)&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;b&gt;5.&lt;/b&gt; 해당 노드에서 5번 노드로 가는 길은 없어 큐가 비게 되어 종료가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꺼낸 원소: (거리 7, 노드 4)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 51px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 20px;&quot;&gt;&lt;b&gt;노드 번호&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4419%; height: 20px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 18.3721%; height: 20px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 18.4883%; height: 20px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 18.2557%; height: 20px;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 18.7211%;&quot;&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 13px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 13px;&quot;&gt;&lt;b&gt;가중치&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.4419%; height: 13px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 18.3721%; height: 13px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 18.4883%; height: 13px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 18.2557%; height: 13px;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;width: 18.7211%;&quot;&gt;MAXVALUE(=무한)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 13.7209%; height: 18px;&quot;&gt;&lt;b&gt;우선순위 큐&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 86.2791%; height: 18px;&quot; colspan=&quot;5&quot;&gt;&amp;nbsp;&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;pre id=&quot;code_1648002785389&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;
import java.io.*;

public class Main {

    static class Node{
        int v; //간선
        int cost; //가중치

        public Node(int v, int cost) {
            this.v = v;
            this.cost = cost;
        }
    }

    //각 노드에 연결되어 있는 노드에 대한 정보를 담는 리스트
    static ArrayList&amp;lt;Node&amp;gt;[] graph;
    //방문한 적이 있는지 체크하는 목적의 리스트
    static boolean[] visit;
    //최단 거리 테이블
    static int[] dist;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int v = Integer.parseInt(st.nextToken());
        int e = Integer.parseInt(st.nextToken());
        int k = Integer.parseInt(br.readLine());

        graph = new ArrayList[v + 1];
        dist = new int[v + 1];
        visit = new boolean[v + 1];

        for (int i = 1; i &amp;lt;= v; i++) {
            graph[i] = new ArrayList&amp;lt;&amp;gt;();
            dist[i] = Integer.MAX_VALUE; //최대값으로 초기화, 최단거리를 찾기 위함.
        }

        for (int i = 0; i &amp;lt; e; i++) {
            // u -&amp;gt; v 로 가는 가중치 w가 주어진다.
            st = new StringTokenizer(br.readLine());
            int inputU = Integer.parseInt(st.nextToken());
            int inputV = Integer.parseInt(st.nextToken());
            int inputW = Integer.parseInt(st.nextToken());

            graph[inputU].add(new Node(inputV, inputW));
        }

        //다익스트라 알고리즘 수행
        dijkstra(k);

        for (int i = 1; i &amp;lt;= v; i++) {
            System.out.println(dist[i] == Integer.MAX_VALUE ? &quot;INF&quot; : dist[i]);
        }
    }

    static void dijkstra(int start) {
        //우선 순위 큐 사용, 가중치를 기준으로 오름차순한다.
        PriorityQueue&amp;lt;Node&amp;gt; q = new PriorityQueue&amp;lt;&amp;gt;((o1, o2) -&amp;gt; o1.cost - o2.cost);
        //시작 노드에 대해서 초기화
        q.add(new Node(start, 0));
        dist[start] = 0;

        while (!q.isEmpty()) {
            //현재 최단 거리가 가장 짧은 노드를 꺼내서 방문 처리 한다.
            Node now = q.poll();

            if (!visit[now.v]) {
                visit[now.v] = true;
            }

            for (Node next : graph[now.v]) {

                //방문하지 않았고, 현재 노드를 거쳐서 다른 노드로 이동하는 거리가 더 짧을 경우
                if (!visit[next.v] &amp;amp;&amp;amp; dist[next.v] &amp;gt; now.cost + next.cost) {
                    dist[next.v] = now.cost + next.cost;
                    q.add(new Node(next.v, dist[next.v]));
                }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;[참고]&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;나동빈 - 이코테&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘 정리</category>
      <category>Java</category>
      <category>다익스트라</category>
      <category>백준 1753</category>
      <category>알고리즘</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/81</guid>
      <comments>https://dding9code.tistory.com/81#entry81comment</comments>
      <pubDate>Wed, 23 Mar 2022 12:13:27 +0900</pubDate>
    </item>
    <item>
      <title>@Bean 과 @Component 의 차이?</title>
      <link>https://dding9code.tistory.com/80</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 영한님 강의중..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@Bean &lt;/b&gt;은 해당 어노테이션이 붙은 &lt;b&gt;메서드&lt;/b&gt;를 모두 호출해서 반환된 객체를 스프링 컨테이너를 등록하고, 이렇게 등록된 객체를 스프링 빈이라 하며, 싱글톤으로 관리가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@Component&lt;/b&gt; 는 @ComponentScan 이 @Component 가 붙은 모든 &lt;b&gt;클래스&lt;/b&gt;를 스프링 빈으로 등록하게 되는데, 이때 스프링 빈의 기본 이름은 클래스명을 사용하되 맨 앞글자만 소문자를 사용하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 보면 둘다 스프링 빈으로 등록하게 되는건 알겠는데 무슨 차이가 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Bean&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Bean 어노테이션은 &lt;b&gt;개발자가 컨트롤이 불가능한 외부 라이브러리들&lt;/b&gt;을 &lt;b&gt;Bean으로 직접 등록&lt;/b&gt;하고 싶은 경우에 사용 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-03-22 오후 1.39.57.png&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;535&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kZYwR/btrwTxd0fI5/R52BFuVDdR67MWm3Ic1YMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kZYwR/btrwTxd0fI5/R52BFuVDdR67MWm3Ic1YMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kZYwR/btrwTxd0fI5/R52BFuVDdR67MWm3Ic1YMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkZYwR%2FbtrwTxd0fI5%2FR52BFuVDdR67MWm3Ic1YMk%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;573&quot; height=&quot;535&quot; data-filename=&quot;스크린샷 2022-03-22 오후 1.39.57.png&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;535&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AppConifg 라고 직접만든 설정 정보 클래스인데 이 클래스는 @Configuration 어노테이션을 사용하였습니다. 그래서 해당 클래스는 설정(구성) 정보로 사용되는데, 이렇게 외부 라이브러리에 @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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-03-22 오후 1.45.04.png&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;261&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9Ir9B/btrwMHIC90X/Z0Q15qdSjGQQFKKAetcpH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9Ir9B/btrwMHIC90X/Z0Q15qdSjGQQFKKAetcpH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9Ir9B/btrwMHIC90X/Z0Q15qdSjGQQFKKAetcpH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9Ir9B%2FbtrwMHIC90X%2FZ0Q15qdSjGQQFKKAetcpH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;657&quot; height=&quot;261&quot; data-filename=&quot;스크린샷 2022-03-22 오후 1.45.04.png&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;261&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;실제 @Bean 내부로 들어가서 코드를 보면 @Target이 METHOD로 지정이 되어있다. 즉 메서드 위에서만 선언이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Component&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 &lt;b&gt;개발자가 직접 컨트롤이 가능한 클래스들&lt;/b&gt;의 경우에는 &lt;b&gt;@Component&lt;/b&gt;를 사용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링에서 많이 사용하는 @Repository, @Controller, @Service 은 @Component의 구체화된 형태로 내부에 @Component가 있어 컴포넌트 스캔의 대상이 되어 자동으로 스프링 빈에 등록하게 된다.&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;스크린샷 2022-03-22 오후 1.49.24.png&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9F2HB/btrwKFYPH9R/UPuEpv5PVrhb0lktaJlQ60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9F2HB/btrwKFYPH9R/UPuEpv5PVrhb0lktaJlQ60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9F2HB/btrwKFYPH9R/UPuEpv5PVrhb0lktaJlQ60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9F2HB%2FbtrwKFYPH9R%2FUPuEpv5PVrhb0lktaJlQ60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;669&quot; height=&quot;277&quot; data-filename=&quot;스크린샷 2022-03-22 오후 1.49.24.png&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Component도 내부를 보면 @Target이 TYPE으로 지정되어 클래스 위에서만 선언이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;참고 - &lt;a href=&quot;https://jojoldu.tistory.com/27?category=635883&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;향로님 블로그&lt;/a&gt;&lt;/p&gt;</description>
      <category>스프링</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/80</guid>
      <comments>https://dding9code.tistory.com/80#entry80comment</comments>
      <pubDate>Tue, 22 Mar 2022 13:52:12 +0900</pubDate>
    </item>
    <item>
      <title>MySQL - View</title>
      <link>https://dding9code.tistory.com/79</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;View&amp;nbsp; 란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뷰는 데이터베이스에 존재하는 가상의 테이블을 뜻합니다. 실제 테이블 처럼 행과 열을 가지고 있지만 실제로는 데이터를 저장하지 않습니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;뷰 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 뷰의 이름을 명시하고 , AS 키워드 다음에 SELECT 문을 사용하여 해당 뷰가 접근할 수 있는 필드를 명시&lt;/p&gt;
&lt;pre id=&quot;code_1647857548273&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE VIEW 뷰이름 AS

SELECT 필드이름1, 필드이름2, ...
FROM 테이블이름
WHERE 조건

...&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;&lt;b&gt;뷰 대체&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- OR REPLACE 절을 추가하여 기존에 존재하는 뷰를 새로운 뷰로 대체 가능, 만약 뷰가 없으면 생성과 동일한 기능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1647857833616&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE OR REPLACE VIEW 뷰이름 AS

SELECT 필드이름1, 필드이름2, ...
FROM 테이블이름
WHERE 조건
...&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;&lt;b&gt;뷰 삭제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DROP 문을 사용하여 뷰 삭제가 가능&lt;/p&gt;
&lt;pre id=&quot;code_1647857887958&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DROP VIEW 뷰이름&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;&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;&lt;b&gt;뷰의 장단점!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;- 보안 : 테이블 구조 및 내용 숨기기&lt;/li&gt;
&lt;li&gt;- 편의 : 복잡한 쿼리 사전 구현 , 재사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;- 한 번 정의된 뷰는 변경이 불가.&lt;/li&gt;
&lt;li&gt;- 삽입, 삭제, 갱신 작업에 많은 제한 사항이 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;집계함수 사용하지 않음(MAX, MIN, AVG ...)&lt;/li&gt;
&lt;li&gt;GROUP BY, UNION, DISTINCT 사용 X&lt;/li&gt;
&lt;li&gt;SELECT 절에 서브쿼리 없음&lt;/li&gt;
&lt;li&gt;WHERE 절의 서브쿼리가 FROM 절의 데이블 참조 X&lt;/li&gt;
&lt;li&gt;조인은 INNER만 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&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;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>MySQL</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/79</guid>
      <comments>https://dding9code.tistory.com/79#entry79comment</comments>
      <pubDate>Mon, 21 Mar 2022 19:18:27 +0900</pubDate>
    </item>
    <item>
      <title>MySQL - 기본키(Primary Key) , 외래키 (Foreign Key)</title>
      <link>https://dding9code.tistory.com/78</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;[업데이트 예정입니다..! 가볍게만 참고하세요.]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;기본키 - Primary Key&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;테이블의 각 row 를 &lt;u&gt;유일성&lt;/u&gt;과 &lt;u&gt;최소성&lt;/u&gt;을 만족시키면서 식별할 수 있는 &lt;u&gt;후보키 중에 선택한 Main key&amp;nbsp;&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Candidate Key(후보키)중에 선택한 Main Key&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;*&lt;u&gt;유일성&lt;/u&gt;과 *&lt;u&gt;최소성&lt;/u&gt;을 만족&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중복되지 않는 고유값만 허용&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;NULL&lt;span&gt;&amp;nbsp;&lt;/span&gt;값 허용하지 않음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;테이블당&lt;span&gt;&amp;nbsp;&lt;/span&gt;하나의 기본키만&lt;span&gt;&amp;nbsp;&lt;/span&gt;지정 가능&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;*Candidate Key ?&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 관계형 데이터베이스에서 *&lt;b&gt;릴레이션&lt;/b&gt;(Relation)의 튜플을 유일하게 식별할 수 있는 속성 또는 속성의 집합 중, 다음 두 성질을 만족해야 함&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;유일성(uniqueness)&lt;/b&gt; : 릴레이션에 있는 모든 튜플에 대해 유일하게 식별되어야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최소성(minimality)&lt;/b&gt; : 유일성을 가진 키를 구성하는 속성(Attribute) 중 하나라도 제외하는 경우 유일성이 깨지는 것을 의미한다. 즉, 릴레이션의 모든 튜플을 유일하게 식별하는 데 꼭 필요한 속성들로만 구성되어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&lt;b&gt;릴레이션&lt;/b&gt; : 테이블이라고 이해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&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;size18&quot;&gt;&lt;u&gt;&lt;b&gt;1. CREATE 문으로 생성&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647855139202&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. CREATE TABLE 테이블이름

(
    필드이름 필드타입 PRIMARY KEY,

    ...
)

2. CREATE TABLE 테이블이름

(

    필드이름 필드타입,

    ...

    [CONSTRAINT 제약조건이름] PRIMARY KEY (필드이름)

)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1653014518126&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 기본키 넣는 방법 1
CREATE TABLE people (
  ID INT PRIMARY KEY,
  className VARCHAR(5),
  Name VARCHAR(10)
);

-- 기본키 넣는 방법 2
CREATE TABLE people (
  ID INT,
  className VARCHAR(5),
  Name VARCHAR(10)
  PRIMARY KEY (ID)
);&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;u&gt;&lt;b&gt;2. ALTER 문으로 PRIMARY KEY 수정&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추가 - &lt;/b&gt;테이블에 새로운 필드를 추가할 때 해당 필드를 기본 키로 설정하는 방법&lt;/p&gt;
&lt;pre id=&quot;code_1647855564419&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ALTER TABLE 테이블이름
ADD 필드이름 필드타입 PRIMARY KEY

ALTER TABLE 테이블이름
ADD [CONSTRAINT 제약조건이름] PRIMARY KEY (필드이름)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;변경 -&amp;nbsp;&lt;/b&gt;기존에 존재하는 필드를 기본 키로 설정하는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1647855698251&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ALTER TABLE 테이블이름
MODIFY COLUMN 필드이름 필드타입 PRIMARY KEY

ALTER TABLE 테이블이름
MODIFY COLUMN [CONSTRAINT 제약조건이름] PRIMARY KEY (필드이름)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;삭제 - &lt;/b&gt;해당 테이블&amp;nbsp;Primary key 제약 조건을 삭제&lt;/p&gt;
&lt;pre id=&quot;code_1647855754615&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ALTER TABLE 테이블이름
DROP PRIMARY KEY&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;* Unique 제약 조건&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 해당 필드는 서로 다른 값을 가져야 한다. (중복 저장 x)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- NULL 값 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1647856032551&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. CREATE TABLE 테이블이름

(
    필드명 필드타입 UNIQUE,

    ...
)

2. CREATE TABLE 테이블이름

(
    필드이름 필드타입,

    ...,

    [CONSTRAINT 제약조건이름] UNIQUE (필드이름)
)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1647855935654&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE people (
  ID INT PRIMARY KEY,
  className VARCHAR(5),
  Name VARCHAR(10)
  UNIQUE (ID)
);&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;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;b&gt;외래키 - Foreign Key&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt;&lt;b&gt;다른 테이블의 Primary Key 와 연결되는(참조되는) 테이블의 column 을 의미&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;한 테이블을 다른 테이블과 연결해주는 역할&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;하나의 테이블을 다른 테이블에 의존하게 만듬&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;외래키 제약 조건을 설정할 때 참조되는 테이블은 UNIQUE나 PRIMARY KEY 제약 조건 설정 필수&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;외래 키 추가&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647856216988&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ALTER TABLE _자식테이블이름
  ADD CONSTRAINT _제약조건이름
  FOREIGN KEY ( _자식테이블외래키 )
  REFERENCES 부모테이블명 ( _부모테이블기본키 )
  -- ON DELETE _삭제시제약 
  -- ON UPDATE _수정시제약&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;외래 키 삭제&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1647856452930&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ALTER TABLE _자식테이블명 DROP FOREIGN KEY _자식테이블외래키&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 외래키는 NULL값이거나 또는 부모 테이블의 기본 키 값과 같아야 합니다. 그렇지 않으면 에러가 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;외래 키 제약 - ON UPDATE, ON DELETE&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;FOREIGN KEY 제약 조건에 의해 참조되는 테이블의 데이터의 수정이나 삭제가 발생하면, 참조하고 있는 테이블의 데이터도 같이 영향을 받습니다. 이때 참조하고 있는 테이블의 동작은 다음 키워드를 사용하여 제약 조건에서 미리 설정을 할&amp;nbsp; 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 92px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 23.5658%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;제약&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.4264%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.0077%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;비고&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.5658%; height: 18px;&quot;&gt;&lt;b&gt;NO ACTION&lt;span style=&quot;background-color: #ffffff; color: #24292e;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;RESTRICT&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.4264%; height: 18px;&quot;&gt;자식 테이블에 해당 외래키가 있을 때 수정/삭제 되지 않음&lt;/td&gt;
&lt;td style=&quot;width: 31.0077%; height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.5658%; height: 18px;&quot;&gt;&lt;b&gt;CASCADE&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.4264%; height: 18px;&quot;&gt;자식 테이블의 해당 행도 수정/삭제&lt;/td&gt;
&lt;td style=&quot;width: 31.0077%; height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.5658%; height: 18px;&quot;&gt;&lt;b&gt;SET NULL&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.4264%; height: 18px;&quot;&gt;자식 테이블의 외래키를 NULL로&lt;/td&gt;
&lt;td style=&quot;width: 31.0077%; height: 18px;&quot;&gt;자식 외래키가 NOT NULL일 시 설정 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.5658%; height: 18px;&quot;&gt;&lt;b&gt;SET DEFAULT&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.4264%; height: 18px;&quot;&gt;자식 테이블의 외래키를 기본값으로&lt;/td&gt;
&lt;td style=&quot;width: 31.0077%; height: 18px;&quot;&gt;InnoDB 엔진에서 사용 불가&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://prinha.tistory.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://prinha.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EC%96%84%EC%BD%94-%EB%A7%88%EC%9D%B4%EC%97%90%EC%8A%A4%ED%81%90%EC%97%98/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;얄코 강의&lt;/a&gt;&lt;/p&gt;</description>
      <category>MySQL</category>
      <category>mysql</category>
      <category>기본키</category>
      <category>외래키</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/78</guid>
      <comments>https://dding9code.tistory.com/78#entry78comment</comments>
      <pubDate>Mon, 21 Mar 2022 19:01:20 +0900</pubDate>
    </item>
    <item>
      <title>[백준14938] - 서강그라운드</title>
      <link>https://dding9code.tistory.com/77</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14938&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ㄷhttps://www.acmicpc.net/problem/14938&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1647615027608&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;14938번: 서강그라운드&quot; data-og-description=&quot;예은이는 요즘 가장 인기가 있는 게임 서강그라운드를 즐기고 있다. 서강그라운드는 여러 지역중 하나의 지역에 낙하산을 타고 낙하하여, 그 지역에 떨어져 있는 아이템들을 이용해 서바이벌을&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/14938&quot; data-og-url=&quot;https://www.acmicpc.net/problem/14938&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bJhRva/hyNJ5kEHRu/BsaKxWJ7FD4VMTsUz4z0ck/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14938&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/14938&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bJhRva/hyNJ5kEHRu/BsaKxWJ7FD4VMTsUz4z0ck/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;14938번: 서강그라운드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;예은이는 요즘 가장 인기가 있는 게임 서강그라운드를 즐기고 있다. 서강그라운드는 여러 지역중 하나의 지역에 낙하산을 타고 낙하하여, 그 지역에 떨어져 있는 아이템들을 이용해 서바이벌을&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-03-18 오후 11.50.43.png&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;1188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dY8ptl/btrwmsFruWx/mSi8J83OhUM79UNvpcnyH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dY8ptl/btrwmsFruWx/mSi8J83OhUM79UNvpcnyH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dY8ptl/btrwmsFruWx/mSi8J83OhUM79UNvpcnyH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdY8ptl%2FbtrwmsFruWx%2FmSi8J83OhUM79UNvpcnyH0%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;1184&quot; height=&quot;1188&quot; data-filename=&quot;스크린샷 2022-03-18 오후 11.50.43.png&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;1188&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제풀이 전]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다익스트라 알고리즘을 알아야 이 문제를 해결할 수 있습니다. 해당 알고리즘 개념을 모르면 쉬운 개념의 문제부터 익히고 오거나, 검색하셔서 해당 개념을 익히면 금방 풀 수 있는 정도의 난이도입니다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제풀이]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다익스트라를 활용한 문제로 수색할 수 있는 거리가 한정되어 있어, 한 정점에서 다른 정점으로 이동하는 최소거리를 전부 구하여 dist배열에 담아주고,&amp;nbsp; 움직일 수 있는 범위이면 해당 아이템을 얻는 식으로 구현하면 됩니다. 그리고 어느 지점에 떨어지는지는 나오지 않아 모든 정점에서 다익스트라를 시작하여 가장 아이템을 많이 획득할 수 있도록 max값을 가져서 출력하도록 구현하면 문제를 해결할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[소스코드]&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1647615418695&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class Main {

    static class Node{
        int v;
        int cost;

        public Node(int v, int cost) {
            this.v = v;
            this.cost = cost;
        }
    }

    static int n, m, r;
    static ArrayList&amp;lt;Node&amp;gt;[] list;
    static int[] dist, item;
    static boolean[] visit;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        r = Integer.parseInt(st.nextToken());

        list = new ArrayList[n + 1];
        dist = new int[n + 1];
        visit = new boolean[n + 1];
        item = new int[n + 1];

        for (int i = 1; i &amp;lt;= n; i++) {
            list[i] = new ArrayList&amp;lt;&amp;gt;();
        }

        st = new StringTokenizer(br.readLine());
        for (int i = 1; i &amp;lt;= n; i++) {
            item[i] = Integer.parseInt(st.nextToken());
        }

        for (int i = 0; i &amp;lt; r; i++) {
            st = new StringTokenizer(br.readLine());
            int u = Integer.parseInt(st.nextToken());
            int v = Integer.parseInt(st.nextToken());
            int w = Integer.parseInt(st.nextToken());

            list[u].add(new Node(v, w));
            list[v].add(new Node(u, w));
        }

        int ans = 0;
        for (int i = 1; i &amp;lt;= n; i++) {
            ans = Math.max(ans, dijkstra(i));
        }

        System.out.println(ans);
    }

    static int dijkstra(int start) {
        Arrays.fill(dist, Integer.MAX_VALUE);
        Arrays.fill(visit, false);

        PriorityQueue&amp;lt;Node&amp;gt; q = new PriorityQueue&amp;lt;&amp;gt;((o1, o2) -&amp;gt; o1.cost - o2.cost);
        q.add(new Node(start, 0));
        dist[start] = 0;

        while (!q.isEmpty()) {
            Node now = q.poll();

            if (!visit[now.v]) {
                visit[now.v] = true;

                for (Node next : list[now.v]) {
                    if (!visit[next.v] &amp;amp;&amp;amp; dist[next.v] &amp;gt; now.cost + next.cost) {
                        dist[next.v] = now.cost + next.cost;
                        q.add(new Node(next.v, dist[next.v]));
                    }
                }
            }
        }
        int sum = 0;

        for (int i = 1; i &amp;lt;= n; i++) {
            if (m &amp;gt;= dist[i]) {
                sum += item[i];
            }
        }

        return sum;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준 문제풀이</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/77</guid>
      <comments>https://dding9code.tistory.com/77#entry77comment</comments>
      <pubDate>Fri, 18 Mar 2022 23:48:31 +0900</pubDate>
    </item>
    <item>
      <title>람다식(Lambda expression) - JAVA</title>
      <link>https://dding9code.tistory.com/76</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;람다식이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;람다식은 메서드를 하나의 식으로 표현한 것&lt;/b&gt;입니다. 메서드를 간략하면서도 명확한 식으로 표현할 수 있게 해주며, 메서드의 이름과 반환값이 없어지므로 '익명함수(anonymous function)' 이라고도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다식은 '익명 함수' 답게 메서드에서 이름과 반환타입을 제거하고 매개변수 선언부와 몸통{ }&amp;nbsp; 사이에 ' -&amp;gt; ' 를 추가합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;//기존방식&lt;br /&gt;반환타입 메서드이름(매개변수 선언) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 문장들&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;//람다사용&lt;br /&gt;(매개변수 선언) -&amp;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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;람다식의 장단점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 코드를 간결하고 명확하게 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 함수를 만드는 과정이 없어 생산성이 높아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 다중 cpu를 활용하는 형태로 구현되어 병렬 프로그래밍에 유리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 남발하여 사용할 경우 가독성이 오히려 떨어짐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 람다를 사용하면서 만든 익명함수는 재사용이 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 디버깅이 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;함수형 인터페이스 (Functional Interface)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 람다식을 다루기 위한 인터페이스를 '&lt;b&gt;함수형 인터페이스&lt;/b&gt;' 라 하며 이는 &lt;b&gt;오직 하나의 추상 메서드만 정의되어 있어야 한다는 제약&lt;/b&gt;이 있다습니다. 왜냐하면 그래야 &lt;b&gt;람다식과 인터페이스의 메서드가 1:1로 연결&lt;/b&gt;될 수 있기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 아래와 같이 인터페이스 메서드를 하나 구현하는데에도 코드를 복잡하세 구현을 해야 했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1647492276559&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Example {

    public static void main(String[] args) {
        ArrayList&amp;lt;Integer&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();

        for (int i = 0; i &amp;lt; 10; i++) {
            list.add((int) (Math.random() * 10) + 1);
        }

        Collections.sort(list, new Comparator&amp;lt;Integer&amp;gt;() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });
        
        System.out.println(list);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 람다식을 사용하여 아래와 같이 간단히 처리할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1647492192532&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Example {

    public static void main(String[] args) {
        ArrayList&amp;lt;Integer&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();

        for (int i = 0; i &amp;lt; 10; i++) {
            list.add((int) (Math.random() * 10) + 1);
        }

        Collections.sort(list, (o1, o2) -&amp;gt; o1 - o2);

        System.out.println(list);
    }
}&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;람다식의 타입과 형변환&lt;/b&gt;&lt;/h4&gt;
&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;pre id=&quot;code_1647493602125&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@FunctionalInterface
interface exFunction {
    void example();
}

public class Example {

    public static void main(String[] args) {
        exFunction f = (exFunction) (() -&amp;gt; {}); //exFunction 생략 가능
        
        //람다식은 Object 형변환이 안된다.
        Object obj = (Object) (() -&amp;gt; {});
        System.out.println(() -&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;람다식은 인터페이스를 구현한 클래스의 객체와 동일하기 때문에 (exFunction) 형변환을 허용하고, 생략이 가능하다. 람다식은 이름이 없을 뿐 분명 객체이지만 &lt;b&gt;Object 타입으로 형변환을 할 수 없다&lt;/b&gt;. 람다식은 오로지 함수형 인터페이스로만 형변환이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;java.util.function 패키지&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java.util.function 패키지에 일반적으로 자주 쓰이는 형식의 메서드를 함수형 인터페이스로 미리 정의해 놓았다. 이 패키지의 인터페이스를 활용하면 재사용성이나 유지보수 측면에서도 활용도가 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;&lt;b&gt;함수형 인터페이스&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;&lt;b&gt;메서드&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;java.lang.Runnable&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;void run()&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;매개변수 x, 반환값 x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;Supplier&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;&lt;b&gt;T get(&lt;/b&gt;) --&amp;gt; T&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;매개변수 x, 반환값 o&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;Consumer&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;T --&amp;gt; &lt;b&gt;void accept(T t)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Supplier와 반대로 매개변수 o, 반환값 x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;Function&amp;lt;T, R&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;T --&amp;gt;&lt;b&gt; R apply(T t)&lt;/b&gt; --&amp;gt; R&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;일반적인 함수. 하나의 매개변수를 받아서 결과를 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;Predicate&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;T --&amp;gt; &lt;b&gt;boolean test(T t)&lt;/b&gt; --&amp;gt; boolean&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;조건식을 표현하는데 사용된다.&lt;br /&gt;매개변수는 하나, 반환 타입은 boolean&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[참고] 타입 문자 'T' 는 'Type'&amp;nbsp; , 'R' 은 'Return Type' 이다.&lt;/p&gt;
&lt;p data-ke-size=&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>자바 (ref. 자바의정석)</category>
      <category>ㅂ</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/76</guid>
      <comments>https://dding9code.tistory.com/76#entry76comment</comments>
      <pubDate>Thu, 17 Mar 2022 14:25:52 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스 Level1] 키패드 누르기 (JAVA) - 2020 Kakao</title>
      <link>https://dding9code.tistory.com/75</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처 - &lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/67256?language=java&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/67256?language=java&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1647400848395&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 키패드 누르기&quot; data-og-description=&quot;[1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5] &amp;quot;right&amp;quot; &amp;quot;LRLLLRLLRRL&amp;quot; [7, 0, 8, 2, 8, 3, 1, 5, 7, 6, 2] &amp;quot;left&amp;quot; &amp;quot;LRLLRRLLLRR&amp;quot; [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] &amp;quot;right&amp;quot; &amp;quot;LLRLLRLLRL&amp;quot;&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/67256?language=java&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/67256?language=java&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eLhrd/hyNHWvJRtJ/31VeMnRrzdCxiOre1aKTSK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/dF51HA/hyNHVDBS0D/8Jwkg9KJIoVp7hI0mHkhY1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/67256?language=java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/67256?language=java&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eLhrd/hyNHWvJRtJ/31VeMnRrzdCxiOre1aKTSK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/dF51HA/hyNHVDBS0D/8Jwkg9KJIoVp7hI0mHkhY1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 키패드 누르기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5] &quot;right&quot; &quot;LRLLLRLLRRL&quot; [7, 0, 8, 2, 8, 3, 1, 5, 7, 6, 2] &quot;left&quot; &quot;LRLLRRLLLRR&quot; [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] &quot;right&quot; &quot;LLRLLRLLRL&quot;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-03-16 오후 12.21.16.png&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;871&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rYgXa/btrv6XLSv58/RUGKYQP4mc8KKvOgPJND30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rYgXa/btrv6XLSv58/RUGKYQP4mc8KKvOgPJND30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rYgXa/btrv6XLSv58/RUGKYQP4mc8KKvOgPJND30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrYgXa%2Fbtrv6XLSv58%2FRUGKYQP4mc8KKvOgPJND30%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;359&quot; height=&quot;392&quot; data-filename=&quot;스크린샷 2022-03-16 오후 12.21.16.png&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;871&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-03-16 오후 12.21.36.png&quot; data-origin-width=&quot;1255&quot; data-origin-height=&quot;743&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMur8i/btrv8chK844/qXWtNm08ojCA3Mt5lYrDK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMur8i/btrv8chK844/qXWtNm08ojCA3Mt5lYrDK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMur8i/btrv8chK844/qXWtNm08ojCA3Mt5lYrDK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMur8i%2Fbtrv8chK844%2FqXWtNm08ojCA3Mt5lYrDK0%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;1255&quot; height=&quot;743&quot; data-filename=&quot;스크린샷 2022-03-16 오후 12.21.36.png&quot; data-origin-width=&quot;1255&quot; data-origin-height=&quot;743&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제 풀기 전]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에 실력이 지금보다 부족할 때 상하좌우 4가지 방향에 이동 한 칸의 거리는 1이니까 bfs 문제인가? 라고 생각을 하고 풀어보려했지만 풀지 못한 기억이 있다. 왼손 오른손이 있고 2, 5 , 8, 0 을 누를때만 가까운 손이 누르도록 하고, 같으면 문제에 주어진 손으로 누르라고 지시하고 해서 그냥 단순 구현으로 해결할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제 풀이]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 '1, 4, 7' 버튼을 누를 때와 '3, 6, 9' 버튼을 누를 때는 처리가 쉽다. 그냥 해당 버튼이 주어지면 왼손, 오른손을 출력하도록 만들면 된다. 하지만 '2, 5, 8, 0' 이 부분을 처리하는게 살짝 까다로웠다. 문제에 2, 5, 8, 0 은 현재 키패드의 위치에서 더 가까운 손가락을 사용한다고 주어졌다. 따라서 현재 왼손의 위치를 가지는 변수와 오른손의 위치를 가지는 변수를 가지고 입력받은 버튼의 거리의 차이를 구해야 문제에 주어진 '조건 4' 와 '조건 4-1' 을 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 거리는 어떻게 구할 것인가? 하면 키패드는 세로는 3개 가로도 3개 이기 때문에 '&lt;b&gt;현재 위치 - 누르는 위치의 절대값&lt;/b&gt;' 을 한 결과를 &lt;b&gt;위 아래로 움직일 때는 '/3 ' 을 해주고, 좌 우 로 움직이는 거리는 '%3'&lt;/b&gt; 이니 두개값을 더하면 거리를 구할 수 있다. 그리고 '0' 은 키패드 상에서 실제 위치는 11이므로 입력이 0이 들어왔을때 11로 바꿔줘서 계산을 해준다. 그렇게 해서 문제에서 요구한 대로 구현을 하면 정답을 구할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;b&gt;[소스 코드]&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1647401988569&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public String solution(int[] numbers, String hand) {
        StringBuilder sb = new StringBuilder();

        int left = 10;
        int right = 12;

        for (int i = 0; i &amp;lt; numbers.length; i++) {
            int n = numbers[i];

            if (n == 1 || n == 4 || n == 7) {
                left = n;
                sb.append(&quot;L&quot;);
            }
            if (n == 3 || n == 6 || n == 9) {
                right = n;
                sb.append(&quot;R&quot;);
            }
            if (n == 2 || n == 5 || n == 8 || n == 0) {
                if( n == 0 ) n = 11;

                int leftDiff = (Math.abs(n - left) / 3) + (Math.abs(n - left) % 3);
                int rightDiff =(Math.abs(n - right) / 3) + (Math.abs(n - right) % 3);

                if (leftDiff == rightDiff) {
                    if (hand.equals(&quot;right&quot;)) {
                        right = n;
                        sb.append(&quot;R&quot;);
                    }else{
                        left = n;
                        sb.append(&quot;L&quot;);
                    }
                } else if (leftDiff &amp;gt; rightDiff) {
                    right = n;
                    sb.append(&quot;R&quot;);
                } else {
                    left = n;
                    sb.append(&quot;L&quot;);
                }
            }
        }
        return sb.toString();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/75</guid>
      <comments>https://dding9code.tistory.com/75#entry75comment</comments>
      <pubDate>Wed, 16 Mar 2022 12:40:58 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스 Level1] 숫자 문자열과 영단어(JAVA) - 2021 Kakao</title>
      <link>https://dding9code.tistory.com/74</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/81301?language=java&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/81301?language=java&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1647182398461&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 숫자 문자열과 영단어&quot; data-og-description=&quot;네오와 프로도가 숫자놀이를 하고 있습니다. 네오가 프로도에게 숫자를 건넬 때 일부 자릿수를 영단어로 바꾼 카드를 건네주면 프로도는 원래 숫자를 찾는 게임입니다. 다음은 숫자의 일부 자&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/81301?language=java&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/81301?language=java&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bwSmNg/hyNGKPoHDz/Vzslbdx2rESHcBrJQfAVyk/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/bidmQl/hyNGIKOqrr/ZSU8h4KtrWrcOoRru1LJT0/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/81301?language=java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/81301?language=java&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bwSmNg/hyNGKPoHDz/Vzslbdx2rESHcBrJQfAVyk/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/bidmQl/hyNGIKOqrr/ZSU8h4KtrWrcOoRru1LJT0/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 숫자 문자열과 영단어&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;네오와 프로도가 숫자놀이를 하고 있습니다. 네오가 프로도에게 숫자를 건넬 때 일부 자릿수를 영단어로 바꾼 카드를 건네주면 프로도는 원래 숫자를 찾는 게임입니다. 다음은 숫자의 일부 자&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-03-13 오후 11.41.29.png&quot; data-origin-width=&quot;1291&quot; data-origin-height=&quot;1112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0nTMa/btrvUCgwiYy/Na5ukKW4UA8JNw88KP9F6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0nTMa/btrvUCgwiYy/Na5ukKW4UA8JNw88KP9F6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0nTMa/btrvUCgwiYy/Na5ukKW4UA8JNw88KP9F6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0nTMa%2FbtrvUCgwiYy%2FNa5ukKW4UA8JNw88KP9F6K%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;1291&quot; height=&quot;1112&quot; data-filename=&quot;스크린샷 2022-03-13 오후 11.41.29.png&quot; data-origin-width=&quot;1291&quot; data-origin-height=&quot;1112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[문제 풀이]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력으로 영단어 숫자와, 숫자가 주어졌을때 결과값을 숫자로 바꿔서 return 하도록 구현을 하면 되는 문제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바꾼다는 점에서 replaceAll 을 떠올렸고,&amp;nbsp; 0&amp;nbsp; ~ 9 까지의 수를 변환하면 되기 때문에 주어진 영단어 10개를 배열로 만들고 for문을 진행을 하여 해당 단어를 해당 배열의 번호로 바꿔주면 풀리는 생각보다 간단한 문제 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[소스 코드]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1647182891580&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public int solution(String s) {
        String[] word = {&quot;zero&quot;, &quot;one&quot;, &quot;two&quot;, &quot;three&quot;, &quot;four&quot;, &quot;five&quot;, &quot;six&quot;, &quot;seven&quot;, &quot;eight&quot;, &quot;nine&quot;};
        StringBuilder sb = new StringBuilder();


        String ans = s;
        for (int i = 0; i &amp;lt; word.length; i++) {
            ans = ans.replaceAll(word[i], String.valueOf(i));
        }

        int answer = Integer.parseInt(ans);

        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래머스</category>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/74</guid>
      <comments>https://dding9code.tistory.com/74#entry74comment</comments>
      <pubDate>Sun, 13 Mar 2022 23:41:01 +0900</pubDate>
    </item>
    <item>
      <title>MySQL - JOIN</title>
      <link>https://dding9code.tistory.com/73</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JOIN&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JOIN 은 데이터베이스 내의 여러 테이블에서 가져온 레코드를 조합하여 하나의 테이블이나 결과 집합으로 표현해 줍니다. 간단하게 테이블을 조립한다 라고 생각하면 될 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블 실습 - &lt;a href=&quot;https://www.w3schools.com/mysql/trymysql.asp?filename=trysql_select_all&quot;&gt;https://www.w3schools.com/mysql/trymysql.asp?filename=trysql_select_all&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1647002516505&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;MySQL Tryit Editor v1.0&quot; data-og-description=&quot;WebSQL stores a Database locally, on the user's computer. Each user gets their own Database object. WebSQL is supported in Chrome, Safari, and Opera. If you use another browser you will still be able to use our Try SQL Editor, but a different version, usin&quot; data-og-host=&quot;www.w3schools.com&quot; data-og-source-url=&quot;https://www.w3schools.com/mysql/trymysql.asp?filename=trysql_select_all&quot; data-og-url=&quot;https://www.w3schools.com/mysql/trymysql.asp?filename=trysql_select_all&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.w3schools.com/mysql/trymysql.asp?filename=trysql_select_all&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.w3schools.com/mysql/trymysql.asp?filename=trysql_select_all&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MySQL Tryit Editor v1.0&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;WebSQL stores a Database locally, on the user's computer. Each user gets their own Database object. WebSQL is supported in Chrome, Safari, and Opera. If you use another browser you will still be able to use our Try SQL Editor, but a different version, usin&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.w3schools.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. JOIN(INNER JOIN) - 내부 조인&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-03-11 오후 9.37.19.png&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boYd4z/btrvLg52Sln/Dm4iusKIlosEBGdgbe8yk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boYd4z/btrvLg52Sln/Dm4iusKIlosEBGdgbe8yk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boYd4z/btrvLg52Sln/Dm4iusKIlosEBGdgbe8yk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboYd4z%2FbtrvLg52Sln%2FDm4iusKIlosEBGdgbe8yk0%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;238&quot; height=&quot;168&quot; data-filename=&quot;스크린샷 2022-03-11 오후 9.37.19.png&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;168&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 양쪽 모두에 값이 있는 행(NOT NULL) 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- INNER 는 선택사항.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1647002556595&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM Categories C
JOIN Products P 
  ON C.CategoryID = P.CategoryID;&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;위와 같이 작성하면 양쪽 모두 값이 있는 행을 가져오는데 Categories 와 Proudct의 CatgegoryID 가 같은 테이블들을 합친 결과가 나오게 됩니다. 여기서 C, P 는 '변수' 라고 생각하시면 됩니다. 아래와 같이 응용이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1647002842319&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT C.CategoryID, C.CategoryName, P.ProductName
FROM Categories C
JOIN Products P 
  ON C.CategoryID = P.CategoryID;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선택할 어떤 테이블의 레코드를 가져올지 가독성이 뛰어나게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. LEFT, RIGHT JOIN - 외부 조인&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-03-11 오후 9.37.25.png&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FoGOX/btrvHYZ97av/VkrJ5Yl7Wy8EqrF2mD0dPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FoGOX/btrvHYZ97av/VkrJ5Yl7Wy8EqrF2mD0dPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FoGOX/btrvHYZ97av/VkrJ5Yl7Wy8EqrF2mD0dPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFoGOX%2FbtrvHYZ97av%2FVkrJ5Yl7Wy8EqrF2mD0dPK%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;238&quot; height=&quot;168&quot; data-filename=&quot;스크린샷 2022-03-11 오후 9.37.25.png&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;168&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;반대쪽에는 데이터가 있든 없든(NULL), 선택된 방향에 있으면 출력 - 행 수 결정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LEFT JOIN - 예제)&lt;/p&gt;
&lt;pre id=&quot;code_1647003233034&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
  C.CustomerName, S.SupplierName,
  C.City, C.Country
FROM Customers C
LEFT JOIN Suppliers S
ON C.City = S.City AND C.Country = S.Country;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-03-11 오후 9.37.30.png&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eG6zLm/btrvL5349Lb/pLPHJ2Z4izXZPj0Qsrd2Bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eG6zLm/btrvL5349Lb/pLPHJ2Z4izXZPj0Qsrd2Bk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eG6zLm/btrvL5349Lb/pLPHJ2Z4izXZPj0Qsrd2Bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeG6zLm%2FbtrvL5349Lb%2FpLPHJ2Z4izXZPj0Qsrd2Bk%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;238&quot; height=&quot;168&quot; data-filename=&quot;스크린샷 2022-03-11 오후 9.37.30.png&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;168&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;반대쪽에는 데이터가 있든 없든(NULL), 선택된 방향에 있으면 출력 - 행 수 결정 LEFT, RIGHT 왼쪽 오른쪽 차이이지 하는 일은 똑같습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RIGHT JOIN - 예제)&lt;/p&gt;
&lt;pre id=&quot;code_1647003536862&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
  C.CustomerName, S.SupplierName,
  C.City, C.Country
FROM Customers C
RIGHT JOIN Suppliers S
ON C.City = S.City AND C.Country = S.Country;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 다이어그램과 같이 한쪽에 데이터가 비어도 테이블을 가져옵니다. 직접 실행을 해보시면 확연히 다른점을 확인 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. FULL OUTER JOIN - 전체 외부 조인&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-03-11 오후 10.37.19.png&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;165&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6E9r6/btrvMIU9CFw/tBCjQn4Hl20TkXu18o7mHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6E9r6/btrvMIU9CFw/tBCjQn4Hl20TkXu18o7mHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6E9r6/btrvMIU9CFw/tBCjQn4Hl20TkXu18o7mHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6E9r6%2FbtrvMIU9CFw%2FtBCjQn4Hl20TkXu18o7mHk%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;256&quot; height=&quot;165&quot; data-filename=&quot;스크린샷 2022-03-11 오후 10.37.19.png&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;165&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문법&lt;/p&gt;
&lt;pre id=&quot;code_1647005869973&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT column_name(s)
FROM table1
FULL OUTER JOIN table2
ON table1.column_name = table2.column_name
WHERE condition;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽 테이블과 오른쪽 테이블 레코드에 일치하는 모든 레코드를 가져옵니다. 많이 보이지는 않아서 이런게 있다 아시면 좋을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>쿠쿠s</author>
      <guid isPermaLink="true">https://dding9code.tistory.com/73</guid>
      <comments>https://dding9code.tistory.com/73#entry73comment</comments>
      <pubDate>Fri, 11 Mar 2022 22:01:22 +0900</pubDate>
    </item>
  </channel>
</rss>