<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>HoGeun.log</title>
        <link>https://velog.io/</link>
        <description>22.11.28 ~</description>
        <lastBuildDate>Wed, 04 Sep 2024 13:36:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>HoGeun.log</title>
            <url>https://velog.velcdn.com/images/choi_ho_geun_97/profile/eed36a75-ed6f-420e-ba0a-3a1c1e650458/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. HoGeun.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/choi_ho_geun_97" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[kopf를 버린 이유]]></title>
            <link>https://velog.io/@choi_ho_geun_97/kopf%EB%A5%BC-%EB%B2%84%EB%A6%B0-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@choi_ho_geun_97/kopf%EB%A5%BC-%EB%B2%84%EB%A6%B0-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Wed, 04 Sep 2024 13:36:04 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>클라우드 리소스 자동화를 위해 
crossplane을 사용하여 리소스들을 매니징하고있음.
동시에, kopf를 통하여 이벤트를 모니터링함.</p>
<h4 id="이슈상황">이슈상황</h4>
<ul>
<li>VPC리소스를 생성 시 crossplane과 kopf가 충돌없이 동작함.</li>
<li>EC2 Instance 생성 시 여러 하위 리소스들을 동시에 생성하며,
하위 리소스들의 준비상태를 기다리며, Instance리소스의 생성이 지연되는 상황이 발생함.
(리소스 status.atProvider가 갱신되지 않는 현상이 발생함. 이 부분에서 crossplane과 kopf의 충돌을 의심함)</li>
</ul>
<p><strong>해당시점에 ec2 Provider pod에서 대강 아래와 같은 Warning을 발생시킴.</strong></p>
<pre><code>,&quot;error&quot;:&quot;cannot update status of the resource ec2.aws.upbound.io/v1beta1, Kind=SecurityGroup/securitygroup-bvf6s3 after an async create: Operation cannot be fulfilled on securitygroups.ec2.aws.upbound.io \&quot;securitygroup-bvf6s3\&quot;: the object has been modified; please apply your changes to the latest version and try again</code></pre><p>처음 이 문제를 마주하였을 때, k8s API가 kopf와 crossplane에 의해 변경된 resource의 Version정보를 타게팅하지 못해서 발생하는 이슈이거나 하위리소스들이 정상적인 상태를 가지지 못하여 발생하는 문제로 생각했으나, 생성시간이 짧은 리소스들은 문제없이 동작한다는 부분이 설명되지 못했음..</p>
<hr>
<p><strong>예상되는 문제점은</strong></p>
<ol>
<li><p>crossplane에 의해 리소스와 리소스 버전이 갱신된 후
kopf가 리소스 관리목적으로 변경된 상태정보로 annotation 필드를 갱신하여 다시 한 번 리소스 버전이 업데이트되면 K8s API는 Crossplane과 kopf에 의해 업데이트 된 리소스버전을 기억해야하지만, 생성지연으로 인해 리소스버전이 유휴상태에 돌입하여 리소스 버전을 명확히 타겟팅하지 못하는 현상.</p>
</li>
<li><p>crossplane의 finalizer와 kopf의 finalizer 충돌
동일한 리소스에 대하여 두개의 트리거가 동작하여 충돌할 우려가 있음.</p>
</li>
</ol>
<h3 id="k8s-watch-stream">K8s watch stream</h3>
<p>1번은 kopf의 피어링 설정으로 annotations과 finalizer를 부여하지 않도록 하면 되었으나, crossplane과 kopf의 트리거가 충돌하여 이마저도 불가해짐 ㅠㅠ 서로 관리해야할 필드를 분리해서 책임을 분산시키거나 읽기전용으로 kopf를 실행시켜볼까 생각도 했는데, 배보다 배꼽이 더 커지는 상황인것같아서 둘 중 하나는 포기해야하는 상황..</p>
<p>당연히 모니터링만을 위해 도입한 kopf를 버렸고, 모니터링 시스템을 k8s 네이티브하게 개발해야했음.</p>
<p>k8s API 가 제공하는 event watch stream으로 개별리소스를 스트림으로 동기적으로 연결하여 실시간으로 이벤트를 수령하도록 구현함.
(고객사가 관리하는 securityGroup만 수만 건.. 거기에 딸려있는 association들을 합치면 모니터링해야하는 리소스의 수는 수십만건 정도될듯)</p>
<p>kopf가 제공하는 강력한 기능인 diff를 사용하지 못하게되면서,</p>
<p>리소스의 이전 상태를 어딘가에 저장해둘 필요가 있었음.
(전역으로 관리하기엔 언젠가 분리해야할것같다는 걱정이 있어서 Redis도입하기로 함)</p>
<p>리소스의 상태는 매우 자주 바뀌기 땜시
Redis 서버에 리소스 만큼의 객체를 만들고, 그 안에 4칸짜리 dequeue를 만들어서 리소스 상태를 관리하기로 함.</p>
<hr>
<p>구현 결과.
Instance 리소스를 생성하며 생성시간이 지연되어도, atProvider가 정상적으로 갱신되며 모든 crossplane의 프로비저닝 작업이 정상적으로 동작하는 것을 확인하였음.</p>
<p>더 이상 ec2 Provider pod에서 warning로그도 출력되지 않음</p>
<h3 id="결론">결론</h3>
<p>당장의 이슈는 해결하였으나..</p>
<p>Kopf와 Crossplane을 동시에 사용할 수 있는 방법도 분명히 있을 것 같아서,
추후에 Kopf와 Crossplane의 이벤트 트리거가 동작하는 방식의 차이를 제대로 알아보고,</p>
<ul>
<li>읽기 전용으로 kopf 실행</li>
<li>finalizer 충돌 관리<ul>
<li>kopf에서만 finalizer 제거</li>
</ul>
</li>
</ul>
<p>를 적용해보아야겠따..</p>
<p>조금 더 범용적으로 설계하려면 그냥 k8s 네이티브하게 개발하는게 나을지두?
고민고민</p>
<p>이슈를 기술적으로 우회해서 처리하기보다는 애초에 이슈가 안생기게끔 설계부터 잘하는게 좋을것같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스. 문자열 여러 번 뒤집기]]></title>
            <link>https://velog.io/@choi_ho_geun_97/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4.-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%97%AC%EB%9F%AC-%EB%B2%88-%EB%92%A4%EC%A7%91%EA%B8%B0</link>
            <guid>https://velog.io/@choi_ho_geun_97/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4.-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%97%AC%EB%9F%AC-%EB%B2%88-%EB%92%A4%EC%A7%91%EA%B8%B0</guid>
            <pubDate>Sat, 16 Sep 2023 04:54:39 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-java">
class Solution {
    public String solution(String my_string, int[][] queries) {

        char[] charArr_my_string = my_string.toCharArray();
        char temp = &#39; &#39;;

        for(int[] query : queries){
            int reverseLength = (query[1] - query[0] +1)/2;
            int sttIdx = query[0]; // 시작 인덱스
            int endIdx = query[1]; // 끝 인덱스

            for(int i = 0; i &lt; reverseLength; i++){
                if(!(sttIdx &gt; endIdx)){ // 시작인덱스가 끝인덱스보다 작다면
                    temp = charArr_my_string[sttIdx];
                    charArr_my_string[sttIdx] = charArr_my_string[endIdx];
                    charArr_my_string[endIdx] = temp;
                    sttIdx ++;
                    endIdx --;
                }
            }
        }
        String answer = new String(charArr_my_string);
        return answer;
    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[StandardServletMultipartResolver Failed to perform cleanup of multipart items

java.io.UncheckedIOException: Cannot delete]]></title>
            <link>https://velog.io/@choi_ho_geun_97/StandardServletMultipartResolver-Failed-to-perform-cleanup-of-multipart-itemsjava.io.UncheckedIOException-Cannot-delete</link>
            <guid>https://velog.io/@choi_ho_geun_97/StandardServletMultipartResolver-Failed-to-perform-cleanup-of-multipart-itemsjava.io.UncheckedIOException-Cannot-delete</guid>
            <pubDate>Sun, 14 May 2023 09:29:01 GMT</pubDate>
            <description><![CDATA[<p>multipart/form-data 타입의 파일업로드 중 발생.</p>
<p>AppData / Local / Temp 폴더는 임시폴더이다.
해당 폴더에 임시 파일업로드는 되었는데, 해당오류가 출력되길래
혹시 프로세스를 물고 안놔주는건가 싶어서 리소스를 모니터링해봤는데</p>
<p>STS가 잡고있던 해당 임시파일은 시간이 지나면서 자원해제 되었다..</p>
<p>그럼 뭐가 문제일까 생각해보니
파일을 당겨온 뒤 후처리 로직을 명확히 작성하지 않은것이 오류의 원인 일 수도 있겠다는 생각이 든다.</p>
<p>내일 처리해봐야겠다.</p>
<p>++ 처리결과
예상대로 후처리 로직을 작성해주지 않아서 발생한 이슈였음.
자원해제 코드를 명확히 작성해주니 해결되었음.
try-finally 구문을사용,
try 구문에서 inputStream을 열어주고,
finally 블록에서 inputStream을 close해주니 해결.</p>
<p>자원해제를 해야하는 것을 알면서도 이런 바보같은 실수를 하다니..
기초를 더 탄탄히 해야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SOLID 5원칙]]></title>
            <link>https://velog.io/@choi_ho_geun_97/SOLID-5%EC%9B%90%EC%B9%99</link>
            <guid>https://velog.io/@choi_ho_geun_97/SOLID-5%EC%9B%90%EC%B9%99</guid>
            <pubDate>Tue, 18 Apr 2023 13:53:42 GMT</pubDate>
            <description><![CDATA[<h1 id="좋은-객체-지향-설계의-5가지-원칙-solid-5원칙">좋은 객체 지향 설계의 5가지 원칙 SOLID 5원칙</h1>
<h3 id="srpsingle-responsibility-principle">SRP(Single responsibility principle)</h3>
<ul>
<li>단일책임원칙</li>
<li>한 클래스는 하나의 책임만 가져야 한다.</li>
<li>하나의 책임이라는 것은 모호함<ul>
<li>클 수도 있고, 작을 수도 있음</li>
<li>문맥과 상황에 따라 다름</li>
</ul>
</li>
<li>중요한 기준은 변경임.<ul>
<li>변경이 있을 때, 파급효과가 적으면 단일 책임 원칙을 잘 따른 것.</li>
<li>ex) UI변경, 객체의 생성과 사용을 분리</li>
</ul>
</li>
</ul>
<h3 id="ocp개방-폐쇄-원칙-openclosed-principle">OCP(개방-폐쇄 원칙 Open/Closed principle)</h3>
<ul>
<li>소프트웨어 요소는 확장에 열려있으나, 변경에 닫혀있어야한다.</li>
<li>다형성을 활용.</li>
<li>인터페이스를 구현한 새로운 클래스를 하나 만드는 것 (확장)</li>
</ul>
<p>문제점</p>
<ul>
<li>구현객체를 변경하려면 클라이언트 코드를 변경해야한다.</li>
<li>분명 다형성을 사용했지만  OCP원칙을 지킬수 없음</li>
<li>이 문제를 해결하려면 객체를 생성하고, 연관관계를 맺어주는 별도의 조립, 설정자가 필요함.<ul>
<li>이 문제를 해결해주는 녀석이 Spirng 컨테이너.</li>
<li>DI도 필요하고 IoC 컨테이너를 필요로함</li>
</ul>
</li>
</ul>
<h3 id="lsp리스코프-치환원칙-liskov-subsititution-principle">LSP(리스코프 치환원칙 Liskov subsititution principle)</h3>
<ul>
<li>프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위타입의 인스턴스로 바꿀 수 있어야함.</li>
<li>다형성에서 하위클래스는 인터페이스 규약을 지켜야한다는 것.</li>
<li>ex) 자동차 인터페이스의 D은 앞으로 가는 기능, 뒤로가게 구현하면 LSP위반.</li>
</ul>
<h3 id="isp인터페이스-분리-원칙-interface-segregation-principle">ISP(인터페이스 분리 원칙 Interface segregation principle)</h3>
<ul>
<li>특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.</li>
<li>자동차 인터페이스 →  운전 인터페이스, 정비 인터페이스로 분리</li>
<li>사용자 클라이언트 → 운전자 클라이언트, 정비사 클라이언트로 분리</li>
<li>분리하면 인터페이스 자체가 변해도 운전자 클라이언트에 영향을 주지 않음.</li>
<li>인터페이스가 명확해지고 대체 가능성이 높아짐.</li>
</ul>
<h3 id="dip의존관계-역전-원칙-dependency-inversion-principle">DIP(의존관계 역전 원칙 Dependency inversion principle)</h3>
<ul>
<li>추상화에 의존해야하고 구체화에 의존하면 안된다.</li>
<li>구현클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻.</li>
<li>역할에 의존해야한다. 객체세상도 클라이언트가 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있따.</li>
</ul>
<h3 id="정리">정리</h3>
<ul>
<li>객체지향의 핵심은 다형성</li>
<li>다형성 만으로는 쉽게 부품갈들이 개발할 수 없음</li>
<li>다형성 만으로는 구현객체를 변경할 때 클라이언트 코드도 함께 변경됨</li>
<li>다형성 만으로는 <strong>OCP, DIP</strong>를 지킬 수 없음.</li>
<li>무언가 더 필요함.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링 핵심원리 강의 정리-1]]></title>
            <link>https://velog.io/@choi_ho_geun_97/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC%EC%9B%90%EB%A6%AC-%EA%B0%95%EC%9D%98-%EC%A0%95%EB%A6%AC-1</link>
            <guid>https://velog.io/@choi_ho_geun_97/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC%EC%9B%90%EB%A6%AC-%EA%B0%95%EC%9D%98-%EC%A0%95%EB%A6%AC-1</guid>
            <pubDate>Tue, 18 Apr 2023 13:52:21 GMT</pubDate>
            <description><![CDATA[<h2 id="스프링-프레임워크">스프링 프레임워크</h2>
<h3 id="핵심기술">핵심기술</h3>
<ul>
<li>스프링 DI 컨테이너</li>
<li>AOP</li>
<li>이벤트</li>
</ul>
<h3 id="웹기술">웹기술</h3>
<ul>
<li>스프링 MVC</li>
<li>스프링 WebFlux</li>
</ul>
<h3 id="데이터-접근-기술">데이터 접근 기술</h3>
<ul>
<li>트랜잭션</li>
<li>JDBC</li>
<li>ORM 지원</li>
<li>XML 지원</li>
</ul>
<h3 id="기술통합">기술통합</h3>
<ul>
<li>캐시</li>
<li>이메일</li>
<li>원격접근</li>
<li>스케줄링</li>
</ul>
<h3 id="테스트">테스트</h3>
<ul>
<li>스프링 기반 테스트 지원</li>
</ul>
<h3 id="언어">언어</h3>
<ul>
<li>코틀린</li>
<li>그루비</li>
</ul>
<h3 id="최근에는-스프링-부트를-통해서-스프링-프레임워크의-기술들을-편리하게-사용함">최근에는 스프링 부트를 통해서 스프링 프레임워크의 기술들을 편리하게 사용함.</h3>
<h2 id="스프링-부트">스프링 부트</h2>
<ul>
<li>스프링을 편리하게 사용할 수 있도록 지원. 요즘에는 기본으로 사용</li>
<li>단독실행가능한 스프링 애플리케이션을 쉽게 생성</li>
<li>Tomcat같은 웹서버를 내장함. 웹서버 설치가 불필요</li>
<li>손쉬운 빌드구성을 위한 Starter 종속성 제공</li>
<li>스프링과3rd parth(외부) 라이브러리 자동 구성</li>
<li>메트릭, 상태확인, 외부구성같은 프로덕션 준비기능 제공</li>
<li>관례에 의한 간결한 설정</li>
</ul>
<h2 id="스프링이란-무엇인가">스프링이란 무엇인가?</h2>
<ul>
<li>스프링 DI 컨테이너 기술</li>
<li>스프링 프레임워크</li>
<li>스프링 부트, 스프링 프레임워크를 포함한 스프링 생태계</li>
</ul>
<h2 id="스프링은-왜-만들었는가">스프링은 왜 만들었는가?</h2>
<h2 id="스프링의-핵심">스프링의 핵심.</h2>
<ul>
<li>자바 기반의 프레임워크</li>
<li>객체지향</li>
<li>스프링은 객체지향언어가 가진 강력한 특징을 살려내는 프레임워크</li>
<li>스프링은 좋은 객체지향 애플리케이션을 개발할 수 있도록 도와주는 프레임워크</li>
</ul>
<h2 id="객체지향의-특징">객체지향의 특징</h2>
<ul>
<li>추상화</li>
<li>캡슐화</li>
<li>상속</li>
<li>다형성</li>
</ul>
<h2 id="유연하고-변경이-용이하다">유연하고 변경이 용이하다?</h2>
<ul>
<li>레고 블럭 조립하듯이</li>
<li>키보드, 마우스 갈아끼우듯이</li>
<li>컴퓨터 부품 갈듯이</li>
<li>컴포넌트를 쉽고 유연하게 변경하면서 개발할 수 있는 방법</li>
</ul>
<h2 id="다형성polymorphism">다형성(Polymorphism)</h2>
<p>클라이언트에 영향을 주지않고, 새로운 기능을 추가할 수 있는 것.</p>
<p>ex) 운전자와 자동차, 공연, 키보드,마우스, 세상의 표준인터페이스, 정렬알고리즘, 할인정책로직</p>
<p>역할과 구현으로 구분하면, 단순해지고, 유연해지며, 변경이 용이해진다.</p>
<p>클라이언트는 구현대상의 <strong>내부구조를 몰라도</strong> 된다.</p>
<p>클라이언트는 구현대상의 <strong>내부구조가 변경되어도</strong> 영향을 받지 않는다.</p>
<p>클라이언트는 구현대상 <strong>자체를 변경해도</strong> 영향을 받지 않는다.</p>
<p>자바언어는 다형성을 활용</p>
<p>역할 = 인터페이스</p>
<p>구현 = 인터페이스를 구현한 클래스, 구현객체</p>
<p>객체를 설계할 때, 역할과 구현을 명확히 분리</p>
<p>객체 설계 시 역할(인터페이스)을 먼저 부여하고, 그 역할을 수행하는 구현객체 만들기</p>
<h3 id="객체의-협력이라는-관계부터-생각해야함">객체의 협력이라는 관계부터 생각해야함.</h3>
<ul>
<li>혼자있는 객체는 없다.</li>
<li>클라이언트 : 요청</li>
<li>서버 : 응답</li>
<li>수 많은 클라이언트와 객체 서버는 서로 협력관계를 가짐.</li>
</ul>
<h3 id="자바언어의-다형성">자바언어의 다형성</h3>
<ul>
<li><em>오버로딩 (메서드 여러개 정의)</em></li>
<li>오버라이딩 (메서드 재정의)</li>
<li>오버라이딩은 자바 기본 문법</li>
<li>오버라이딩 된 메서드가 실행</li>
</ul>
<p>다형성으로 인터페이스를 구현한 객체를 실행시점에 유연하게 변경할 수 있는것이 자바언어가 가진 다형성의 장점이다!</p>
<p>인터페이스를 안정적으로 잘 설계하는 것이 제일 중요.</p>
<h3 id="한계점">한계점</h3>
<ul>
<li>역할(인터페이스) 자체가 변하면, 클라이언트, 서버 모두에 큰 변경이 발생</li>
</ul>
<p>다시한번 강조. 인터페이스를 안정적으로 잘 설계하는 것이 제일 중요.</p>
<h3 id="정리">정리</h3>
<ul>
<li>스프링은 다형성을 극대화한다.</li>
<li>스프링에서 이야기하는 제어의 역전(IoC), 의존관계 주입(DI)은 다형성을 활용해서 역할과 구현을 편리하게 다룰 수 있도록 지원.</li>
</ul>
<h2 id="좋은-객체-지향-설계의-5가지-원칙-solid-5원칙">좋은 객체 지향 설계의 5가지 원칙 SOLID 5원칙</h2>
<h3 id="srpsingle-responsibility-principle">SRP(Single responsibility principle)</h3>
<ul>
<li>단일책임원칙</li>
<li>한 클래스는 하나의 책임만 가져야 한다.</li>
<li>하나의 책임이라는 것은 모호함<ul>
<li>클 수도 있고, 작을 수도 있음</li>
<li>문맥과 상황에 따라 다름</li>
</ul>
</li>
<li>중요한 기준은 변경임.<ul>
<li>변경이 있을 때, 파급효과가 적으면 단일 책임 원칙을 잘 따른 것.</li>
<li>ex) UI변경, 객체의 생성과 사용을 분리</li>
</ul>
</li>
</ul>
<h3 id="ocp개방-폐쇄-원칙-openclosed-principle">OCP(개방-폐쇄 원칙 Open/Closed principle)</h3>
<ul>
<li>소프트웨어 요소는 확장에 열려있으나, 변경에 닫혀있어야한다.</li>
<li>다형성을 활용.</li>
<li>인터페이스를 구현한 새로운 클래스를 하나 만드는 것 (확장)</li>
</ul>
<p>문제점</p>
<ul>
<li>구현객체를 변경하려면 클라이언트 코드를 변경해야한다.</li>
<li>분명 다형성을 사용했지만  OCP원칙을 지킬수 없음</li>
<li>이 문제를 해결하려면 객체를 생성하고, 연관관계를 맺어주는 별도의 조립, 설정자가 필요함.<ul>
<li>이 문제를 해결해주는 녀석이 Spirng 컨테이너.</li>
<li>DI도 필요하고 IoC 컨테이너를 필요로함</li>
</ul>
</li>
</ul>
<h3 id="lsp리스코프-치환원칙-liskov-subsititution-principle">LSP(리스코프 치환원칙 Liskov subsititution principle)</h3>
<ul>
<li>프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위타입의 인스턴스로 바꿀 수 있어야함.</li>
<li>다형성에서 하위클래스는 인터페이스 규약을 지켜야한다는 것.</li>
<li>ex) 자동차 인터페이스의 D은 앞으로 가는 기능, 뒤로가게 구현하면 LSP위반.</li>
</ul>
<h3 id="isp인터페이스-분리-원칙-interface-segregation-principle">ISP(인터페이스 분리 원칙 Interface segregation principle)</h3>
<ul>
<li>특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.</li>
<li>자동차 인터페이스 →  운전 인터페이스, 정비 인터페이스로 분리</li>
<li>사용자 클라이언트 → 운전자 클라이언트, 정비사 클라이언트로 분리</li>
<li>분리하면 인터페이스 자체가 변해도 운전자 클라이언트에 영향을 주지 않음.</li>
<li>인터페이스가 명확해지고 대체 가능성이 높아짐.</li>
</ul>
<h3 id="dip의존관계-역전-원칙-dependency-inversion-principle">DIP(의존관계 역전 원칙 Dependency inversion principle)</h3>
<ul>
<li>추상화에 의존해야하고 구체화에 의존하면 안된다.</li>
<li>구현클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻.</li>
<li>역할에 의존해야한다. 객체세상도 클라이언트가 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있따.</li>
</ul>
<h3 id="정리-1">정리</h3>
<ul>
<li>객체지향의 핵심은 다형성</li>
<li>다형성 만으로는 쉽게 부품갈들이 개발할 수 없음</li>
<li>다형성 만으로는 구현객체를 변경할 때 클라이언트 코드도 함께 변경됨</li>
<li>다형성 만으로는 <strong>OCP, DIP</strong>를 지킬 수 없음.</li>
<li>무언가 더 필요함.</li>
</ul>
<h3 id="다시-스프링으로">다시 스프링으로.</h3>
<ul>
<li>스프링은 다음 기술로 다형성 + OCP, DIP를 가능하게 지원함.<ul>
<li>DI (Dependency Injection) : 의존관계, 의존성 주입</li>
<li>DI 컨테이너 제공</li>
</ul>
</li>
<li>클라이언트 코드의 변경 없이 기능 확장</li>
<li>쉽게 부품을 교체하듯이 개발</li>
</ul>
<h3 id="실무고민">실무고민</h3>
<ul>
<li>하지만 인터페이스를 도입하면 추상화라는 비용이 발생</li>
<li>기능을 확장할 가능성이 없다면, 구체클래스를 직접사용하고, 향후 꼭 필요할 때 리팩토링해서 인터페이스를 도입하는 것도 방법이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[국비 수료 3주 전]]></title>
            <link>https://velog.io/@choi_ho_geun_97/%EA%B5%AD%EB%B9%84-%EC%88%98%EB%A3%8C-3%EC%A3%BC-%EC%A0%84</link>
            <guid>https://velog.io/@choi_ho_geun_97/%EA%B5%AD%EB%B9%84-%EC%88%98%EB%A3%8C-3%EC%A3%BC-%EC%A0%84</guid>
            <pubDate>Sat, 25 Mar 2023 15:44:25 GMT</pubDate>
            <description><![CDATA[<h4 id="springboot를-시작한지-한-달차">SpringBoot를 시작한지 한 달차</h4>
<p>자바를 공부하고 2주만에 JDBC를 배웠을 때 부터
지금까지 그만둘까 고민도 많이 했지만..</p>
<blockquote>
<p>어째서인지 슬금슬금 재미를 느끼기 시작했다.</p>
</blockquote>
<p>이론공부보다 프로젝트 실습위주의 학습이 더 체득에 수월했다는 표현이 맞겠다.</p>
<hr>
<h4 id="조금씩-성장-중---">조금씩 성장 중 . . .</h4>
<p>불과 한달 전에는 이해가 가지 않던 코드들이 점차 이해되기 시작했고,
다른분들께 방해가 될까봐 중도포기를 고민했던 내가 팀원들로부터 문제상황해결에대한 질문을 받기 시작하고, 코드를 수정해드리는 일들이 반복되면서</p>
<blockquote>
<p>&quot;아! 그냥 잡생각없이 하니까 되긴 되는구나.&quot;</p>
</blockquote>
<p>싶었다.</p>
<hr>
<h4 id="수료-후-계획">수료 후 계획</h4>
<p>이제서야 CRUD를 겨우 해낸 단계이기에 당장에 취업을 목표로 하는 것이 맞는지는 모르겠다.</p>
<p>수료후에는 7일정도 쉴 예정이고,
안정된 포트폴리오와 협업 프로젝트 경험축적을 원하기 때문에 단기부트캠프 등록을 고민 중이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JPA] Entity Mapping Annotation]]></title>
            <link>https://velog.io/@choi_ho_geun_97/JPA-Entity-Mapping-Annotation</link>
            <guid>https://velog.io/@choi_ho_geun_97/JPA-Entity-Mapping-Annotation</guid>
            <pubDate>Tue, 14 Feb 2023 14:23:39 GMT</pubDate>
            <description><![CDATA[<h3 id="1-entity">1. @Entity</h3>
<blockquote>
<p>@Entity 해당 클래스를 DB테이블과 매핑</p>
</blockquote>
<hr>
<h3 id="2-table">2. @Table</h3>
<blockquote>
<p>엔티티와 매핑할 테이블을 지정</p>
</blockquote>
<table>
<thead>
<tr>
<th>property</th>
<th>description</th>
</tr>
</thead>
<tbody><tr>
<td>name</td>
<td>매핑할 테이블 이름</td>
</tr>
<tr>
<td>catalog</td>
<td>catalog 기능이 있는 DB에서 catalog 매핑</td>
</tr>
<tr>
<td>schema</td>
<td>schema 기능이 있는 DB에서 schema 매핑</td>
</tr>
<tr>
<td>uniqueContraints</td>
<td>DDL생성 시 Unique 제약조건 생성 <br>※ 스키마 자동생성 기능을 사용하여 DDL을 만들 때만 사용함.</td>
</tr>
</tbody></table>
<hr>
<h3 id="3-id">3. @Id</h3>
<blockquote>
<p>특정 속성을 기본키로 설정하는 어노테이션</p>
</blockquote>
<p>@Id만 적을 경우 기본 키를 직접 부여해야함.</p>
<p>@GeneratedValue 어노테이션을 사용하면 기본값을 DB에서 자동으로 생성할 수 있음.</p>
<table>
<thead>
<tr>
<th>property</th>
<th>function</th>
</tr>
</thead>
<tbody><tr>
<td>@GeneratedValue(strategy=GenerationType.IDENTITY)</td>
<td>기본키 생성을 DB에 위임(MySQL)</td>
</tr>
<tr>
<td>@GeneratedValue(strategy=GenerationType.SEQUENCE)</td>
<td>DB시퀀스를 사용하여 기본 키 할당(Oracle)</td>
</tr>
<tr>
<td>@GeneratedValue(strategy=GenerationType.TABLE)</td>
<td>키 생성 테이블 사용(모든 DB)</td>
</tr>
<tr>
<td>@GeneratedValue(strategy=GenerationType.AUTO)</td>
<td>선택된 DB에 따라 자동으로 전략선택</td>
</tr>
</tbody></table>
<hr>
<h3 id="4-column">4. @Column</h3>
<blockquote>
<p>필드속성을 지정할 때 사용</p>
</blockquote>
<table>
<thead>
<tr>
<th>property</th>
<th>description</th>
<th>default</th>
</tr>
</thead>
<tbody><tr>
<td>name</td>
<td>필드명을 지정</td>
<td>객체의 필드이름</td>
</tr>
<tr>
<td>insertable</td>
<td>등록가능여부</td>
<td>true</td>
</tr>
<tr>
<td>updatable</td>
<td>수정가능여부</td>
<td>true</td>
</tr>
<tr>
<td>nullable</td>
<td>DDL 생성 시 설정값에 따라 null가능 여부를 설정</td>
<td>true</td>
</tr>
<tr>
<td>unique</td>
<td>DDl 생성 시 간단하게 한 컬럼에 유니크 제약 조건 설정</td>
<td>false</td>
</tr>
<tr>
<td>columnDefinition</td>
<td>테이블 컬럼 속성을 직접 설정</td>
<td>-</td>
</tr>
<tr>
<td>length</td>
<td>문자길이 제약조건 설정</td>
<td>255</td>
</tr>
<tr>
<td>precision,scale</td>
<td>BigDeciaml, BigInteger 타입에서 사용</td>
<td>0,0</td>
</tr>
</tbody></table>
<hr>
<h3 id="5-temporal">5. @Temporal</h3>
<blockquote>
<p>날짜 타입을 매핑할 때 사용</p>
</blockquote>
<ul>
<li>LocalDate, LocalDateTime 사용 시 생략가능</li>
</ul>
<h3 id="6-enumerated">6. @Enumerated</h3>
<blockquote>
<p>자바 enum 타입을 매핑할 때 사용</p>
</blockquote>
<table>
<thead>
<tr>
<th>이름</th>
<th>description</th>
<th>default</th>
</tr>
</thead>
<tbody><tr>
<td>value</td>
<td>EnumType.ORDINAL</td>
<td>EnumType.ORDINAL</td>
</tr>
<tr>
<td>value</td>
<td>EnumType.String</td>
<td>EnumType.ORDINAL</td>
</tr>
</tbody></table>
<h3 id="7-lob">7. @Lob</h3>
<blockquote>
<p>데이터베이스 BLOB, CLOB타입과 매핑</p>
</blockquote>
<h3 id="8-transient">8. @Transient</h3>
<blockquote>
<p>해당필드를 매핑하지 않음. (테이블과 연관없는 필드를 지정할 때 사용)</p>
</blockquote>
<h3 id="9-onetomany-manytoone">9. @OneToMany, @ManyToOne</h3>
<blockquote>
<p>연관관계 매핑에 관하여 따로 정리하겠음.</p>
</blockquote>
<h3 id="10-access">10. @Access</h3>
<blockquote>
<p>JPA가 엔티티 데이터에 접근하는 방식을 지정</p>
</blockquote>
<table>
<thead>
<tr>
<th>접근방식</th>
<th>기능</th>
</tr>
</thead>
<tbody><tr>
<td>AccessType.FIELD</td>
<td>필드에 직접 접근, 필드 접근 권한이 private여도 접근 가능</td>
</tr>
<tr>
<td>AccessType.PROPERTY</td>
<td>getter를 통해 접근</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[나만보는 JDBC 정리 ++ 수정중]]></title>
            <link>https://velog.io/@choi_ho_geun_97/%EB%82%98%EB%A7%8C%EB%B3%B4%EB%8A%94-JDBC-%EC%A0%95%EB%A6%AC-%EC%88%98%EC%A0%95%EC%A4%91</link>
            <guid>https://velog.io/@choi_ho_geun_97/%EB%82%98%EB%A7%8C%EB%B3%B4%EB%8A%94-JDBC-%EC%A0%95%EB%A6%AC-%EC%88%98%EC%A0%95%EC%A4%91</guid>
            <pubDate>Tue, 07 Feb 2023 17:10:34 GMT</pubDate>
            <description><![CDATA[<h1 id="jdbc란">JDBC란?</h1>
<blockquote>
<p>자바에서 DB에 접속할 수 있도록 하는 자바 API이다.</p>
</blockquote>
<p>SQL에서 연결/인증, 쿼리실행, 결과패치를 수행한다.</p>
<h2 id="구성">구성</h2>
<blockquote>
<p>거의 한 단으로 묶어서 사용한다고한다.</p>
</blockquote>
<ol>
<li>Class.forName(&quot;드라이버&quot;);</li>
<li>Connection con = DriverManager.getConnection(url,아이디,비번);</li>
<li>Statement st = con.createStatement();<ul>
<li>또는 PreparedStatement</li>
</ul>
</li>
<li>ResultSet rs = st.executeQuery(sql);</li>
</ol>
<p>...</p>
<p>n. rs.close();
n+1. st.close();
n+2. con.close();</p>
<blockquote>
<p>기능별로 설명하면 다음과 같다.</p>
</blockquote>
<ol>
<li>JDBC 드라이버 로딩</li>
<li>DBMS 서버 접속</li>
<li>DB가 처리한 결과를 자바프로그램으로 전달할 객체 생성</li>
<li>SQL문 실행</li>
</ol>
<p>n ~ n+2. 사용했던 객체들을 메모리상에서 자원해제</p>
<hr>
<blockquote>
<p>ResultSet 객체가 가지는 SELECT문의 결과값은 ResultSet 객체의 메서드를 활용하여 추출할 수 있다.</p>
</blockquote>
<p>void afterLast();
    - 커서를 빈끝 행으로 이동</p>
<p>void beforeFirst();
    - 커서를 시작 빈행으로 이동</p>
<p>boolean next();
    - 커서다음에 값(레코드)이 있는지 판단하여 없으면 false, 있으면 true를 반환한 다음, 커서를 다음행으로 이동</p>
<pre><code class="language-java">
    if(rs.next()) return ... // 요런 식으로 사용하면 커서가 가르킬 다음 항목이 있는 경우에만 실행된다.

    // while 문을 사용하면 다음 항목이 없을 때 까지 반복할 수 있다.
</code></pre>
<hr>
<h2 id="트랜잭션">트랜잭션</h2>
<blockquote>
<p>하나의 뭉탱이(단위)로 처리되길 바라는 쿼리(업무 수행 단위, 논리적 수행 단위)의 묶음</p>
</blockquote>
<p>트랜잭션 처리란 ACID를 유지하는 것을 말한다.</p>
<p>Atomicity : 원자성
Consistency : 일관성
Isolation : 고립성
Durability : 지속성</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS_FormData.append() 메서드]]></title>
            <link>https://velog.io/@choi_ho_geun_97/JSFormData.append-%EB%A9%94%EC%84%9C%EB%93%9C</link>
            <guid>https://velog.io/@choi_ho_geun_97/JSFormData.append-%EB%A9%94%EC%84%9C%EB%93%9C</guid>
            <pubDate>Thu, 12 Jan 2023 14:44:34 GMT</pubDate>
            <description><![CDATA[<h1 id="formdataappend-메서드">FormData.append() 메서드</h1>
<p>FormData인터페이스의 append()메서드는 객체의 기존 Key에 새로운 Value를 추가하거나, Key값이 없으면 Key값과 함께 객체에 새로 추가해주는 기능을 수행한다.</p>
<p>객체의 key값과 함께 Value를 추가할 때에는 기존 객체의 가장 끝에 값이 추가된다. </p>
<blockquote>
<p>key와 value를 다룰 수 있다는 점에서 원격 API를 통한 JSON객체를 다룰 때 자주 활용되는 듯 싶다. DOM 핸들링에도 자주 사용된다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS_기록]]></title>
            <link>https://velog.io/@choi_ho_geun_97/JS%EA%B8%B0%EB%A1%9D</link>
            <guid>https://velog.io/@choi_ho_geun_97/JS%EA%B8%B0%EB%A1%9D</guid>
            <pubDate>Wed, 04 Jan 2023 14:01:45 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>자바스크립트는 타입추론을 지원한다.</p>
</blockquote>
<h3 id="변수-선언-방식">변수 선언 방식</h3>
<pre><code class="language-javascript">var 변수명; =&gt; es6이전
let 변수명; =&gt; es6이후 변수 선언 방식
const 변수명; =&gt; es6이후 상수 선언 방식</code></pre>
<h3 id="var를-사용하기-껄끄러운-이유">var를 사용하기 껄끄러운 이유</h3>
<blockquote>
<p>변수 호이스팅이 발생하기 때문이다.<br>es6의 <code>let</code>과 <code>const</code>의 등장 이전,
변수의 선언을 <code>var</code>를 사용해야만하던 호랑이 담배피던 시절. . .
변수의 유효범위는 Global Scope와 Function Scope로만 존재했다.</p>
</blockquote>
<p>함수밖에 선언된 변수는 모두 전역변수가 되어버렸기 때문에 코드를 읽어야하는 입장에서는 가독성이 떨어질 수 밖에 없었다.</p>
<pre><code class="language-javascript">console.log(`a : ${a}`); //  undefined !호이스팅
var a = 1;
function variableEx(){
    console.log(`a : ${a}`); // undefined
     var a = 2;
      console.log(`a : ${a}`); // a : 2


}
console.log(`a : ${a}`); // a : 1 </code></pre>
<blockquote>
<p>변수와 함수의 선언만 해당 스코프의 최상단으로 끌어올려지는 것이 호이스팅이다.</p>
</blockquote>
<p>Execution Context의 단계를 나누어 설명하자면</p>
<ol>
<li>선언 : 변수를 실행 컨텍스트의 변수객체에 등록</li>
<li>초기화 : 변수 객체에 등록된 변수를 위한 메모리 공간 확보,(이 때 undefined로 초기화) 메모리가 할당되면 참조를 통해 변수로 접근가능</li>
<li>할당 : 사용자가 정의한 값을 변수에 초기화</li>
</ol>
<p>즉, var키워드로 변수를 생성할 경우, 선언과 초기화단계가 동시에 일어난다.
사용자가 지정한 값이 변수에 초기화 되기 직전단계에서 실행컨텍스트가 undefined로 초기화했기 때문에 저꼴이 나는 것이다.</p>
<blockquote>
<p>CallStack의 실행순서,Execution Context, Lexical Scope를 잘 이해하면 이해에 무리가 없을듯
호이스팅에 대해 완벽히 이해하려면 Execution Context의 생성과정에 대한 깊은 이해가 필요해보인다..</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA_중첩클래스: 선언위치에 따른 분류]]></title>
            <link>https://velog.io/@choi_ho_geun_97/JAVA%EC%A4%91%EC%B2%A9%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%84%A0%EC%96%B8%EC%9C%84%EC%B9%98%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%B6%84%EB%A5%98</link>
            <guid>https://velog.io/@choi_ho_geun_97/JAVA%EC%A4%91%EC%B2%A9%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%84%A0%EC%96%B8%EC%9C%84%EC%B9%98%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%B6%84%EB%A5%98</guid>
            <pubDate>Tue, 03 Jan 2023 13:27:38 GMT</pubDate>
            <description><![CDATA[<h2 id="선언위치에-따른-분류">선언위치에 따른 분류</h2>
<h3 id="멤버클래스">멤버클래스</h3>
<h4 id="인스턴스-멤버-클래스">인스턴스 멤버 클래스</h4>
<pre><code class="language-java">
class A {
    class B{. . .}
}
</code></pre>
<h4 id="객체-생성-조건">객체 생성 조건</h4>
<ul>
<li>A객체를 생성해야만 B객체 생성가능</li>
</ul>
<hr>
<h4 id="정적-멤버-클래스">정적 멤버 클래스</h4>
<pre><code class="language-java">
class A {
    static class B{. . .}
}
</code></pre>
<h4 id="객체-생성-조건-1">객체 생성 조건</h4>
<ul>
<li>A객체를 생성하지 않아도 B객체를 생성할 수 있음</li>
</ul>
<hr>
<h3 id="로컬클래스">로컬클래스</h3>
<pre><code class="language-java">
class A {
    void method(){
    class B{. . .}
    }
}
</code></pre>
<h4 id="객체-생성-조건-2">객체 생성 조건</h4>
<ul>
<li>method()가 실행될 때만 B 객체를 생성할 수 있음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MVC 패턴]]></title>
            <link>https://velog.io/@choi_ho_geun_97/MVC-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@choi_ho_geun_97/MVC-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Mon, 26 Dec 2022 11:19:49 GMT</pubDate>
            <description><![CDATA[<h1 id="mvc">MVC?</h1>
<blockquote>
<p>MVC -&gt; 유지보수가 편해지는 코드구성 방식</p>
</blockquote>
<h2 id="1-model은-controller와-view에-의존하지-않아야한다">1. Model은 Controller와 View에 의존하지 않아야한다.</h2>
<p>(Model 내부에 Controller와 View에 관련된 코드가 있으면 안된다.)</p>
<h2 id="2-view는-model에만-의존해야하고-controller에는-의존하면-안된다">2. View는 Model에만 의존해야하고, Controller에는 의존하면 안된다.</h2>
<p>(View 내부에 Model 코드만 존재할 수 있고, Controller의 코드가 있으면 안된다.)</p>
<h2 id="3-view가-model로부터-데이터를-받을-때-사용자마다-다르게-보여주어야하는-데이터에-대해서만-받아야한다">3. View가 Model로부터 데이터를 받을 때, 사용자마다 다르게 보여주어야하는 데이터에 대해서만 받아야한다.</h2>
<h2 id="4-controller는-model과-view에-의존해도-된다">4. Controller는 Model과 View에 의존해도 된다.</h2>
<p>(Controller 내부에는 Model과 View의 코드가 존재할 수 있다.)</p>
<h2 id="5-view가-model로부터-데이터를-받을-때-반드시-controller에서-받아야한다">5. View가 Model로부터 데이터를 받을 때, 반드시 Controller에서 받아야한다.</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[MySQL 살펴보기_2]]></title>
            <link>https://velog.io/@choi_ho_geun_97/MySQL-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B02</link>
            <guid>https://velog.io/@choi_ho_geun_97/MySQL-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B02</guid>
            <pubDate>Wed, 21 Dec 2022 13:07:16 GMT</pubDate>
            <description><![CDATA[<h2 id="order-by">order by</h2>
<blockquote>
<p>select문에서 result set을 정렬하기 위해 사용하는 구문이다.</p>
</blockquote>
<p>select 문의 가장 <strong>마지막</strong>에 작성하며,
실행순서도 가장 마지막이다.</p>
<hr>
<h3 id="select문의-실행순서">select문의 실행순서</h3>
<blockquote>
<p>from -&gt; where -&gt; group by -&gt; having -&gt; select - order by</p>
</blockquote>
<hr>
<h3 id="asc와-desc">asc와 desc</h3>
<p>asc
오름차순</p>
<p>desc
내림차순</p>
<p>만약 컬럼에 null이 존재한다면 default로 상단에 배치</p>
<pre><code class="language-sql"># 사원들의 이름, 급여 보너스를 조회하되 bonus로 오름차순 정렬

select emp_name, salary, bonus, SAL_LEVEL, DEPT_CODE
from employee
# order by bonus asc; </code></pre>
<hr>
<h2 id="group-by">group by</h2>
<blockquote>
<p>특정 컬럼을 기준으로 그루핑하여 그룹함수를 사용해 원하는 데이터를 추출할 목적으로 사용한다.</p>
</blockquote>
<h3 id="group-함수">group 함수</h3>
<ul>
<li>sum()</li>
<li>count()</li>
<li>avg()</li>
<li>max()</li>
<li>min()</li>
</ul>
<p>select 절에는 그루핑한 기준이되는 컬럼과 그 외 함수의 결과만 올 수 있다.</p>
<pre><code class="language-sql"># 부서별 급여의 총액과 평균 급여를 보자
select dept_code, sum(salary), avg(salary)
from employee
group by DEPT_CODE;


# 부서의 평균급여가 3000000이상인 부서를 조회
select dept_code
from employee
# where avg(SALARY) &gt;= 3000000 : where절이 돌아가는 시점에는 그루핑이 안되어있음
# 개별 탐색을 마친후에 그루핑을 해야한다.
# 때문에 where절에서는 그루핑함수를 못쓴다.

group by DEPT_CODE
having sum(SALARY) &gt;= 3000000;
</code></pre>
<hr>
<h3 id="집계함수-rollup">집계함수 (rollup)</h3>
<blockquote>
<p>with rollup </p>
</blockquote>
<p>그룹별 중간집계와 총집계를 계산한다.</p>
<pre><code class="language-sql">#부서별, 직급별, 연봉레벨별
select dept_code, job_code, SAL_LEVEL, sum(salary), count(*)
from employee
where DEPT_CODE is not null
group by DEPT_CODE, JOB_CODE, SAL_LEVEL with rollup
order by dept_code is null asc
,job_code is null asc
,sal_level is null asc
, dept_code asc
, job_code asc
, sal_level asc;</code></pre>
<p>result set에는 각 부서(그룹)별 합이 출력된다.</p>
<p>다만, 데이터의 양이 많으면 그룹별로 집계된 값에대한 가독성이 현저히 떨어진다.</p>
<p>이런상황을 타개하려면 grouping 함수를 사용하면 된다.</p>
<h3 id="grouping-함수">grouping 함수</h3>
<blockquote>
<p>grouping (Columns_name)</p>
</blockquote>
<p>해당 row의 집계값이 인자로 전달받은 columns set의 산출물이면 0,
아니면 1을 갖는다.</p>
<p>내가 보고있는 그룹이 어디에 그루핑된건지 알아야할 때 쓴다.</p>
<pre><code class="language-sql">select dept_code, job_code, SAL_LEVEL, sum(salary), count(*)
    ,grouping(dept_code)
    ,grouping(job_code)
    ,grouping(SAL_LEVEL)
from employee
where DEPT_CODE is not null
group by DEPT_CODE, JOB_CODE, SAL_LEVEL with rollup
order by dept_code is null asc
,job_code is null asc
,sal_level is null asc
, dept_code asc
, job_code asc
, sal_level asc;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[MySQL 살펴보기]]></title>
            <link>https://velog.io/@choi_ho_geun_97/MySQL-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@choi_ho_geun_97/MySQL-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Wed, 21 Dec 2022 12:45:09 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>테이블에서 원하는 조건의 데이터를 조회한 결과를 result set (결과집합)이라고한다.</strong></p>
</blockquote>
<h3 id="작성법">작성법</h3>
<pre><code class="language-sql">select column_name
from table_name
where condition;</code></pre>
<p>생성할 컬럼(열)이름, 데이터를 가져올 테이블이름, 조건문 순으로 작성한다.</p>
<h2 id="연산자">연산자</h2>
<p>타언어와 거의 유사한 연산자를 가지고있다.</p>
<h3 id="산술연산자">산술연산자</h3>
<p>+, -, *, /, %</p>
<h3 id="비교연산자">비교연산자</h3>
<p>&lt;, &gt;, &lt;=, &gt;=, =, !=, &lt;&gt;</p>
<h3 id="논리연산자">논리연산자</h3>
<p>and, or, not</p>
<h3 id="연산자-우선순위">연산자 우선순위</h3>
<p>적용된다.</p>
<hr>
<h4 id="컬럼-별칭">컬럼 별칭</h4>
<p>변수 지정하듯이 별칭을 지정할 수 있다.</p>
<p>컬럼명 as 별칭,
컬럼명 별칭,
컬럼명 as &#39;별칭&#39;,
컬럼명 &#39;별칭&#39;</p>
<hr>
<h4 id="distinct">distinct</h4>
<ul>
<li>result set에서 중복된 row를 제거한다.
ex) 근로자 테이블에서 부서코드 조회, 중복제거<pre><code class="language-sql">select distinct dept_code
from employee;</code></pre>
</li>
</ul>
<hr>
<h4 id="and">and</h4>
<pre><code class="language-sql"># 1. employee 테이블에서 부서코드가 D6, 급여를 200만원 이상 받는 직원의 이름, 부서코드 급여 조회

select emp_name, dept_code, salary
from employee
where DEPT_CODE = &#39;D6&#39; and SALARY &gt;= 2000000;</code></pre>
<h4 id="or">or</h4>
<pre><code class="language-sql"># 2. employee테이블에서 부서코드가 D9 이거나 D5인 사원 중
# 급여를 400만원 이상 받는 모든 사원을 조회하시오

select emp_name, DEPT_CODE, SALARY
from employee
where (DEPT_CODE = &#39;D9&#39; or DEPT_CODE = &#39;D5&#39;) and SALARY &gt;= 4000000;</code></pre>
<hr>
<h4 id="between">between</h4>
<blockquote>
<p><strong>between A and B</strong> : 이상 이하 표현식</p>
</blockquote>
<pre><code class="language-sql"># 3. employee테이블에서 월급이 350만원 이상, 600만원 이하에 속하지 않는 사원들의 모든 정보를 조회
select emp_name, salary
from employee
where Not (SALARY between 3500000 and 6000000);</code></pre>
<hr>
<h4 id="날짜-데이터">날짜 데이터</h4>
<blockquote>
<p>날짜데이터는 비교연산이 가능하다.</p>
</blockquote>
<hr>
<h4 id="like">like</h4>
<blockquote>
<p>문자열의 특정데이터 포함여부를 확인</p>
</blockquote>
<p>컬럼값의 like 절에서 지정한 패턴을 만족하는 문자열이 있다면  true</p>
<h5 id="like패턴-작성법">like패턴 작성법</h5>
<p>컬럼명 like &#39;패턴&#39;
패턴문자는 &#39;%&#39;이다.</p>
<p>&#39;A%&#39; : A로 시작하는
&#39;%A&#39; : A로 끝나는
&#39;%A%&#39;: A를 포함하는</p>
<pre><code class="language-sql"># employee 테이블에서 성이 이씨이고 입사일이 12-01-01 이후인 사원의 사번,이름,고용일 조회

select emp_id, emp_name, hire_date
from employee
where EMP_NAME like &#39;이%&#39;
and HIRE_DATE &gt; &#39;12-01-01&#39;;</code></pre>
<h5 id="like의-와일드카드-_">like의 와일드카드 &#39;_&#39;</h5>
<p>like절의 와일드카드 &#39;_&#39;</p>
<blockquote>
<p>_에는 어떤 문자가 와도 상관없다.</p>
</blockquote>
<pre><code class="language-sql"># employee 테이블에서 전화번호의 뒤에서 4번째 자리가 9인 사원의 이름, 전화번호 조회
select emp_name, phone
from employee
where phone like &#39;%9___&#39;;</code></pre>
<p>위 코드처럼 뒤에서부터 4번째 자리까지 도달하는 3개의 자리에 &#39;_&#39;을 기입한다.</p>
<hr>
<h4 id="in">IN</h4>
<blockquote>
<p>컬럼값이 목록에 있으면 true</p>
</blockquote>
<pre><code class="language-sql">#직급코드가 &#39;J7&#39; 또는 &#39;J2&#39;인 직원 중 급여가 200만원 이상인 직원의 이름, 급여, 직급코드를 조회

select emp_name, salary, JOB_CODE
from employee
where JOB_CODE in(&#39;J7&#39;,&#39;J2&#39;)
and SALARY &gt;= 2000000;</code></pre>
<h4 id="is-null">is null</h4>
<blockquote>
<p>컬럼값이 null인지 확인</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA_StringJoiner&join()]]></title>
            <link>https://velog.io/@choi_ho_geun_97/JAVAStringJoinerjoin</link>
            <guid>https://velog.io/@choi_ho_geun_97/JAVAStringJoinerjoin</guid>
            <pubDate>Thu, 15 Dec 2022 12:16:12 GMT</pubDate>
            <description><![CDATA[<h2 id="join">join()</h2>
<p>여러개의 문자열사이에 구분자를 넣어 결합한다.</p>
<pre><code class="language-java">String animals = &quot;dog,cat,bear&quot;;
String[] arr = animals.split(&quot;,&quot;);
String str = String.join(&quot;-&quot;,arr);

// 실행결과 &quot;dog-cat-bear&quot;</code></pre>
<h2 id="stringjoiner">StringJoiner</h2>
<p>구분자로 구분하고 지정한 문자열로 감싼다.
StringJoiner(구분자,첫번째 문자열,마지막 문자열)</p>
<pre><code class="language-java">        StringJoiner sj = new StringJoiner(&quot;,&quot;, &quot;[&quot;, &quot;]&quot;);
        String[] strarr = {&quot;aaa&quot;,&quot;bbb&quot;,&quot;ccc&quot;};

        for (String s : strarr) {
            sj.add(s.toUpperCase());
        }System.out.println(sj.toString());
// 실행결과 [AAA,BBB,CCC]</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA_String클래스]]></title>
            <link>https://velog.io/@choi_ho_geun_97/JAVAString%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@choi_ho_geun_97/JAVAString%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Thu, 15 Dec 2022 12:03:31 GMT</pubDate>
            <description><![CDATA[<h1 id="string클래스">String클래스</h1>
<h2 id="생성자와-메서드">생성자와 메서드</h2>
<ul>
<li>String(String s)<pre><code class="language-java">String s = new String(&quot;안녕&quot;)</code></pre>
</li>
</ul>
<hr>
<ul>
<li>String(char[] value)<pre><code class="language-java">char[] c = {&#39;H&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;};
String s = new String(c);
</code></pre>
</li>
</ul>
<p>// 실행결과 s = &quot;Hello&quot;</p>
<pre><code>
---


- String(StringBuffer buf)
```java
StringBuffer sb = new StringBuffer(&quot;Hello&quot;);
String s = new String(sb);

// 실행결과 s = &quot;Hello&quot;</code></pre><hr>
<ul>
<li>char charAt(int index)<pre><code class="language-java">String s = &quot;Hello&quot;;
String n = &quot;12345&quot;;
char c1 = s.charAt(1);
char c2 = n.charAt(1);
</code></pre>
</li>
</ul>
<p>// 실행결과 c1 = e c2 = 0</p>
<pre><code>
---

- int compareTo(String str)
```java
int i = &quot;aaa&quot;.compareTo(&quot;aaa&quot;)
int i2 = &quot;aaa&quot;.compareTo(&quot;bbb&quot;)
int i3 = &quot;bbb&quot;.compareTo(&quot;aaa&quot;)
// 실행결과  i = 0, i2 = -1, i3 = 1</code></pre><hr>
<ul>
<li>String concat(String str)<pre><code class="language-java">String s = &quot;Hello&quot;;
String s2 = s.concat(&quot;World&quot;);
// 실행결과  s2 = &quot;HelloWorld&quot;</code></pre>
</li>
</ul>
<hr>
<ul>
<li>boolean contains(CharSequence s)<pre><code class="language-java">String s = &quot;abcdefg&quot;;
boolean b = s.contains(&quot;bc&quot;);
</code></pre>
</li>
</ul>
<p>// 실행결과 b = true</p>
<pre><code>
---

- boolean endsWith(String suffix)
```java
String file = &quot;Hello.txt&quot;;
boolean b = file.endWith(&quot;txt&quot;);

// 실행결과 true</code></pre><hr>
<ul>
<li>boolean equals(Object obj)<pre><code class="language-java">String s = &quot;Hello&quot;;
boolean b = s.equals(&quot;Hello&quot;);
boolean c = s.equals(&quot;hello&quot;);
</code></pre>
</li>
</ul>
<p>// 실행결과 b = true, c = fasle</p>
<pre><code>
---

- boolean equalsIgnoreCase(String str)
```java
String s = &quot;Hello&quot;;
boolean b = s.equalsIgnoreCase(&quot;Hello&quot;);
boolean c = s.equalsIgnoreCase(&quot;hello&quot;);

// 실행결과 b = true, c = true</code></pre><hr>
<ul>
<li>int indexOf(int ch)<pre><code class="language-java">String s = &quot;Hello&quot;;
int idx1 = s.indexOf(&#39;O&#39;);
int idx2 = s.indexOf(&#39;k&#39;);
</code></pre>
</li>
</ul>
<p>// 실행결과  idx1 = 4, idx2 = -1</p>
<pre><code>
---

- int indexOf(int ch, int pos)
```java
String s = &quot;Hello&quot;;
int idx1 = s.indexOf(&#39;e&#39;, 0);
int idx2 = s.indexOf(&#39;e&#39;, 2);

// 실행결과 idx1 = 1, idx2 = -1</code></pre><hr>
<ul>
<li>int indexOf(String str)<pre><code class="language-java">String s = &quot;ABCDEFG&quot;
int idx = s.indexOf(&quot;CD&quot;);
</code></pre>
</li>
</ul>
<p>// 실행결과 idx = 2</p>
<pre><code>
---

- String intern()
```java
String s = new String(&quot;abc&quot;);
String s2 = new String(&quot;abc&quot;);
boolean b = (s == s2);
boolean b2 = s.equals(s2);
boolean b3 = (s.intern() == s2.intern());

// 실행결과 b1 = false, b2 = true, b3 = true</code></pre><blockquote>
<p>분명 equals는 두 객체가 같은지 판단한다고했다.
s와 s2의 객체가 같은 이유가 뭘까?
String() 클래스로 같은 값을 선언하면 같은 객체이다.
hashCode()를 출력하여 결과를 비교해보면 알 수 있다.</p>
</blockquote>
<hr>
<ul>
<li>int lastIndexOf(int ch)<pre><code class="language-java">String s = &quot;java.lang.Object&quot;;
int idx1 = s.lastIndexOf(&#39;.&#39;);
int idx2 = s.indexOf(&#39;.&#39;);
</code></pre>
</li>
</ul>
<p>// 실행결과 idx1 = 9, idx2 = 4</p>
<pre><code>- int lastIndexOf(String str)
    매개변수만 다를 뿐 lastIndexOf()와 같은 기능을 제공한다.


---

- int length()
    길이를 알려준다.

---

- String replace(char old, char nw)
```java
String s = &quot;Hello&quot;;
String s1 = s.replace(&#39;H&#39;,&#39;C&#39;);

// 실행결과 s1 = &quot;Cello&quot;</code></pre><ul>
<li><p>String replace(CharSequence old, CharSequence nw)</p>
<ul>
<li>문자열 중 old문자열을 nw문자열로 <strong>모두</strong> 바꾼 문자열을 반환한다.</li>
</ul>
</li>
<li><p>String replaceAll(String regex, String replacement)</p>
<ul>
<li>문자열 중에서 지정된 regex와 일치하는 모든 문자열을 새로운 문자열로 바꾼다.</li>
</ul>
</li>
<li><p>String replaceFirst(String regex, String replacement)</p>
<ul>
<li>regex와 일치하는 문자열 중 첫번째 것만 새로운 문자열로 바꾼다.</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>String[] split(String regex)<pre><code class="language-java">String animals = &quot;dog,cat,bear&quot;;
String[] arr = animals.split(&quot;,&quot;);
</code></pre>
</li>
</ul>
<p>// 실행결과 arr[0] = &quot;dog&quot;, arr[1] = &quot;cat&quot;, arr[2] = &quot;bear&quot;</p>
<pre><code>- String[] split(String regex, int limit)
  - 문자열을 지정된 분지라(regex)로 나누어 배열에 반환한다. 단, 문자열 전체를 지정된 수(limit)로 자른다.

---

- boolean startWith(String prefix)
  - 주어진 문자열로 시작하는지 반환한다.

---

- String substring(int begin)
- String substring(int begin, int end)
  - 주어진 시작위치부터 끝위치까지 범위에 포함된 문자열을 얻는다.
  시작위치의 문자는 범위에 포함되지만 끝위치의 문자는 범위에 포함되지 않는다. (begin &lt;= x &lt; end)
```java
String s = &quot;java.lang.Object&quot;;
String c = s.substring(10);
String p = s.substring(5,9);

// 실행결과 c = &quot;Object&quot;, p = &quot;lang&quot;</code></pre><hr>
<ul>
<li>String toLowerCase()<ul>
<li>모든 문자열을 소문자로 반환 and 반환</li>
</ul>
</li>
<li>String toUpperCase()<ul>
<li>모든 문자열을 대문자로 변환 and 반환</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>String toString()<ul>
<li>String 인스턴스에 저장되어있는 문자열을 반환</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>String trim()<ul>
<li>문자열의 왼쪽끝과 오른쪽 끝에 있는 공백을 없앤 결과를 반환
단, 문자열 중간의 공백은 제거되지않는다.</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>static String valueOf(type)<ul>
<li>지정된 값을 문자열로 변환 and 반환</li>
</ul>
</li>
</ul>
<hr>
<p>매개변수만 다른 메서드들도 있기때문에 어렵지않다.</p>
<p>기억안날땐 문서 참고하자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA_Object클래스]]></title>
            <link>https://velog.io/@choi_ho_geun_97/JAVAObject%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@choi_ho_geun_97/JAVAObject%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Wed, 14 Dec 2022 15:07:57 GMT</pubDate>
            <description><![CDATA[<h1 id="object클래스">Object클래스</h1>
<blockquote>
<p>object클래스는 모든 클래스의 조상클래스이다.
덕분에 모든 클래스에서 바로 사용가능하다.</p>
</blockquote>
<h2 id="object-클래스의-메서드">Object 클래스의 메서드</h2>
<pre><code class="language-java">protected Object clone() // 객체 자신의 복사본을 return
public boolean equals(Object obj) // 객체 자신과 객체 obj가 같은 객체인지 비교한다. 같으면 true
protected void finalize() // 객체가 소멸될 때 가비지 컬렉터에 의해 자동호출된다. 이 때 수행되어야 하는 코드가 있을 때 오버라이딩한다. (거의 안씀)
public Class getClass() // 객체 자신의 클래스 정보를 담고있는 Class인스턴스를 return
public int hashCode() // 객체 자신의 해시코드를 return
public String toString // 객체 자신의 정보를 문자열로 return

public void notify() // 객체 자신을 사용하려고 기다리는 쓰레드를 하나만 깨움
public void notifyAll() // 다깨움

public void wait() // 다른 쓰레드가 notify()나 notifyAll()을 호출할 때까지 무한히 or 지정된 시간(time, nanos)동안 기다리게 한다.
public void wait(longtime) // &quot;
public void wait(longtime, nanos) // &quot;</code></pre>
<p>Object클래스는 위 11개의 메서드만 가지고 있다.</p>
<p>이 중 가장 많이 쓰이는 메서드를 정리하려한다.</p>
<h3 id="equalsobject-obj">equals(Object obj)</h3>
<pre><code class="language-java">public class Obj_Equals {

    public static void main(String[] args) {
        Person p1 = new Person(1414124123123L);
        Person p2 = new Person(1414124123123L);

        if(p1 == p2) { // 두 인스턴스가 바라보는 참조변수가 서로 다르다.
            System.out.println(&quot;p1 과 p2는 같은 사람입니다.&quot;);
        } else {
            System.out.println(&quot;p1 과 p2는 다른 사람입니다.&quot;);
        }

        if(p1.equals(p2)) { // 같은 참조변수를 바라보고있다. equsls() 는 오버라이딩되어 두 인스턴스의 타입을 비교한 뒤 true 이면 id와 매개변수의 id를 비교한다.
            System.out.println(&quot;p1 과 p2는 같은 사람입니다.&quot;);
        } else {
            System.out.println(&quot;p1 과 p2는 다른 사람입니다.&quot;);
        }


    }

}

class Person{
    long id; // 

    // equals 메서드 오버라이딩, 재정의 하였다.
    public boolean equals(Object obj) {
        if(obj != null &amp;&amp; obj instanceof Person) { // obj가 null 이외의 값을 가지면서, Person 타입일 때.
            return id == ((Person)obj).id; // true, this.id와 Person타입으로 long타입으로 형변환된 매개변수obj.id를 비교한다.
        } else {
            return false; 
        }
    }

    public Person(long id) { // long타입의 id를 매개변수로 갖는 Person 메서드
        this.id = id; // 매개변수를 this.id에 초기화한다.
    }


}</code></pre>
<blockquote>
<p><strong>여기서 눈여겨볼것은
비교대상간의 비교 전에 타입을 일치시켜줘야한다는 것.</strong></p>
</blockquote>
<hr>
<h3 id="hashcode">hashCode()</h3>
<p>equals()와 유사하게 객체의 변수값을 비교해야한다면,
hashCode()도 오버라이딩 해야하는데</p>
<p>일반적으로는 해시코드가 같은 두객체가 존재하는 것이 가능하다.
하지만 <strong>Object클래스의 hashCode() 메서드에서는 객체의 주소값을 이용해 해시코드를 반환</strong>하기 때문에 서로 다른 객체는 같은 해시코드를 가질 수 없다.</p>
<p>때문에 적절히 오버라이딩 해야한다.</p>
<p>오버라이딩을 안하면?
원래 Object클래스에 정의된대로 모든 해시코드가 각기 다른 값을 가지게 된다.</p>
<pre><code class="language-java">public class Obj_HashCode {

    public static void main(String[] args) {

        String str1 = new String(&quot;ABC&quot;);
        String str2 = new String(&quot;ABC&quot;);

        System.out.println(str1.equals(str2));
        System.out.println(str1.hashCode()); // override가 가능한 Object의 hashCode
        System.out.println(str2.hashCode()); // str1과 str2는 같은 객체를 참조한 같은 문자열을 가진다, hashCode의 값이 같다.

        System.out.println(System.identityHashCode(str1)); // 고유한 hashCode를 return
        System.out.println(System.identityHashCode(str2)); // 출력해보면 str1과str2는 상이함.

        // 어쨋거나 실무에서 원하는 것은 두 인스턴스를 오차없이 비교하는 것이다.
        // String클래스를 상속받는 hashCode()는 문자열이 같으면 동일한 해시코드를 반환
        // identityHashCode는 객체의 주소값으로 해시를 생성



    }

}</code></pre>
<hr>
<h3 id="tostring">toString()</h3>
<p>이 메서드는 인스턴스에 대한 정보를 문자열로 반환한다.</p>
<p>toString은 항상 오버라이딩 되어야한다.</p>
<p>Object클래스에 정의된 toString은 아래와 같다.</p>
<pre><code class="language-java">    public String toString() {
        return getClass().getName() + &quot;@&quot; + Integer.toHexString(hashCode());
    }</code></pre>
<p>만약 오버라이딩하지 않고 그대로 가져다 사용하면,
16진수의 해시코드를 마주하게된다.</p>
<pre><code class="language-java">    public static void main(String[] args) {


        String country = new String(&quot;Korea&quot;);
        java.util.Date today = new java.util.Date();

        System.out.println(country); // korea 
        System.out.println(country.toString()); // korea 
        System.out.println(today); // today
        System.out.println(today.toString()); // today

    }</code></pre>
<p>String 클래스의 toString()은 인스턴스가 갖고있는 문자열을 return하도록 overriding되어있다.</p>
<p>Date 클래스의 경우 Date인스턴스가 갖고있는 날짜와 시간을 문자열로 return하도록 overriding되어있다.</p>
<blockquote>
<p>toString()은 인스턴스나 클래스에 대한 정보, 인스턴스변수의 값을 문자열로 변환하여 return하도록 overriding하는것이 일반적이다.</p>
</blockquote>
<pre><code class="language-java">public class Card {
    String kind;
    int number;

     Card() {
         this(&quot;Spade&quot;,1); 
    }

    public Card(String kind, int number) {
        this.kind = kind;
        this.number = number;
    }
    @Override
    public String toString() {
        return &quot;Card [kind=&quot; + kind + &quot;, number=&quot; + number + &quot;]&quot;;
    }
}

class CardToString {
    public static void main(String[] args) {
        Card c1 = new Card();
        Card c2 = new Card(&quot;Heart&quot;,10);

        System.out.println(c1);
        System.out.println(c2);

    }
}</code></pre>
<p>Card클래스의 toString을 오버라이딩했다.</p>
<hr>
<h3 id="clone">clone()</h3>
<p>자신을 복제하여 새로운 인스턴스를 생성하는 메서드이다.</p>
<p>원형을 보존하고 새로운 클론을 생성하여 변경 전의 값을 참고하는데 도움을 준다.</p>
<p>단, 인스턴스 변수의 값만을 복제하기에 참조타입의 인스턴스 변수가 있다면 완벽히 복제되지 않는다.</p>
<pre><code class="language-java">
import java.awt.Point;

// cloneable 인터페이스 구현
public class Obj_clone implements Cloneable{ // 클론 구현시 Cloneable을 반드시 implements 구현해줘야한다. 안해주면 예외발생한다.

    int x, y;

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



    @Override
    public String toString() {
        return &quot;Obj_clone [x=&quot; + x + &quot;, y=&quot; + y + &quot;]&quot;;
    }

    public Object clone() { // 접근제한자를 protected에서 public 으로 변경.
        Object obj = null;
        try {
            obj = super.clone();  // 조상클래스의 클론 호출
        } catch (CloneNotSupportedException e) {}// clone은 반드시 예외처리해주어야한다.
        return obj;
    }
}

class CloneEX1{
    public static void main(String[] args) {
        Point original = new Point(2, 6);
        Point copy = (Point)original.clone();
        System.out.println(original);
        System.out.println(copy);
    }

}
</code></pre>
<p>주의할 것.</p>
<ul>
<li>cloneable 인터페이스 구현</li>
<li>clone() 오버라이딩 할 때 접근제한자는 public</li>
<li>반드시 예외처리할 것.(CloneNotSupportedException)</li>
</ul>
<h4 id="얕은복사와-깊은복사-이슈">얕은복사와 깊은복사 이슈</h4>
<p>clone은 단순히 객체에 담긴 값만을 복사하기 때문에 
객체 배열을 복제하는 경우에는 원본과 복제본이 같은 값을 공유하므로,
완전한 복사라고 보기어렵다.</p>
<p>이를 얕은복사라고한다.</p>
<p>반면,
원본이 참조하고 있는 객체까지 복사하는 것을 깊은복사라고 칭한다.
깊은복사에서는 원본과 복사본이 서로 다른 객체를 참조하기 때문에 원본의 값변경이 복사본에 영향을 주지 않는다.</p>
<p><strong>매우 중요하다.</strong></p>
<hr>
<h3 id="getclass">getClass</h3>
<p>getClass는 자신이 속한 클래스의 Class객체를 반환한다.</p>
<h3 id="class-객체를-얻는-방법">Class 객체를 얻는 방법</h3>
<ul>
<li>생성된 객체로부터 얻는 방법</li>
<li>클래스 리터럴로부터 얻는 방법</li>
<li>클래스 이름으로부터 얻는 방법</li>
</ul>
<pre><code class="language-java">Class Iobj = new Card().getClass(); // 생성된 객체로부터 얻기
Class Oobj = Card.class; // 리터럴로 얻기
Class Kobj = Class.forName(&quot;card&quot;); // 클래스 이름으로 얻기
</code></pre>
<p>일어나서 String Class 공부하기</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA_예외처리_finally]]></title>
            <link>https://velog.io/@choi_ho_geun_97/JAVA%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%ACfinally</link>
            <guid>https://velog.io/@choi_ho_geun_97/JAVA%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%ACfinally</guid>
            <pubDate>Tue, 13 Dec 2022 14:54:06 GMT</pubDate>
            <description><![CDATA[<h2 id="finally">finally</h2>
<blockquote>
<p><strong>finally블럭은 try-catch문과 함께 사용된다.</strong></p>
</blockquote>
<p>단, 예외의 발생여부와는 관계없이 실행되어야할 코드를 포함한다.</p>
<h3 id="syntax">Syntax</h3>
<pre><code class="language-java">try {    // 예외가 발생할 가능성이 있는 문장
    . . .
} 
catch(Exception3 e){    // 예외발생 시 처리를 위한 문장
    . . .
} 
finally{    // 예외와 관계없이 항상 실행되어야 할 문장
    . . .
} </code></pre>
<h3 id="예시코드_1">예시코드_1</h3>
<pre><code class="language-java">public class FinallyTest {

    public static void main(String[] args) {
        try {
            startInstall();        // 프로그램 설치 메서드
            copyFiles();        // 파일복사 메서드
            deleteTempFiles();    // 프로그램 설치에 사용된 임시파일 삭제 메서드
        } catch (Exception e) {
            e.printStackTrace();
            deleteTempFiles();    // 프로그램 설치에 사용된 임시파일 삭제
        }
    }
    static void startInstall() {
        /*    프로그램 설치에 필요한 파일을 준비하는 코드 */
    }
    static void copyFiles() {
        /*    파일들을 복사하는 코드 */
    }
    static void deleteTempFiles() {
        /*    임시파일을 삭제하는 코드 */
    }
}</code></pre>
<p>위 코드의 경우 deleteTempFiles()가 여러 번 겹친다.
deleteTempFiles()는 예외발생여부에 관계없이 실행되어야하므로
다음과 같이 finally블럭을 사용해준다.</p>
<h3 id="예시코드_2">예시코드_2</h3>
<pre><code class="language-java">public class FinallyTest {

    public static void main(String[] args) {
        try {
            startInstall();        // 프로그램 설치 메서드
            copyFiles();        // 파일복사 메서드
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            deleteTempFiles();    // 프로그램 설치에 사용된 임시파일 삭제
        }
    }
    static void startInstall() {
        /*    프로그램 설치에 필요한 파일을 준비하는 코드 */
    }
    static void copyFiles() {
        /*    파일들을 복사하는 코드 */
    }
    static void deleteTempFiles() {
        /*    임시파일을 삭제하는 코드 */
    }
}
</code></pre>
<p>중복을 제거할 수 있다.</p>
<h4 id="주의">주의</h4>
<p>try문에 return문이 실행되어 메서드가 종료되는 경우에도
finally블럭의 문장들이 먼저 실행된 뒤 종료된다.</p>
<p>catch문에서 return문을 만나도 마찬가지이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA_예외처리(exception_handling)(2)]]></title>
            <link>https://velog.io/@choi_ho_geun_97/JAVA%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%ACexceptionhandling2</link>
            <guid>https://velog.io/@choi_ho_geun_97/JAVA%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%ACexceptionhandling2</guid>
            <pubDate>Tue, 13 Dec 2022 13:43:04 GMT</pubDate>
            <description><![CDATA[<h2 id="메서드에-예외선언하기">메서드에 예외선언하기</h2>
<h3 id="예시코드_1">예시코드_1</h3>
<pre><code class="language-java">public static void main(String[] args) throws Exception{
        method1();
    }

    private static void method1() throws Exception{
        method2();
    }

    private static void method2() throws Exception{
        throw new Exception();
    }</code></pre>
<p>메인 메서드에서 Exception을 throws 한다는 것은 반드시 처리해야하는 Exception이라는 의미이다.</p>
<p>예외를 전달받은 메서드가 예외를 처리하지 못하면 자신을 호출한 메서드(호출스택에 있는 메서드)를 따라 전달되다가 제일 마지막에 위치한 main메서드로 예외를 전달하고,
main메서드도 예외를 처리하지 못하면,
main메서드까지 종료되며 프로그램이 종료된다.</p>
<p>위 코드를 실행결과를 통해 다음과 같은 사실을 파악할 수 있다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/choi_ho_geun_97/post/1c97cf94-deb0-4848-adcc-573267899e08/image.png" alt=""></p>
<hr>
<ul>
<li><p>예외 발생 후 
method2, method1, main 메서드가 호출(스택)되었으며,
예외가 발생한 곳은 method2 부터 method1, main 순이다.</p>
</li>
<li><p>method2가 의도적으로 발생시킨 예외는 try catch문을 통해 처리하지 않았으므로 예외가 자신을 호출한 method1에게 전달된다.</p>
</li>
<li><p>method1도 마찬가지로 예외처리를 해주지 않았으므로 main메서드에 예외를 넘겨주며
마지막으로 예외를 넘겨받은 main메서드도 처리할 방법이 선언되지 않았으므로 강제 종료된다.</p>
</li>
</ul>
<blockquote>
<p>예외가 발생한 메서드에서 처리를 하지 않고 throw로 자신을 호출한 메서드에 예외를 넘기면
해당 예외를 넘겨받은 메서드에서 처리를 해줘야한다.</p>
</blockquote>
<hr>
<h3 id="예시코드_2">예시코드_2</h3>
<pre><code class="language-java">
    public static void main(String[] args) {
        method1();
    }

    static void method1() {
        try {
            throw new Exception(); // 임의로 예외 발생
        }catch(Exception e) { // Exception 타입의 참조변수 e 선언
            System.out.println(&quot;예외가 처리됨&quot;); // 예외처리 시 출력될 문구
            e.printStackTrace(); // 예외에 대한 정보를 화면에 출력하는 메서드
        }

    }</code></pre>
<p>try문에서 임의로 예외를 발생시키고,
catch문을 통해 예외에 대한 처리를 진행한다.</p>
<hr>
<h3 id="예시코드_3">예시코드_3</h3>
<pre><code class="language-java">    public static void main(String[] args) {
        try {
            method1();
        } catch (Exception e) { // 예외 캐치
            System.out.println(&quot;main 메서드에서 예외가 처리됨&quot;);
            e.printStackTrace(); // 에러 메시지 출력
        }
    }

    private static void method1() throws Exception{
        throw new Exception(); // 임의로 에러 발생
    }</code></pre>
<p>예시코드 2와 예시코드 3은 둘 다 method1에서 예외가 발생한다.</p>
<p>하지만 처리방법은 상이하다.</p>
<p>예시코드 2는 main메서드가 method1을 호출하고 method1은 본인의 영역 내에서 자체적으로 예외를 처리하기 때문에 main메서드는 예외발생 여부를 알 턱이 없다.</p>
<p>반면 
예시코드3에서 method1은 throws를 통해 자신을 호출한 메서드로 예외를 넘겨준다.
예외를 넘겨받은 main메서드는 예외와 일치하는 catch문을 실행시킨다. </p>
<p>처리방법은 그때그때 상황에 맞게 사용하자.</p>
<hr>
<h3 id="예시코드_4">예시코드_4</h3>
<pre><code class="language-java">import java.io.File;

public class ExceptionEX16 {
    public static void main(String[] args) {
        try {
            File f = createFile(&quot;&quot;); // 얘기 정상적으로 실행되어야 밑 syso코드가 실행된다. 예외가 발생하면 바로 catch블록으로 간다.
            System.out.println(f.getName()+&quot;파일이 성공적으로 생성되었습니다.&quot;);
        } catch (Exception e) {
            e.getStackTrace();
            System.out.println(e.getMessage()+&quot;파일명을 다시 입력하세요.&quot;);
        }
    }
    static File createFile (String fileName) throws Exception{
        if(fileName == null || fileName.equals(&quot;&quot;)) { // 파일 이름이 null값이거나 공백이면
            throw new Exception(&quot;파일이 유요하지 않습니다.&quot;);
        }

        File f = new File(fileName); // File클래스의 객체 생성
        f.createNewFile(); // File 객체의 createNewfile 메서드를 이용하여 실제 파일 생성
        return f;
    }
}
</code></pre>
<p>위 코드는 main메서드가 createFile메서드로부터 예외를 넘겨받아 자체적으로 처리하는 코드이다.</p>
<blockquote>
<p>예시코드를 치며 문득 든 생각은
&quot;메인메서드의 try부분의 첫코드에서 메서드를 받아 처리하면 더 다채로운 예외처리는 하지 못할 것 같다.&quot; 라고 생각했는데 <strong>내 생각이 틀렸다.</strong></p>
</blockquote>
<p>오히려 main메서드의 try구분에서 다른 메서드들을 넘겨받아, 메서드를 하나씩 실행시켜가면서 예외를 파악하는 편이 객체지향적이라고 느꼈다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA_예외처리(exception_handling)(1)]]></title>
            <link>https://velog.io/@choi_ho_geun_97/JAVA%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%ACexceptionhandling</link>
            <guid>https://velog.io/@choi_ho_geun_97/JAVA%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%ACexceptionhandling</guid>
            <pubDate>Tue, 13 Dec 2022 10:51:08 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>프로그램이 오동작하거나 비정상적으로 종료되는 경우가 있다.
이런 경우를 에러 또는 오류라고 한다.</p>
</blockquote>
<h3 id="에러의-종류">에러의 종류</h3>
<h4 id="컴파일-에러">컴파일 에러</h4>
<ul>
<li>컴파일 시 발생하는 에러<h4 id="런타임-에러">런타임 에러</h4>
</li>
<li>실행 시 발생하는 에러<h4 id="논리적-에러">논리적 에러</h4>
</li>
<li>실행은 되지만 의도와 다르게 작동하는 것</li>
</ul>
<hr>
<p>자바는 실행 시 발생할 수 있는 오류를 두 가지로 구분하였다.
에러와 예외이다.</p>
<p>에러는 <strong>메모리부족</strong>(OutOfMemoryError)이나 스택오버플로우(StackOverflowError)와 같이 일단 발생하면 복구될 수 없는 심각한 오류이다.</p>
<p>반면 예외는 발생하더라도 수습이 가능하다.</p>
<h2 id="예외클래스">예외클래스</h2>
<p>자바는 실행 시 발생할 수 있는 모든 오류(Exception과 Error)를 클래스로 정의하였다.
Exception클래스와 Error클래스는 Object의 자손이다.</p>
<p>모든 예외의 최고 조상클래스는 Exception 클래스이다</p>
<pre><code>Exception
    - IOException
    - ClassNotFoundException
    - ...
    - RuntimeException
        - ArtithmeticException
        - ClassCastException
        - NullPointerException
        - ...
        - IndexOutOfBoundsException</code></pre><h2 id="try-catch문">try-catch문</h2>
<p>표현법은 다음과 같다.</p>
<pre><code class="language-java">try{
    // 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch(Exception1 e1) {
    // Exception1이 발생했을 경우, 이를 처리하기 위한 코드 작성
} catch(Exception2 e2) {
    // Exception2이 발생했을 경우, 이를 처리하기 위한 코드 작성
} catch(Exception3 e3) {
    // Exception3이 발생했을 경우, 이를 처리하기 위한 코드 작성
}
</code></pre>
<h2 id="try-catch-예문">try-catch 예문</h2>
<pre><code class="language-java">public static void main(String[] args) {
        int number = 100;
        int result = 0;

        for (int i = 0; i &lt; 10; i++) {
            try {
                result = number / (int)(Math.random()*10);
                System.out.println(result);
            } catch (ArithmeticException e) {
                System.out.println(&quot;0&quot;);
            }



        }
    }</code></pre>
<p>for 문이 돌아가며 랜덤한 수를 반환할 때
정수인 number를 0으로 나누면 발생될 에러를 ArithmeticException으로 처리가능한 것을 확인했다.</p>
<h2 id="실행순서흐름">실행순서(흐름)</h2>
<p>try-catch문에서 예외가 발생한 경우와 발생하지 않는 경우는 서로 실행순서가 다르다.</p>
<p>try블럭 내에서 예외가 발생한 경우 </p>
<ul>
<li>발생한 예외와 일치하는 catch블럭이 있는지 확인한다.</li>
<li>일치하는 catch블럭을 찾으면, catch블럭 내의 코드를 실행하고 전체 try-catch문을 빠져나가서 그 다음 문장을 계속 실행한다. 만일 일치하는 catch블럭이 없으면 예외는 처리되지 못한다.</li>
</ul>
<p>try블럭 밖에서 예외가 발생한 경우</p>
<ul>
<li>catch블럭을 거치지 않고 전체 try-catch문을 빠져나가서 수행을 계속한다.</li>
</ul>
<h2 id="catch블럭">catch블럭</h2>
<p>catch블럭은 예문에서 보았듯이
(){} 소괄호와 중괄호로 구성된다.</p>
<p>예외가 발생하면 <strong>발생된 예외 클래스의 인스턴스가 생성</strong>된다.
예외가 발생한 문장이 try블럭에 포함되어있다면,
해당 예외를 처리할 수 있는 catch블럭을 찾게된다.</p>
<p>첫번째 catch블럭부터 차례로 일치여부를 따져가면서 catch블럭 내에 선언된 참조변수와 생성된 예외클래스의 인스턴스에 instanceof연산자를 사용하여 비교하는데,
검사가 true인 catch블럭을 만날 때 까지 계속된다.</p>
<p>true인 블럭이 하나도 없으면 예외는 처리되지 않는다.</p>
<p>소괄호에는 예외클래스 타입의 참조변수가 선언되어야한다.</p>
<p>만약 catch블럭의 괄호에 Exception 클래스 타입의 참조변수를 선언해놓으면
해당 catch블럭은 모든 종류의 예외에 대해서 처리한다.</p>
<p>Exception 클래스는 모든 예외클래스의 조상이기 때문이다.</p>
<h2 id="printstacktrace와-getmessage">printStackTrace()와 getMessage()</h2>
<p>예외 발성시 생성되는 예외클래스의 인스턴스에는 <strong>발생한 예외에 대한 정보</strong>가 담겨있다.
printStackTrace()와 getMessage()메서드를 통해 <strong>이 정보들</strong>을 얻을 수 있다.</p>
<pre><code class="language-java">    public static void main(String[] args) {
        System.out.println(1);
        System.out.println(2);
        try {
            System.out.println(3);
            System.out.println(0/0); // 예외발생
            System.out.println(4); // 실행되지 않음
        } catch (ArithmeticException ae) {
            System.out.println(&quot;예외메시지 :&quot; + ae.getMessage());
        }System.out.println(6);
    }</code></pre>
<pre><code>실행결과
1
2
3
예외메시지 : by zero
6</code></pre><h2 id="예외-발생시키기">예외 발생시키기</h2>
<blockquote>
<p>키워드 throw를 사용하여 직접 예외를 발생시킬 수 있다.</p>
</blockquote>
<ol>
<li>발생시키려는 예외클래스의 객체 생성</li>
<li>throw를 이용하여 예외를 발생</li>
</ol>
<pre><code class="language-java">public static void main(String[] args) {

        try {
            Exception e = new Exception(&quot;고의로 발생시킴&quot;);
            throw e; // 예외를 던져줌
        } catch(Exception ce) {
            System.out.println(&quot;ExceptionType :&quot;+ ce.getMessage());
            ce.printStackTrace();
        } System.out.println(&quot;프로그램 정상종료&quot;);



    }
</code></pre>
<pre><code>실행결과
ExceptionType :고의로 발생시킴
java.lang.Exception: 고의로 발생시킴
    at XXXXXXXX.com.mc.exceptionhandling.PracticeThrow.main(PracticeThrow.java:8)
프로그램 정상종료
</code></pre><h2 id="메서드에-예외-선언하기">메서드에 예외 선언하기</h2>
<p>메서드에 예외를 선언하려면 선언부에 throws를 사용해서 메서드 내에서 발생될 수 있는 예외를 적어주면된다.</p>
<pre><code class="language-java">void method() throws Exception1, Exception2, Exception3, Exception4{
    . . .
}</code></pre>
<p>위와같이 구현하며 여러 예외를 사용할 땐  쉼표로 구분한다.</p>
]]></description>
        </item>
    </channel>
</rss>