<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>FinDer___.log</title>
        <link>https://velog.io/</link>
        <description>낙관적 개발자</description>
        <lastBuildDate>Thu, 18 Sep 2025 08:44:14 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>FinDer___.log</title>
            <url>https://velog.velcdn.com/images/assdd_123/profile/4d430bea-8e51-4665-8c6e-503d98b1a290/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. FinDer___.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/assdd_123" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[SQL] 서브쿼리란?]]></title>
            <link>https://velog.io/@assdd_123/SQL-%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%AC%EB%9E%80</link>
            <guid>https://velog.io/@assdd_123/SQL-%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%AC%EB%9E%80</guid>
            <pubDate>Thu, 18 Sep 2025 08:44:14 GMT</pubDate>
            <description><![CDATA[<p>프로그래머스 고득점 Kit와 코딩테스트 SQL 문제를 풀다 서브쿼리가 헷갈리는 경우가 많아 이번 기회에 서브쿼리를 정리하고자 한다.</p>
<h1 id="서브쿼리란">서브쿼리란?</h1>
<ul>
<li><strong>하나의 SQL문 안에 포함되어 있는 또 다른 SQL문!</strong></li>
<li>반드시 <strong>괄호로 묶어야 한다!</strong>
EX) SELECT 안에 SELECT 문, INSERT, UPDATE, DELETE 안의 SELECT문</li>
</ul>
<h1 id="서브쿼리-사용-가능한-곳">서브쿼리 사용 가능한 곳</h1>
<ol>
<li>SELECT절</li>
<li>FROM절</li>
<li>WHERE절</li>
<li>HAVING절</li>
<li>ORDER BY절</li>
<li>기타 DML (INSERT, DELETE, UPDATE)절</li>
</ol>
<p><strong>다만 GROUP BY절에는 서브쿼리를 사용할 수 없다.</strong></p>
<h1 id="서브-쿼리-종류">서브 쿼리 종류</h1>
<h2 id="_1-동작하는-방식에-따라-_">_1. 동작하는 방식에 따라 _</h2>
<h3 id="1-un-correlated비연관-서브쿼리">1) UN-CORRELATED(비연관) 서브쿼리</h3>
<ul>
<li>서브쿼리가 메인쿼리 컬럼을 가지고 있지 않은 형태의 서브쿼리</li>
<li>메인쿼리에 서브쿼리가 실행된 결과 값을 제공하기 위한 목적으로 사용 </li>
</ul>
<h3 id="2-correlated연관-서브쿼리">2) CORRELATED(연관) 서브쿼리</h3>
<ul>
<li>서브쿼리가 메인쿼리 컬럼을 가지고 있는 형태의 서브 쿼리</li>
<li>일반적으로 메인쿼리가 먼저 수행된 후에 서브쿼리에서 조건이 맞는지 확인하고자 할 때 사용 </li>
</ul>
<h2 id="2-위치에-따라"><em>2. 위치에 따라</em></h2>
<h3 id="1-스칼라-서브쿼리-scalar-subquery">1) 스칼라 서브쿼리 (Scalar Subquery)</h3>
<ul>
<li><strong>SELECT절에 사용하는 서브쿼리</strong></li>
<li>서브쿼리 결과를 마치 <strong>하나의 컬럼</strong>처럼 사용하기 위해 주로 사용</li>
<li>단일값을 반환 (값을 계산), 즉 각 행마다 스칼라 서브쿼리 결과가 하나여야 한다. (단일행 서브쿼리 형태)<pre><code class="language-SQL">SELECT 
  emp_name,
  salary,
  (SELECT AVG(salary) FROM employees) AS avg_salary,
  (SELECT dept_name FROM departments d WHERE d.dept_id = e.dept_id) AS dept_name
FROM employees e;</code></pre>
</li>
</ul>
<h3 id="2-인라인-뷰-inline-view">2) 인라인 뷰 (Inline View)</h3>
<ul>
<li><strong>FROM절에 사용하는 서브쿼리</strong></li>
<li><strong>서브쿼리 결과를 테이블처럼 사용하기 위해 주로 사용 (임시 테이블처럼 사용)</strong></li>
<li>데이터 가공 역할 </li>
<li>테이블명이 존재하지 않기 때문에 다른 테이블과 조인 시 <strong>반드시 테이블 별칭 명시 (단독으로 사용하는 경우 불필요)</strong></li>
<li>WHERE절 서브쿼리와 다르게 <strong>서브쿼리 결과를 메인 쿼리의 어느 절에서도 사용할 수 있다.</strong></li>
<li>인라인뷰의 결과와 메인쿼리 테이블과 조인할 목적으로 주로 사용</li>
<li>모든 연산자 사용 가능 </li>
</ul>
<pre><code class="language-SQL">SELECT 
    dept_summary.dept_id,
    dept_summary.avg_salary,
    d.dept_name
FROM (
    SELECT 
        dept_id,
        AVG(salary) as avg_salary,
        COUNT(*) as emp_count
    FROM employees 
    GROUP BY dept_id
) dept_summary
JOIN departments d ON dept_summary.dept_id = d.dept_id
WHERE dept_summary.avg_salary &gt; 5000;</code></pre>
<h3 id="3-where절-서브쿼리">3) WHERE절 서브쿼리</h3>
<ul>
<li>가장 일반적인 서브쿼리</li>
<li>비교 상수 자리에 <strong>값을 전달하기 위한 목적으로 주로 사용(상수항의 대체)</strong></li>
<li><strong>리턴 데이터의 형태에 따라</strong> 단일행 서브쿼리, 다중행 서브쿼리, 다중컬럼 서브쿼리, 상호연관 서브쿼리로 구분 </li>
<li><strong>필터링 조건</strong>으로 사용 (조건 설정)</li>
</ul>
<h3 id="where절-서브쿼리-종류">WHERE절 서브쿼리 종류</h3>
<h3 id="1-단일행-서브쿼리-single-row-subquery">1) 단일행 서브쿼리 (Single Row Subquery)</h3>
<ul>
<li>*<em>서브쿼리 결과가 1개의 행이 리턴되는 형태 *</em></li>
<li>단일행 서브쿼리 연산자 종류</li>
<li><code>=</code>, <code>&gt;</code>, <code>&lt;</code>, <code>&gt;=</code>, <code>&lt;=</code>, <code>&lt;&gt;</code> (같지 않다)
```SQL</li>
<li><ul>
<li>평균 급여보다 높은 급여를 받는 직원 
SELECT emp_name, salary
FROM employees
WHERE salary &gt; (SELECT AVG(salary) FROM employees);</li>
</ul>
</li>
</ul>
<p>-- 최고 급여를 받는 직원
SELECT emp_name, salary
FROM employees
WHERE salary = (SELECT MAX(salary) FROM employees);</p>
<pre><code>
### 2) 다중행 서브쿼리 (Multiple Row Subquery)
- **서브쿼리 결과가 여러 행이 리턴되는 형태 (여러 개의 행 반환)**
- `IN`, `ANY`, `ALL`, `EXISTS` 연산자
- 다중행 서브쿼리 연산자 

| 연산자 | 의미 |
| --- | --- |
|   IN  | 같은 값을 찾음 |
| &gt; ANY | 최솟값을 반환 |
| &lt; ANY | 최댓값을 반환 |
| &lt; ALL | 최솟값을 반환 |
| &gt; ALL | 최댓값을 반환 |

- 예시
&gt; ALL(2000, 3000) : 최대값(3000)보다 큰 행들 반환
&lt; ALL(2000, 3000) : 최소값(2000)보다 작은 행들 반환
&gt; ANY(2000, 3000) : 최소값(2000)보다 큰 행들 반환
&lt; ANY(2000, 3000) : 최대값(3000)보다 작은 행들 반환


```sql
-- IN 사용: 서울에 있는 부서의 직원들
SELECT emp_name, dept_id
FROM employees
WHERE dept_id IN (
    SELECT dept_id 
    FROM departments 
    WHERE location = &#39;서울&#39;
);

-- ANY 사용: 어떤 부서의 평균급여보다라도 높은 급여를 받는 직원
SELECT emp_name, salary
FROM employees
WHERE salary &gt; ANY (
    SELECT AVG(salary) 
    FROM employees 
    GROUP BY dept_id
);

-- ALL 사용: 모든 부서의 평균급여보다 높은 급여를 받는 직원
SELECT emp_name, salary
FROM employees
WHERE salary &gt; ALL (
    SELECT AVG(salary) 
    FROM employees 
    GROUP BY dept_id
);</code></pre><h3 id="3-다중컬럼-서브쿼리-multiple-column-subquery">3) 다중컬럼 서브쿼리 (Multiple Column Subquery)</h3>
<ul>
<li><strong>여러 개의 컬럼을 반환하여 동시에 비교</strong></li>
<li>메인쿼리와의 비교 컬럼이 2개 이상</li>
<li>대소 비교 전달 불가 (두 값을 동시에 묶어 비교 x)
```sql</li>
<li><ul>
<li>각 부서별 최고급여와 최소급여를 동시에 받는 직원
SELECT emp_name, dept_id, salary
FROM employees
WHERE (dept_id, salary) IN (
 SELECT dept_id, MAX(salary)
 FROM employees
 GROUP BY dept_id
 UNION
 SELECT dept_id, MIN(salary)
 FROM employees
 GROUP BY dept_id
);</li>
</ul>
</li>
</ul>
<p>-- 특정 부서의 특정 직급과 일치하는 직원
SELECT emp_name, dept_id, job_title
FROM employees
WHERE (dept_id, job_title) = (
    SELECT dept_id, job_title
    FROM employees
    WHERE emp_name = &#39;김철수&#39;
);</p>
<pre><code>
### 4) 상호연관 서브쿼리 (Correlated Subquery)
- **메인쿼리와 서브쿼리의 비교를 수행하는 형태**
- 비교할 집단이나 조건은 서브쿼리에 명시 (메인쿼리절에는 서브쿼리 컬럼이 정의되지 않았기 때문에 에러 발생)
- 외부쿼리의 컬럼을 참조하는 서브쿼리. 외부 쿼리의 각 행마다 서브쿼리가 실행된다.
```sql
-- 같은 부서 내에서 평균급여보다 높은 급여를 받는 직원
SELECT emp_name, dept_id, salary
FROM employees e1
WHERE salary &gt; (
    SELECT AVG(salary)
    FROM employees e2
    WHERE e2.dept_id = e1.dept_id  -- 외부 쿼리 참조
);

-- EXISTS 사용: 부하직원이 있는 매니저
SELECT emp_name, emp_id
FROM employees manager
WHERE EXISTS (
    SELECT 1
    FROM employees subordinate
    WHERE subordinate.manager_id = manager.emp_id  -- 외부 쿼리 참조
);

-- NOT EXISTS 사용: 부하직원이 없는 직원
SELECT emp_name, emp_id
FROM employees e1
WHERE NOT EXISTS (
    SELECT 1
    FROM employees e2
    WHERE e2.manager_id = e1.emp_id
);</code></pre><ul>
<li>대소 비교할 컬럼을 메인쿼리에, 일치 조건을 서브쿼리에 전달<pre><code class="language-sql">SELECT EMPNO, ENAME, SAL, DEPTNO
FROM EMP E1
WHERE SALARY &gt; (SELECT AVG(SALARY)
              FROM EMP E2
              WHERE E1.DEPTNO = E2.DEPTNO
              GROUP BY DEPTNO);</code></pre>
</li>
</ul>
<h3 id="서브쿼리-주의사항">서브쿼리 주의사항</h3>
<ul>
<li>특별한 경우 (TOP-N 분석 등)을 제외하고는 서브 쿼리절에 ORDER BY절을 사용할 수 없다.</li>
<li>단일 행 서브쿼리와 다중 행 서브쿼리에 따라 연산자의 선택이 중요하다.<pre><code class="language-sql">SELECT *
FROM EMP
WHERE SAL IN (SELECT SALARY
            FROM EMP
            WHERE DEPTNUM = 20
            ORDER BY SALARY);</code></pre>
위와 같이 작성하면 에러가 발생한다. </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자료구조] HashMap vs LinkedHashMap]]></title>
            <link>https://velog.io/@assdd_123/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-HashMap-vs-LinkedHashMap</link>
            <guid>https://velog.io/@assdd_123/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-HashMap-vs-LinkedHashMap</guid>
            <pubDate>Thu, 18 Sep 2025 02:10:47 GMT</pubDate>
            <description><![CDATA[<p>역시나 코딩테스트 문제를 풀다 <code>HashMap</code>이랑 <code>LinkedHashMap</code>이 약간 헷갈려 정리할려고 글을 쓴다. </p>
<p>HashMap의 경우 단점이 하나 있다. 그 단점은 put을 통해 데이터나 객체를 넣을 때 <strong>key의 순서가 지켜지지 않는다는 것</strong>이다. 코드상으로 순차적으로 key, value를 넣어도, 실제 HashMap에서는 해당 순서가 지켜지지 않는다.</p>
<pre><code class="language-java">HashMap&lt;String, String&gt; = new HashMap&lt;&gt;();

map.put(&quot;강아지&quot;, &quot;참새&quot;);
map.put(&quot;고양이&quot;, &quot;토끼&quot;);
map.put(&quot;호랑이&quot;, &quot;사자&quot;);</code></pre>
<p>이렇게 <code>key</code>와 <code>value</code>를 해시맵에 넣는다고 가정하면, 다음과 같이 저장된다는 것이다</p>
<table>
<thead>
<tr>
<th>key</th>
<th>value</th>
</tr>
</thead>
<tbody><tr>
<td>고양이</td>
<td>토끼</td>
</tr>
<tr>
<td>호랑이</td>
<td>사자</td>
</tr>
<tr>
<td>강아지</td>
<td>참새</td>
</tr>
</tbody></table>
<p>그래서 입력된 key의 순서가 보장되어야 한다면 <code>LinkedHashMap</code> 을 사용하면 된다.</p>
<p><code>LinkedHashMap</code> 은 put을 통해 <strong>입력된 순서대로 key가 보장</strong>되므로 해당 문제를 해결할 수 있다. 사용법은 다음과 같다.</p>
<pre><code class="language-java">LinkedHashMap&lt;String, String&gt; = new LinkedHashMap&lt;&gt;();

map.put(&quot;강아지&quot;, &quot;참새&quot;);
map.put(&quot;고양이&quot;, &quot;토끼&quot;);
map.put(&quot;호랑이&quot;, &quot;사자&quot;);</code></pre>
<table>
<thead>
<tr>
<th>key</th>
<th>value</th>
</tr>
</thead>
<tbody><tr>
<td>강아지</td>
<td>참새</td>
</tr>
<tr>
<td>고양이</td>
<td>토끼</td>
</tr>
<tr>
<td>호랑이</td>
<td>사자</td>
</tr>
</tbody></table>
<p>그러면 <code>HashMap</code>이랑 비교했을 때 <code>LinkedHashMap</code>이 어떤 특성을 가지고 있는지 알아보자.</p>
<h3 id="공통점">공통점</h3>
<ul>
<li>데이터를 <code>key-value</code> 쌍으로 저장한다.</li>
<li>비동기로 처리된다.</li>
</ul>
<h3 id="key">Key</h3>
<ul>
<li><strong>중복을 허용하지 않는다.</strong></li>
<li>하나의 null값을 저장할 수 있다.</li>
</ul>
<h3 id="value">Value</h3>
<ul>
<li><strong>중복을 허용한다.</strong></li>
<li>여러 개의 null값을 저장할 수 있다.</li>
</ul>
<h3 id="차이점">차이점</h3>
<h3 id="hashmap">HashMap</h3>
<ul>
<li>데이터의 <strong>삽입 순서를 보장하지 않는다.</strong></li>
<li>AbstractMap 클래스를 상속하고, Map 인터페이스를 구현한다.</li>
</ul>
<h3 id="linkedhashmap">LinkedHashMap</h3>
<ul>
<li>데이터의 <strong>삽입 순서를 보장</strong>한다.</li>
<li>HashMap 클래스를 상속하고, Map 인터페이스를 구현한다.</li>
</ul>
<h3 id="성능">성능</h3>
<h3 id="create">Create</h3>
<ul>
<li>HashMap &lt; LinkedHashMap (오래 걸림)</li>
</ul>
<h3 id="iterate">Iterate</h3>
<ul>
<li>(오래 걸림) HashMap &gt; LinkedHashMap</li>
</ul>
<h3 id="access">Access</h3>
<ul>
<li>(오래 걸림) HashMap &gt; LinkedHashMap</li>
</ul>
<h3 id="결론">결론</h3>
<ul>
<li>HashMap보다 <strong>LinkedHashMap의 성능이 약간 더 우세하지만, 전체적인 성능에는 큰 차이가 없다.</strong></li>
<li>HashMap은 <strong>순서를 보장하지 않아도 될 때</strong>, LinkedHashMap은 <strong>순서를 보장해야 될 떄</strong> 사용한다.</li>
</ul>
<h3 id="참고">참고</h3>
<p><a href="https://fruitdev.tistory.com/141">https://fruitdev.tistory.com/141</a>
<a href="https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html">https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html</a>
<a href="https://da-nyee.github.io/posts/java-hashmap-vs-likedhashmap/">https://da-nyee.github.io/posts/java-hashmap-vs-likedhashmap/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[25년 하반기 목표]]></title>
            <link>https://velog.io/@assdd_123/25%EB%85%84-%ED%95%98%EB%B0%98%EA%B8%B0-%EB%AA%A9%ED%91%9C</link>
            <guid>https://velog.io/@assdd_123/25%EB%85%84-%ED%95%98%EB%B0%98%EA%B8%B0-%EB%AA%A9%ED%91%9C</guid>
            <pubDate>Wed, 17 Sep 2025 07:33:15 GMT</pubDate>
            <description><![CDATA[<p>25년 하반기 공고가 슬슬 올라오고 있다. 교육 수료하고 벌써 6개월이 지났는데 시간이 너무 빠르다. 상반기에도 여러 기업에 지원했지만 서합률은 15-20% 정도 되었고, 붙은 서류마저도 코딩테스트나 필기 전형에서 떨어져서 6개월동안 코딩테스트에만 집중했던 것 같다. </p>
<h3 id="그러면-나는-지난-6개월동안-뭘-했나">그러면 나는 지난 6개월동안 뭘 했나?</h3>
<p>*<em>1. 백준 (물)골드 1 달성
*</em><img src="https://velog.velcdn.com/images/assdd_123/post/4e33ab5d-e567-443f-bde8-27f61567d132/image.png" alt="">
교육 수료하고 그동안 미뤄왔던 예비군에 다녀오고, 다른 기업 필기 시험 보느라 코테를 대충 공부하고 이후 4월 30일부터 본격적으로 코테를 파기 시작했다. 5개월 남짓한 기간동안 대략 230여 문제 좀 푼 것 같다. 매일 꾸준히 1문제씩 풀고 있고, 현재 4달 넘게 지속 중이다. </p>
<p>*<em>2. 프로그래머스 400여 문제 해결
*</em>프로그래머스도 백준과 같이 병행해 풀었다. 코딩 입문, 기초, SQL 고득점 kit만 다 풀어도 300문제가 넘어서, 양치기를 정말 많이 하긴 했다.</p>
<p>*<em>3. 토익 취득 
*</em>2년 전에 취득했던 오픽의 성적이 만료되서 토익을 취득했다. 사실 토익을 취득한 이유는 일부 금공 같은 경우는 토익만 받는 곳이 있어서 딴건데 나름 잘 한 것 같다. 2주 정도 준비해서 급하게 따긴 했지만, 뭐 기준 점수는 넘겼다.</p>
<p>*<em>4. 오픽 재취득
*</em>오픽은 본격적인 취준 전에 3번 정도 응시했었다. 3번 다 모두 IH가 나와서 나름 공부 안한거치고는 잘 나왔기에 나 정도면 영어 잘한다고 생각했었다. 하지만, 그동안 영어 말하기 공부를 안하기도 했고, 외운 티가 좀 났는지 다시 응시한 2번의 시험 모두 IM2가 나왔다. 솔직히 돈도 좀 많이 날리고, 실망스럽긴 하지만 뭐 시간 날 때 취미로 다시 연습해야겠다.</p>
<p>*<em>5. 프로젝트 리팩토링 
*</em>부트캠프 때 했던 프로젝트 중에 약간 구현의 아쉬움이 있던 프로젝트를 가지고 혼자 성능개선이랑 부하테스트를 진행했었다. 비동기 처리도 해보고, 인덱싱 처리, Redis 캐싱 처리를 해서 약 11배 정도 성능 개선을 할 수 있었다. JMeter로 부하테스트를 실시하니 100명은 거뜬하게 쓸 수 있는 시스템을 구축한 것 같다. 물론, 더 많은 유저가 들어올 수 있도록 성능개선을 해야 되지만, 처음 해보는 성능개선이라 미숙한 점이 많았다.</p>
<p><strong>6. 운동 &amp; 러닝</strong>
작년 1월 친구한테 배운 헬스를 1주일에 4번 정도 꾸준히 하고 있다. 작년에 비하면 몸이 확실히 좋아지긴 했고, 한 개도 못했던 턱걸이를 이제는 컨디션 좋으면 7-8개까지 당길 수 있는 수준으로 올라왔다. 살크업하던 시기 6분대가 나왔던 달리기도 이제는 5분 후반대가 나오기 시작했다. 원래는 마라톤에 나갈려고 가끔 뛰었지만 날씨도 좋은데 꼭 마라톤에 나가보고 싶다!</p>
<h3 id="그러면-하반기동안-나는-뭘-해야-할까">그러면 하반기동안 나는 뭘 해야 할까?</h3>
<p><strong>당연히 취업이다!</strong>
솔직히 나는 전공자임에도 학교 다니는 기간에 &quot;방황&quot;이라는 이유로 전공 공부를 등한시했다. 사실, 모든 공부는 다 힘들고 누구나 다 힘들다. 그럼에도 불구하고 누구는 성공하고, 누구는 실패한다. 요즘 솔직히 개발자 취업 시장이 정말 쉽지는 않다. 대기업에 재직 중인 친한 형도 2-3년 전까지는 이 정도는 아니었다고 한다. 솔직히 하반기 열리면서 불안해서 잠도 못 잔적 있도 있고, 자신감도 취준 처음 할 당시에 비하면 많이 떨어져있는 상태이다. 나이는 먹고 그러니 당연히 그럴만하다. 매일 별에별 생각이 다 들어서 공부 방해 될때가 많다. 그래서 몇 가지 목표를 세울려고 한다.</p>
<h3 id="미친-듯이-운동하기">미친 듯이 운동하기</h3>
<p>몸이 건강해야 정신도 건강하다. 운동을 꾸준히 하긴 했지만, 익숙해져서 관습적으로 운동한 것 같다. 운동 시간을 조금 더 늘리거나 무게를 늘리는 등 미친 듯이 운동해서 정신을 맑게 해야겠다.</p>
<h3 id="코딩테스트-복습">코딩테스트 복습</h3>
<p>사실 코딩테스트 문제 푸는거에만 초점을 맞춰서 복습을 제대로 안했다. 그러니 다시 풀었던 개념 또 보고 하느라 시간이 배로 들고 있다는 것을 느꼈다. 그래서 1,2주 전부터 문제 푼 후에 다시 풀어보고 하루 뒤에 1주일 뒤에 이런 식으로 반복적으로 풀어보고 있다. 효과는 괜찮은 것 같다.</p>
<h3 id="코딩테스트-유형-디깅">코딩테스트 유형 디깅</h3>
<p>몇 번의 코딩테스트를 본 결과, 요새 코테 트렌드가 바뀐 것 같다. 과거에는 BFS/DFS, 구현, DP 등의 문제가 많이 나왔다면, 요새는 다들 잘해서 그런지 이분탐색 / DP 심화 / 다익스트라 쪽으로 꽤 나오는 것 같다. 특히, 이분탐색이랑 골드 1-2 수준의 DP가 꽤 자주 나왔다. SQL 출제하는 기업 같은 경우도 몇몇 문제는 프로그래머스 고득점 Kit로 대비할 수 없는 수준이었다.
그래서 일단은 매일 꾸준히 구현 1문제와 다른 유형의 문제들(이분탐색, 투포인터, DP, 다익스트라, 유니온 파인드 등) 2-3문제씩 매일 풀고 복습할려고 한다. <strong>코딩테스트 제발 합격하자!</strong></p>
<h3 id="포트폴리오-정리">포트폴리오 정리</h3>
<p>사실 내가 여태껏 진행한 프로젝트가 기술의 깊이가 얕다고 판단해 새로운 개인 프로젝트를 팔까 5월부터 고민했었다. 하지만, 계속 미루다보니 아직 아무것도 한게 없다. 코테만 하다보니 백엔드 API 짜는 방법도 가물가물해서 사이드 프로젝트를 심심풀이로 하나 만들려고 한다. 언제 완성할지는 모르겠지만 일단 해보자</p>
<h3 id="cs-지식-정리">CS 지식 정리</h3>
<p>사실 이거는 학교 다닐 때 열심히 공부 했으면 금방 한다. 하지만, 나는 학교 다닐 때 많이 방황했던지라 이에 대한 추가 공부도 필요한 상태다. 필기 시험 준비할 겸 옛날에 봤던 책, PPT, 깃허브 등을 참고해서 공부하자</p>
<h3 id="자소서--면접">자소서 &amp; 면접</h3>
<p>공고 뜨는대로 최대한 많이 써보자. 이전에도 많이 써봤지만 마스터 자소서 하나 만들어서 최대한 많이 써보자.</p>
<h3 id="결론">결론</h3>
<p>사실 이렇게 아무생각 없이 글을 쓰다보니 학교 다닐 때 정말 성실하게 공부하고 조금만 더 빨리 졸업하고 그랬으면 이미 진작 어디든 일하고 있지 않았을까 라는 생각이 든다. 지금 취준하는 타이밍이 나쁜 것도 있지만 그렇다고 아예 아무것도 안하기에 내가 너무 젊다. 취업이 정말 힘들긴 하다. 나도 모르게 계속 남과 비교하고 있고, 한창 꽃다운 나이에 주말에도 제대로 쉬지 못하고 지친 몸과 마음을 이끌고 계속 공부를 해야되니 말이다. 솔직히 이 개발자 말고 다른 걸 해볼까라는 생각도 많이 든다.(지금도 들고 있다.) 쉬운거 하나 없지만 일단 &quot;끝까지 결과를 만들어보자&quot;라는 마인드로 하고 있다. 취준의 끝을 봐야 할 것 같다. 정말 두서 없이 의식의 흐름대로 쓴 글이지만 내가 원하는대로 최대한 되도록 더 노력해야겠다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 자바 입출력 정리 (백준)]]></title>
            <link>https://velog.io/@assdd_123/Java-%EC%9E%90%EB%B0%94-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EC%A0%95%EB%A6%AC-%EB%B0%B1%EC%A4%80</link>
            <guid>https://velog.io/@assdd_123/Java-%EC%9E%90%EB%B0%94-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EC%A0%95%EB%A6%AC-%EB%B0%B1%EC%A4%80</guid>
            <pubDate>Sat, 31 May 2025 07:52:23 GMT</pubDate>
            <description><![CDATA[<p>백준으로 코테 문제를 풀다보면 입출력 코드를 짜야 할 부분이 많다. 프로그래머스는 파라미터로 입력을 받고 answer로 리턴하는 형태로 입출력이 되는데 반해, 백준은 해당 입출력 받는 코드를 짜야 된다.</p>
<p>나 같은 경우는 원래 C++로 코테를 공부했을 때는, 입력은 cin을 출력은 그냥 cout이나 printf로 사용했기에 별 문제가 없었다. 하지만 Java로 코테 언어를 바꾸게 되면서 백준을 풀다가 입출력 부분이 계속 헷갈려 이번 기회에 블로그에 한꺼번에 정리할려고 한다.</p>
<h2 id="1-scanner">1. Scanner</h2>
<p>아마 자바에서 키보드로 데이터를 입력 받아 변수에 저장하는 가장 쉬운 방법은 <strong>Scanner</strong>를 사용하는 것이다. 사용 방법은 다음과 같다.</p>
<pre><code class="language-java">Scanner scanner = new Scanner(System.in); </code></pre>
<p>왼쪽 <strong>Scanner scanner</strong>는 Scanner 변수를 선언하는 부분이고, 오른쪽 new Scanner(System.in)은 Scanner 객체를 생성하는 부분이다. 이렇게 생성된 Scanner를 왼쪽 scanner 변수에 대입한다. 보통 백준에서는 Scanner를 다음과 같이 많이 쓴다. 먼저, Scanner를 사용하기 위해서는 다음과 같이 <code>java.util.Scanner</code> 클래스를 반드시 import 해야 한다. 아니면 <code>import java.util.*</code>을 사용해서 util 클래스 전체를 import 해도 된다. </p>
<pre><code class="language-java">import java.util.Scanner;

public class Main {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt(); // 3을 입력 받았다고 가정
        int b = sc.nextInt(); // 5를 입력 받았다고 가정 

        System.out.println(a + b); // 8
   }
}</code></pre>
<p>참 쉽다. 나는 그래서 주로 간단한 브론즈 문제나, 입력이 간단할 경우 Scanner를 주로 쓴다. 위에 nextInt()는 Scanner에서 자주 사용되는 메서드 중 하나이다. Scanner에서 자주 쓰는 메서드의 종류는 다음과 같다. </p>
<table>
<thead>
<tr>
<th>메서드명</th>
<th>설명</th>
<th>예시 입력 값</th>
</tr>
</thead>
<tbody><tr>
<td><code>next()</code></td>
<td>공백(스페이스, 탭 등) 단위로 문자열 한 단어 입력</td>
<td><code>Hello World</code> → <code>Hello</code></td>
</tr>
<tr>
<td><code>nextLine()</code></td>
<td>한 줄 전체 입력 (개행까지)</td>
<td><code>Hello World</code> → <code>Hello World</code></td>
</tr>
<tr>
<td><code>nextInt()</code></td>
<td>정수 입력</td>
<td><code>42</code></td>
</tr>
<tr>
<td><code>nextLong()</code></td>
<td>long형 정수 입력</td>
<td><code>10000000000L</code></td>
</tr>
<tr>
<td><code>nextDouble()</code></td>
<td>double형 실수 입력</td>
<td><code>3.14</code></td>
</tr>
<tr>
<td><code>nextFloat()</code></td>
<td>float형 실수 입력</td>
<td><code>3.14f</code></td>
</tr>
<tr>
<td><code>nextBoolean()</code></td>
<td><code>true</code> 또는 <code>false</code> 입력 (boolean 값)</td>
<td><code>true</code></td>
</tr>
<tr>
<td><code>hasNext()</code></td>
<td>다음 입력 토큰 존재 여부 확인</td>
<td>(값 확인 없이 true/false 반환)</td>
</tr>
<tr>
<td><code>hasNextLine()</code></td>
<td>다음 줄 존재 여부 확인</td>
<td>(값 확인 없이 true/false 반환)</td>
</tr>
<tr>
<td><code>hasNextInt()</code></td>
<td>다음 토큰이 정수인지 확인</td>
<td>(값 확인 없이 true/false 반환)</td>
</tr>
<tr>
<td><code>close()</code></td>
<td>Scanner 객체를 닫고 자원을 해제</td>
<td>(특정 입력 없음)</td>
</tr>
</tbody></table>
<p>하지만 문제의 입출력이 많아지고 느려질 수록 이러한 Scanner 방식을 사용하면 입력 받을 때 시간초과가 발생할 수 있다. 또한, 문제마다 1, 2초 등의 시간 제한이 있기 때문에 각 테스트 케이스의 개수가 늘어날 수록 System.out.println()의 호출 횟수 또한 증가하게 된다. 그러므로 Scanner와 System.out.println 대신 <strong>BufferedReader</strong>와 <strong>BufferedWriter</strong>를 사용할 수 있다. </p>
<h2 id="2-bufferedreader--bufferedwriter">2. BufferedReader / BufferedWriter</h2>
<h3 id="bufferedreader">BufferedReader</h3>
<p>우선 BufferedReader와 BufferedWriter를 설명하기 전에 간단하게 스트림(Stream)이라는 개념을 설명하고자 한다. </p>
<p>먼저, 데이터는 키보드를 통해 입력될 수도 있고, 파일 또는 프로그램으로부터 입력될 수도 있다. 반대로, 데이터는 모니터로 출력될 수도 있고, 파일에 저장되거나 다른 프로그램으로 전송될 수도 있다. 이것을 다 합쳐 <strong>데이터 입출력</strong>이라고 부른다.</p>
<p>자바는 입력 스트림과 출력 스트림을 통해 데이터를 입출력한다. 스트림은 <strong>단방향으로 데이터가 흐르는 것</strong>을 말하는데 아래 그림과 같이 데이터는 출발지에서 나와 도착지로 흘러들어간다. 
<img src="https://velog.velcdn.com/images/assdd_123/post/05414d7a-ca90-42a6-a253-ac5c53fb5a39/image.png" alt=""></p>
<pre><code class="language-java">BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 선언
String str = br.readLine(); // 한줄 읽음 
int i = Integer.parseInt(br.readLine()); </code></pre>
<p>readLine() 메서드를 통해 한 줄 전체를 입력 받는다. 다만, 해당 메서드는 String으로 리턴 값이 고정되어 있기 때문에, 다른 타입으로 입력을 받고자 한다면 반드시 형변환이 필요하다. 그리고, 예외처리를 반드시 필요로 한다. 보통 main문에 throws IOException를 통한 예외처리를 많이 사용하는 편이다. (그리고 자바의 입출력과 관련한 java.io.* 클래스를 import 해야 한다.)
즉, BufferedReader는 Scanner와 달리 개행문자를 받아들이고 입력 받은 데이터가 String으로 고정되어 있다. 그러므로 따로 데이터를 가공해야 되는 경우가 많지만 Scanner보다 속도가 빠르다는 장점이 있다. 아래 사진을 보면 BufferedReader가 Scanner보다 빠른 것을 알 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/69115d70-8f62-42e6-97d8-f2e6ffcbd879/image.png" alt=""></p>
<p>BufferedReader 클래스의 메서드 종류는 다음과 같다.</p>
<table>
<thead>
<tr>
<th><strong>타입 + 메서드명</strong></th>
<th><strong>설명</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>void close()</strong></td>
<td>입력 스트림을 닫고, 사용하던 자원을 해제</td>
</tr>
<tr>
<td><strong>void mark(int, readAheadLimit)</strong></td>
<td>스트림의 현재 위치를 마킹</td>
</tr>
<tr>
<td><strong>int read()</strong></td>
<td>한 글자만 읽어 정수형으로 반환 (e.g ,&#39;3&#39;을 읽어 정수형인 (int)&#39;3&#39; = 51로 반환)</td>
</tr>
<tr>
<td><strong>String readLine()</strong></td>
<td>한 줄을 읽음</td>
</tr>
<tr>
<td><strong>boolean ready()</strong></td>
<td>입력 스트림이 사용할 준비가 되었는지 확인 (1이 준비 완료)</td>
</tr>
</tbody></table>
<h3 id="stringtokenizer">StringTokenizer</h3>
<p>BufferedReader를 통해 읽은 데이터는 개행문자 단위 (즉, Line 단위)로 나누어진다. 만약 이를 공백 단위로 데이터를 가공하고 싶으면 따로 작업을 해야 한다. 이럴 때 사용하는 것이 StringTokenizer나 String.split() 함수이다. StringTokenizer 클래스를 사용하기 위해서는 import java.util.StringTokenizer;를 import 해야 한다.</p>
<pre><code class="language-java">BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 선언 
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken()); // 문자열 -&gt; 정수 변환
int M = Integer.parseInt(st.nextToken());

// String.split() 메서드
String[] arr = str.split(&quot; &quot;);</code></pre>
<p>StringTokenizer의 nextToken() 함수를 사용하면 readLine()을 통해 입력 받은 토큰 값을 공백 단위로 구분하여 순서대로 호출한다.
String.split() 함수를 사용하면, 배열에 공백단위로 끊어 데이터를 저장하여 사용할 수 있다. </p>
<h3 id="bufferedwriter">BufferedWriter</h3>
<p>일반적으로 출력을 할 때 System.out.println(&quot;&quot;); 을 사용하는 경우가 많다. 하지만 출력해야 하는 양이 많은 문제를 접하게 된 경우에 System.out.println(&quot;&quot;);을 사용하게 되면 성능상에 문제가 발생할 수 있다. 그래서 출력해야 될 양이 많은 경우에는, 입력과 동일하게 버퍼를 사용하는 것이 좋다.</p>
<pre><code class="language-java">BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); // 선언
String str = &quot;ABC&quot;;
bw.write(str); // 출력
bw.newLine(); // 줄바꿈
bw.flush(); // 버퍼에 남아있는 데이터 모두 출력
bw.close();  // 스트림 (연결된 자원) 닫음. 자원 해제 
</code></pre>
<p>BufferedWriter는 System.out.println(&quot;&quot;);처럼 출력과 개행을 동시해 할 수 없기 때문에, 개행을 위해서는 따로 newLine(); 또는 bw.write(&quot;\n&quot;);을 사용해야 한다. 그리고 BufferedWriter의 경우 버퍼를 점유하고 있기 때문에 반드시 사용 후, flush()를 통해 버퍼에 남아있는 데이터를 모두 출력하고, close()를 통해 버퍼를 해제해야 한다. close()를 사용하게 되면, 출력 스트림을 아예 닫아버리기 때문에 한번 출력 후, 다른 것도 출력하고자 한다면 flush()를 사용하면 된다. </p>
<table>
<thead>
<tr>
<th><strong>타입 + 메서드명</strong></th>
<th><strong>설명</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>void close()</strong></td>
<td>스트림을 닫음. 닫기 전 flush().</td>
</tr>
<tr>
<td><strong>void flush()</strong></td>
<td>스트림을 비움</td>
</tr>
<tr>
<td><strong>void newLine()</strong></td>
<td>개행 문자 역할</td>
</tr>
<tr>
<td><strong>void write(char[] buf, int offset, int length)</strong></td>
<td>버퍼 offset 위치부터 length 크기 만큼 write</td>
</tr>
<tr>
<td><strong>void write(int c)</strong></td>
<td>한 글자 쓰기</td>
</tr>
<tr>
<td><strong>void (String s, int offset, int length)</strong></td>
<td>문자열에서 offset에서부터 일정 길이만큼 write</td>
</tr>
</tbody></table>
<h2 id="3-string-stringbuffer-stringbuilder">3. String, StringBuffer, StringBuilder</h2>
<p>또, 자바로 알고리즘 문제를 풀다보면 StringBuilder를 사용하는 경우가 많다. 그러므로, String과 StrigBuffer, StringBuilder와의 차이점을 중심으로 이를 설명하고자 한다.</p>
<p>먼저, String 클래스 관련 메서드를 보여주고자 한다. 종류는 다음과 같다.</p>
<pre><code class="language-java">String str = &quot;apple&quot;;

// 길이 반환
str.length(); // 5

// 빈 문자열 체크
str.isEmpty(); // false

// 문자 찾기
str.charAt(0); // &#39;a&#39;
str.indexOf(&quot;a&quot;); // 0
str.lastIndexOf(&quot;p&quot;); // 2

// 문자 자르기
str.substring(1, 3); // &quot;pp&quot;
str.substring(3); // &quot;le&quot;

// 문자 치환 (바꾸기)
// replace([기존문자], [바꿀문자])
str.replace(&#39;p&#39;, &#39;e&#39;); // &quot;aeele&quot;

// replaceAll([정규식], [바꿀문자])
str.replaceAll(&quot;.&quot;, &quot;/&quot;); // &quot;/////&quot;

// replaceFirst([기존문자], [바꿀문자])
str.replaceFirst(&quot;p&quot;, &quot;e&quot;); // &quot;aeple&quot;

// 문자 동일 여부 판단
str.equals(&quot;apple&quot;); // true

// 문자 비교
// str과 &quot;applp&quot;가 다를 때 compareTo 결과
str.compareTo(&quot;applp&quot;); // -1

// 문자 포함 여부 판단
str.contains(&quot;app&quot;); // true

// 문자열 분리
str.split(&quot; &quot;); // {&quot;apple&quot;} (공백 없으므로 전체 문자열 반환)
str.split(&quot;&quot;); // {&quot;a&quot;, &quot;p&quot;, &quot;p&quot;, &quot;l&quot;, &quot;e&quot;}

// 문자 앞뒤 공백 제거
str.trim(); // &quot;apple&quot; (앞뒤 공백 없으므로 그대로)

// 문자 &lt;-&gt; 숫자 변환
Integer.parseInt(&quot;100&quot;); // 100
Integer.toString(100);  // &quot;100&quot;
</code></pre>
<p>자바에서 문자열이란 문자들을 배열의 형태로 구성한 이뮤터블(immutable) 객체이다. 이뮤터블 객체는 <strong>값을 변경할 수 없는 객체</strong>로 시간 복잡도 관점에서 주의해야 할 필요가 있다.</p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/0d158393-d891-4f4d-bd06-1007522b25ce/image.png" alt=""></p>
<pre><code class="language-java">String string = &quot;He&quot;;
string += &quot;llo&quot;;
System.out.println(string); // &quot;Hello&quot;</code></pre>
<ol>
<li>문자열을 &quot;He&quot;로 초기화. 변수 string이 문자열 &quot;He&quot;를 참조</li>
<li>이어서 string이 참조하는 &quot;He&quot;와 &quot;llo&quot;를 합쳐 새로운 문자열을 만들고 string은 새로운 문자열인 &quot;Hello&quot;를 참조한다.</li>
</ol>
<p>즉, 자바에서 String 객체는 값을 변경할 수 없으므로 문자열을 변경할 때마다 기존 문자열을 끊고 새 문자열을 참조해야 한다(새로운 값을 할당). 그러므로 시간 복잡도 관점에서 연산의 비용이 클 수 밖에 없다. </p>
<p>그러므로 이러한 문제를 해결하기 위해 나온 것이 StringBuffer 클래스와 StringBuilder 클래스이다. 이 두 클래스는 뮤터블하므로 값을 변경할 때 시간 복잡도 관점에서 더 효율적이다. </p>
<p>String의 값을 변경하는 연산이 많을 때 StringBuffer와 StringBuilder 클래스를 사용할 수 있고, 두 클래스의 차이는 멀티 스레드 환경에서 Thread-Safe 여부로 나뉜다. Thread-Safe가 없는 StringBuilder 클래스가 속도 측면에서 미세하지만 더 빠르므로 StringBuilder를 사용하면 된다. </p>
<p>즉, 코딩테스트에서 문자열의 값을 변경하는 연산이 많을 때 시간 초과가 발생하지 않도록 StringBuilder를 사용하면 좋다. StringBuilder 관련 메서드는 아래와 같다.</p>
<pre><code class="language-java">StringBuilder sb = new StringBuilder(); // StringBuilder 객체 생성

// 문자열 추가
sb.append(&quot;apple&quot;);

// 특정 인덱스에 문자 삽입
sb.insert(2, &quot;oo&quot;);

// 문자열 삭제
sb.delete(0, 2); // &quot;oople&quot;

// 특정 인덱스의 문자 삭제
sb.deleteCharAt(2); // &quot;oole&quot;

// 특정 인덱스의 문자를 변경
sb.setCharAt(1, &#39;p&#39;);

// 문자열 뒤집기
sb.reverse();

// 문자열 절대길이 줄이기 
sb.setLength(2);

// 문자열 절대길이 늘이기
sb.setLength(4);</code></pre>
<p>이렇게 백준에서 많이 쓰이는 자바 입출력 형식과 문자열 등을 알아봤다. 사실 대부분의 기업 코딩 테스트는 프로그래머스로 응시해서 입출력 같은 경우는 몰라도 된다. 하지만 백준과 같이 입출력이 많은 경우에는 반드시 이를 필수적으로 알아야 한다. 이전에는 정말 헷갈렸지만 이렇게 한번 제대로 정리하니깐 복습하기가 더 수월해진 것 같다! </p>
<h3 id="참고">참고</h3>
<ul>
<li><a href="https://rlawo32.tistory.com/entry/%EB%B0%B1%EC%A4%80-JAVA-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EC%A0%95%EB%A6%AC">https://rlawo32.tistory.com/entry/%EB%B0%B1%EC%A4%80-JAVA-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EC%A0%95%EB%A6%AC</a></li>
<li><a href="https://ittrue.tistory.com/108">https://ittrue.tistory.com/108</a></li>
<li><a href="https://rlakuku-program.tistory.com/33">https://rlakuku-program.tistory.com/33</a></li>
<li><a href="https://mebadong.tistory.com/12">https://mebadong.tistory.com/12</a></li>
<li><a href="https://product.kyobobook.co.kr/detail/S000212576322">코딩 테스트 합격자 되기: 자바편</a></li>
<li><a href="https://product.kyobobook.co.kr/detail/S000212853100">이것이 자바다</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Java Collection Framework 정리]]></title>
            <link>https://velog.io/@assdd_123/Java-Collection-Framework</link>
            <guid>https://velog.io/@assdd_123/Java-Collection-Framework</guid>
            <pubDate>Sat, 31 May 2025 06:41:55 GMT</pubDate>
            <description><![CDATA[<p>자바로 코딩테스트를 준비하다보면 ArrayList나 Stack, Queue 등을 선언해서 쓰는 것을 많이 해봤을 것이다. 하지만, 문제를 풀다보면 각 문제에 맞는 자료구조의 종류들이 많다. 그래서 이번 기회에 Java Collection Framework를 정리해볼려고 한다.</p>
<h2 id="1-java-collection-framework란">1. Java Collection Framework란?</h2>
<p>먼저, <strong>Java Collection Framework</strong>란 자바에서 널리 알려져 있는 자료 구조(Data Structure)들을 바탕으로 객체들을 효율적으로 추가, 삭제, 검색할 수 있도록 관련된 <strong>인터페이스</strong>와 <strong>클래스</strong>들을 <strong>java.util</strong> 패키지에 포함시켜 놓은 것을 말한다. </p>
<p>즉, <strong>자료 구조의 형태들을 자바 클래스로 구현한 모음집</strong>이라고 보면 된다. 더 쉽게 생각하면 자바에서 C++의 STL 역할을 한다고 생각하면 쉬울 것이다. 이 컬렉션 프레임워크를 통해 자바 개발자들은 직접 자료구조를 직접 구현할 필요없이 이들을 인스턴스화시켜서 사용만 하면 된다.</p>
<h3 id="1-1-컬렉션-프레임워크의-이점">1-1. 컬렉션 프레임워크의 이점</h3>
<p>컬렉션 프레임워크는 다음과 같은 이점을 가진다.</p>
<ul>
<li>List, Queue, Set, Map 등의 인터페이스를 제공하고, 이를 구현하는 클래스를 제공하여 <strong>일관된 API</strong>를 사용할 수 있다.</li>
<li><strong>가변적인 저장 공간</strong>을 제공한다. 이는 고정적인 저장 공간을 제공하는 배열과 대비되는 특징이라고 볼 수 있다.</li>
<li>개발자 스스로 자료구조, 알고리즘 등을 구현할 필요 없이, <strong>이미 구현된 컬렉션 클래스를 목적에 맞게 선택해서 사용</strong>하면 된다.</li>
<li>제공되는 API의 코드는 검증되었으며, 고도로 <strong>최적화</strong>되어 있다.</li>
</ul>
<h3 id="1-2-구성요소">1-2. 구성요소</h3>
<p>컬렉션 프레임워크는 다음과 같이 크게 3가지 요소로 구성되어 있다.</p>
<ol>
<li><p><strong>인터페이스(Interfaces)</strong> : 각 컬렉션을 나타내는 추상 데이터에 대한 인터페이스(List, Set, Map, Queue 등). 클래스는 이 인터페이스를 구현하는 방식으로 작성되어 있기 때문에 상세 동작은 달라도 일관된 조작법으로 사용할 수 있다. </p>
</li>
<li><p><strong>클래스(Classes)</strong> : 컬렉션 별 인터페이스의 구현(Implementation). 같은 List 컬렉션이더라도 개발자의 목적에 따라 ArrayList, LinkedList 등으로 상세 구현이 달라질 수 있다.</p>
</li>
<li><p><strong>알고리즘(Algorithms)</strong> : 컬렉션이 제공하는 연산, 검색, 정렬, 셔플(Shuffle) 등에 대한 메서드.</p>
</li>
</ol>
<p>이러한 특성을 가진 자바 컬렉션 프레임워크의 계층도는 아래와 같다. </p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/d2daf5b2-43cc-443a-a40d-2c1705f42796/image.png" alt="">
사실 컬렉션 프레임워크를 구성하는 인터페이스와 클래스의 종류는 정말 많다. 그래서 나는 코딩테스트에 주로 나오는 것들로 정리하고자 한다. 크게 List, Queue, Set, Map 인터페이스로 구성되어 있다고 생각하면 쉽다.</p>
<h2 id="2-배열-arraylist">2. 배열, ArrayList</h2>
<h3 id="배열-array">배열 (Array)</h3>
<p>배열은 처음 선언할 때 크기가 결정된다. 즉, 크기가 정적이다. 만약 문제에서 데이터의 개수를 정확히 알 수 있다면 코드가 더 간결하고 속도가 더 빠른 배열을 사용하면 된다. </p>
<pre><code class="language-java">int[] arr1 = {1, 2, 4, 5, 3}; // 1차원 배열 선언 + 생성 + 초기화
int[] arr2 = new int[5]; // new 연산자를 사용해 배열 선언 후 생성

int[][] arr3 = {{1, 2, 3}, {4, 5, 6}}; // 2차원 배열 생성 (2행 3열)
System.out.println(arr[1][2]); // 6
// arr[1][2]에 저장된 값을 7로 변경
arr[1][2] = 7;
// 변경된 값을 출력
System.out.println(arr[1][2]); // 7

System.out.println(arr1.length); // arr1 배열의 전체 데이터 개수를 리턴 : 5
Arrays.sort(arr1); // arr1 배열의 모든 데이터 정렬하는 Arrays 클래스의 sort() 메서드 : [1, 2, 3, 4, 5]
System.out.println(Arrays.toString(arr1)); 
// 배열의 모든 데이터를 String으로 변환하는 Arrays 클래스의 toString() 메서드: [1, 2, 3, 4, 5]
</code></pre>
<h3 id="arraylist">ArrayList</h3>
<p>자바에서 크기가 동적으로 변경되는 배열이 필요할 때는 ArrayList를 활용하면 된다. 실제로 코딩테스트 문제를 풀다보면 많이 활용된다.</p>
<pre><code class="language-java">List&lt;String&gt; list = new ArrayList&lt;&gt;();
List&lt;String&gt; list2 = new ArrayList&lt;&gt;();


// 요소 삽입
list.add(&quot;one&quot;);

// 특정 인덱스에 요소 삽입
list.add(0, &quot;zero&quot;);

// 리스트 병합 (추가되는 리스트가 뒤로 온다)
list.addAll(list2);

// 특정 요소의 첫번째 인덱스 반환
list.indexOf(&quot;zero&quot;);

// 특정 요소의 마지막 인덱스 반환
list.lastIndexOf(&quot;zero&quot;);

// 특정 인덱스의 값 삭제
list.remove(0);

// 첫 번째 값 삭제
list.remove(&quot;one&quot;);

// 리스트 차집합
list.removeAll(list2);

// 리스트 교집합
list.retainAll(list2);

// 리스트 비우기
list.clear();

// 리스트 비어있는지 체크
list.isEmpty();

// 리스트 길이
list.size();

// 리스트 특정 요소 포함여부 체크
list.contains(&quot;one&quot;);

// 리스트에 다른 리스트 요소가 전부 포함되어 있는지 여부 체크
list.containsALL(list2); 

// 람다식 사용하여 요소를 제거
list.removeIf(x -&gt; x % 2 == 0) // list 에서 짝수인 수를 모두 제거 
</code></pre>
<h3 id="array-to-list--list-to-array--배열-↔-리스트">Array to List / List to Array / 배열 ↔ 리스트</h3>
<p>프로그래머스 문제를 풀 때 많이 사용하는 패턴이다. 프로그래머스는 백준과 달리 리턴 값의 형태가 중요하기 때문에 이에 주의해 알고리즘을 구현해야 한다. </p>
<pre><code class="language-java">// 문자열 타입 배열을 List로 변환
String[] temp = {&quot;apple&quot;, &quot;banana&quot;, &quot;lemon&quot;};
List&lt;String&gt; list = new ArrayList&lt;&gt;(Arrays.asList(temp));

// List를 문자열 배열로 변환
List&lt;String&gt; list = new ArrayList&lt;&gt;();
String[] temp = list.toArray(new String[list.size()]);

// 정수 배열을 List로 변환
int[] temp = {1, 2, 3, 4};
List&lt;Integer&gt; list = new ArrayList&lt;&gt;(Arrays.asList(temp));

// List를 정수 배열로 변환
List&lt;Integer&gt; list = new ArrayList&lt;&gt;();
int[] temp = list.stream().mapToInt(x -&gt; x).toArray();</code></pre>
<h3 id="collections-관련-메서드">Collections 관련 메서드</h3>
<pre><code class="language-java">int[] temp = {1, 2, 3, 10, 20};
List&lt;Integer&gt; list = new ArrayList&lt;&gt;(Arrays.asList(arr));

// 정수형 List 원소 중 최대, 최소값
Collections.max(list);
Collections.min(list);

// List 정렬
Collections.sort(list); // 오름차순 (ASC)
Collections.sort(list, Collections.reverseOrder()); // 내림차순 (DESC)

// List 뒤집기
Collections.reverse(list);

// List 내 원소의 개수 반환
Collections.frequency(list, 3);

// List 내 원소를 이진탐색을 이용해 찾기
Collections.binarySearch(list, 10); // 3
</code></pre>
<h2 id="3-스택-stack">3. 스택 (Stack)</h2>
<p>스택은 제일 나중에 넣은 데이터를 먼저 꺼낼 수 있는 자료구조이다. 즉, LIFO(Last In First Out)의 특성을 가진다. </p>
<pre><code class="language-java">Stack&lt;Integer&gt; stack = new Stack&lt;&gt;();

// 요소 추가
stack.push(1);

// 요소 제거 (꺼내기)
stack.pop();

// 스택 비우기
stack.clear();

// 스택 크기 체크
stack.size();

// 스택이 비어있는지 유무 확인
stack.empty();

// 스택에 요소가 존재하는지 확인
stack.contains(1);

// 스택 최상단 요소 확인. pop()과 다름
stack.peek();</code></pre>
<h2 id="4-queue-큐">4. Queue (큐)</h2>
<p>큐(Queue)는 먼저 들어간 데이터가 먼저 나오는 자료구조이다. 즉, 선입선출 또는 FIFO(First In First Out)의 특징을 가진다. </p>
<pre><code class="language-java">Queue&lt;Integer&gt; queue = new LinkedList&lt;&gt;();

// 큐에 요소 추가 (enqueue)
queue.add(1); // 문제 상황에서 예외 발생 
queue.offer(2); // 문제 상황에서 false 리턴

// 큐에서 요소 제거 (dequeue)
queue.remove(); // 문제 상황에서 예외 발생
queue.pool(); // 문제 상황에서 null 리턴 

// 큐 비우기
queue.clear(); 

// 큐의 최전방 요소 확인
queue.element();  // 문제 상황에서 예외 발생
queue.peek(); // 문제 상황에서 null 리턴 </code></pre>
<h3 id="arraydeque">ArrayDeque</h3>
<p>자바에서 제공하는 양방항 큐 (Double-ended queue) 구현체를 ArrayDeque라고 한다. Deque 인터페이스를 상속 받는다. 스택이나 큐로 사용하기에 적합하며, 동적 배열을 기반으로 하여 효율적인 성능을 제공한다. </p>
<ol>
<li>양방향 큐 : 앞쪽과 뒤쪽 모두에서 삽입과 삭제가 가능하다.</li>
<li>빠른 성능 : <code>ArrayDeque</code>는 연결 리스트 기반의 <code>LinkedList</code> 보다 더 빠른 성능을 제공하는 경우가 많다. </li>
<li>크기 제한 없음 : 내부 배열은 필요에 따라 자동으로 크기 조정</li>
<li>단일 스레드 환경에서 사용해야 한다. <pre><code class="language-java">ArrayDeque&lt;Integer&gt; deque = new ArrayDeque&lt;&gt;();
</code></pre>
</li>
</ol>
<p>// 삽입 메서드
deque.addFirst(10);    // [10]
deque.addLast(20);     // [10, 20]
deque.offerFirst(5);   // [5, 10, 20]
deque.offerLast(25);   // [5, 10, 20, 25]</p>
<p>// 삭제 메서드
deque.removeFirst();   // 제거: 5 → [10, 20, 25]
deque.removeLast();    // 제거: 25 → [10, 20]
deque.pollFirst();     // 제거: 10 → [20]
deque.pollLast();      // 제거: 20 → []</p>
<p>// 조회 메서드
deque.addLast(30);     // [30]
deque.addLast(40);     // [30, 40]
deque.getFirst();      // 반환: 30
deque.getLast();       // 반환: 40
deque.peekFirst();     // 반환: 30
deque.peekLast();      // 반환: 40</p>
<p>// 기타 메서드
deque.size();          // 반환: 2
deque.contains(30);    // 반환: true
deque.isEmpty();       // 반환: false
deque.clear();         // [ ]
deque.isEmpty();       // 반환: true
deque.addLast(50);     // [50]
deque.addLast(60);     // [50, 60]
Object[] array = deque.toArray(); // [50, 60]</p>
<pre><code>- 여기서 `peek()`은 **맨 앞(혹은 맨 뒤) 요소를 반환만 하고 제거하지 않는다**.
- 반대로, `poll()`은 **맨 앞 (혹은 맨 뒤) 요소를 반환 후 제거**한다. 
```java
ArrayDeque&lt;Integer&gt; deque = new ArrayDeque&lt;&gt;();
deque.addLast(10);
deque.addLast(20);

// peekFirst(): 앞 요소 반환 (제거x)
System.out.println(deque.peekFirst()); // 10
System.out.println(deque); // 10 20

// pollFirst(): 앞 요소 반환 후 제거
System.out.println(deque.pollFirst()); // 10
System.out.println(deque); // 20 </code></pre><h3 id="linkedlist-연결-리스트">LinkedList (연결 리스트)</h3>
<p><strong>LinkedList</strong>는 <strong>List 인터페이스와 Deque 인터페이스를 모두 구현하는 클래스</strong>이다. 즉, List 인터페이스와 Deque 인터페이스의 메서드를 모두 지원한다. 순차 저장과 삽입/삭제가 빠른 특징이 있다. 
<strong>- 앞/뒤 추가/삭제는 O(1)
**- 중간 접근/삭제/검색은 O(n)</strong></p>
<pre><code class="language-java">// LinkedList 선언
LinkedList&lt;Integer&gt; list = new LinkedList&lt;&gt;();

// 요소 추가 (List 메서드)
list.add(10);              // [10]
list.add(1, 20);           // [10, 20]
list.add(30);              // [10, 20, 30]

// 요소 접근 및 수정
list.get(1);               // 반환: 20
list.set(1, 25);           // [10, 25, 30]

// 요소 삭제
list.remove(1);            // 제거: 25 → [10, 30]
list.removeFirst();        // 제거: 10 → [30]
list.removeLast();         // 제거: 30 → []

// 앞/뒤 삽입 (Deque 메서드)
list.addFirst(5);          // [5]
list.addLast(15);          // [5, 15]
list.offerFirst(1);        // [1, 5, 15]
list.offerLast(20);        // [1, 5, 15, 20]

// 앞/뒤 요소 확인
list.getFirst();           // 반환: 1
list.getLast();            // 반환: 20
list.peekFirst();          // 반환: 1
list.peekLast();           // 반환: 20

// 앞/뒤 요소 제거
list.pollFirst();          // 제거 및 반환: 1 → [5, 15, 20]
list.pollLast();           // 제거 및 반환: 20 → [5, 15]

// 기타 메서드
list.size();               // 반환: 2
list.contains(15);         // 반환: true
list.isEmpty();            // 반환: false
list.toArray();            // 배열로 변환: [5, 15]
list.clear();              // 모두 제거
list.isEmpty();            // 반환: true</code></pre>
<h3 id="priorityqueue-우선순위-큐">PriorityQueue (우선순위 큐)</h3>
<p>우선순위 큐(PriorityQueue)는 Queue 인터페이스의 구현체 중 하나이다. 요소를 저장할 때 자동으로 우선순위를 부여하고, 요소를 꺼낼 때 우선순위가 가장 높은 요소부터 반환한다. </p>
<ul>
<li>내부적으로 Heap(이진 트리) 구조를 사용해 효율적인 삽입/삭제 (O(log n))를 지원한다.</li>
<li>기본적으로 Comparable에 따라 우선순위를 매기며, Comparator를 지정하면 사용자 정의 하에 우선순위로 동작이 가능하다. </li>
</ul>
<pre><code class="language-java">// 선언 (기본: 오름차순 정렬)
PriorityQueue&lt;Integer&gt; pq = new PriorityQueue&lt;&gt;();

// 요소 추가
pq.add(30);          // [30]
pq.offer(10);        // [10, 30]
pq.add(20);          // [10, 30, 20]

// 우선순위 가장 높은 요소 조회 (제거X)
pq.peek();           // 반환: 10

// 우선순위 가장 높은 요소 제거 (제거O)
pq.poll();           // 제거: 10 → [20, 30]

// 가장 높은 요소 제거 (예외 발생 가능)
pq.remove();         // 제거: 20 → [30]

// 특정 요소 포함 여부 확인
pq.contains(30);     // 반환: true

// 크기 확인
pq.size();           // 반환: 1

// 비어있는지 확인
pq.isEmpty();        // 반환: false

// 배열로 변환
Object[] arr = pq.toArray(); // [30]

// 모든 요소 제거
pq.clear();          // []

// Comparator를 사용한 내림차순 우선순위 큐
PriorityQueue&lt;Integer&gt; pqDesc = new PriorityQueue&lt;&gt;(Comparator.reverseOrder());
pqDesc.add(3);       // [3]
pqDesc.add(1);       // [3, 1]
pqDesc.add(2);       // [3, 1, 2]
pqDesc.peek();       // 반환: 3
</code></pre>
<h2 id="5-hashmap해시맵-hashset해시셋">5. HashMap(해시맵), HashSet(해시셋)</h2>
<h3 id="hashmap">HashMap</h3>
<p><code>Map</code> 인터페이스의 구현체이다(<code>Map&lt;K, V&gt;</code>). <code>&lt;key, value&gt;</code> 쌍의 특징을 가지고, value만 중복을 허용한다. 또한, null 허용과 관련해 key는 1개, value는 여러 개 가능하다. 또한, 순서를 보장하지 않는다. 해시 테이블을 기반으로 하여 평균 <code>O(1)</code>에 가까운 접근 시간을 제공해 주로 검색에 많이 쓰인다. </p>
<pre><code class="language-java">HashMap&lt;Integer, String&gt; hashMap = new HashMap&lt;&gt;();

// 요소 추가
hashMap.put(1, &quot;딸기&quot;);
hashMap.put(2, &quot;바나나&quot;);
hashMap.put(1, &quot;사과&quot;); // (1. &quot;딸기&quot;)의 value가 &quot;사과&quot;로 대체됨 

// 키에 해당하는 값 조회
hashMap.get(1);
hashMap.get(2);
// 키에 해당하는 값이 없으면 null을 반환한다. 
hashMap.get(3); 

// null 대신 기본 값을 반환할 수 있는 getOrDefault() 메서드 
System.out.println(map.getOrDefault(1, &quot;default value1&quot;)); // 1
System.out.println(map.getOrDefault(2, &quot;defalut value2&quot;)); // 2
System.out.println(map.getOrDefault(3, &quot;default value3&quot;)); // default value3

// 요소 삭제 
hashMap.remove(1); // key가 1인 요소 삭제

// 전체 삭제
hashMap.clear(); 

// key 포함 여부 확인
hashMap.containsKey(1); 

// value 포함 여부 확인
hashMap.containsValue(&quot;사과&quot;);

// key - value 출력
for (Integer key : hashMap.keySet()) {
                System.out.prinlnt(key + &quot; &quot; + hashMap.get(key));
}

for (Entry&lt;Integer, String&gt; temp : hashMap.entrySet()) {
                System.out.println(temp.getKey() + &quot; &quot; + temp.getValue());
}
</code></pre>
<h3 id="hashset">HashSet</h3>
<p><code>Set</code> 인터페이스의 구현체이다(<code>Set&lt;E&gt;</code>). HashSet은 Key값만 저장하지만 HashMap과 달리 중복을 허용하지 않는다. 1개의 null 값을 허용하고, HashMap과 마찬가지로 순서를 보장하지 않는다. 내부적으로 HashMap을 사용하고, value는 dummy object이다. HashMap과 같이 평균적으로 O(1)에 가까운 검색 성능을 보장한다. </p>
<pre><code class="language-java">HashSet&lt;Integer&gt; hashSet = new HashSet&lt;&gt;();
HashSet&lt;Integer&gt; hashSet2 = new HashSet&lt;&gt;();

// 요소 추가
hashSet.add(1);

// 요소 삭제
hashSet.remove(1); // 값이 1인 요소 삭제

// 차집합 
hashSet.removeAll(hashSet2); 

// 교집합
hashSet.retainAll(hashSet2);

// 데이터 초기화
hashSet.clear();

// hashSet 사이즈 확인
hashSet.size();

// 특정 요소 포함 여부 확인
hashSet.contains(1);

// 요소 전체 출력 
// Iterator 사용
Iterator tempIterator = hashSet.iterator();
while (tempIterator.hasNext()) {
                System.out.println(tempIterator.next());
}

// for-each문 사용
for (String item : hashSet) {
                System.out.println(item);
}</code></pre>
<p>이렇게 정리를 끝마쳤다. 사실, 컬렉션 프레임워크 종류가 워낙 방대하고, 내가 못 다룬 부분도 분명 있을 테지만 대부분 여기에 다룬 것 같다. 정리한다고 여러 블로그, 책, GPT를 참고해서 노션에 정리했지만 사실 귀찮아서(?) 미루고 또 미뤘지만 결국 정리에 성공했다....(정리하느라 너무 힘들긴 했다...ㅋㅋㅋ) 분명 틀린 부분도 있을텐데 계속 보면서 수정해야 할 것 같다. 자바 코딩테스트 공부에 도움이 되면 좋겠다! </p>
<h3 id="참고">참고</h3>
<ul>
<li><a href="https://velog.io/@kkyes1210/JAVA-%EB%AC%B8%EB%B2%95-%EC%A0%95%EB%A6%AC-for-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8">https://velog.io/@kkyes1210/JAVA-%EB%AC%B8%EB%B2%95-%EC%A0%95%EB%A6%AC-for-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8</a></li>
<li><a href="https://hudi.blog/java-collection-framework-1/">https://hudi.blog/java-collection-framework-1/</a></li>
<li><a href="https://product.kyobobook.co.kr/detail/S000212576322">코딩 테스트 합격자 되기: 자바 편
</a></li>
<li><a href="https://product.kyobobook.co.kr/detail/S000212853100">이것이 자바다</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] Date Functions (날짜 함수)]]></title>
            <link>https://velog.io/@assdd_123/SQL-Date-Functions-%EB%82%A0%EC%A7%9C-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@assdd_123/SQL-Date-Functions-%EB%82%A0%EC%A7%9C-%ED%95%A8%EC%88%98</guid>
            <pubDate>Sat, 31 May 2025 05:13:27 GMT</pubDate>
            <description><![CDATA[<h3 id="0-date-functions-날짜-함수">0. Date Functions (날짜 함수)</h3>
<p>프로그래머스 고득점 Kit에서 날짜 함수 관련 문제를 풀다 모르거나 헷갈리는 문법이 많았다. 그래서 한번 정리를 해봤다. 주요 함수는 아래와 같다.</p>
<h3 id="1-sysdate-현재-날짜와-시간">1. <code>SYSDATE</code>: 현재 날짜와 시간</h3>
<pre><code class="language-sql">SELECT SYSDATE AS NOW
FROM DUAL;</code></pre>
<h3 id="2-current_date--세션-기준-현재-날짜">2. <code>CURRENT_DATE</code> : 세션 기준 현재 날짜</h3>
<pre><code class="language-sql">SELECT CURRENT_DATE AS SESSION_NOW
FROM DUAL;</code></pre>
<h3 id="3-날짜-→-문자열-변환-to_char">3. 날짜 → 문자열 변환 (<code>TO_CHAR()</code>)</h3>
<pre><code class="language-sql">SELECT FIRST_NAME, LAST_NAME, TO_CHAR(HIRE_DATE, &#39;YYYY-MM-DD&#39;) AS HIRED
FROM EMPLOYEES
WHERE HIRE_DATE BETWEEN DATE &#39;2016-01-01&#39; AND DATE &#39;2016-12-31&#39;
ORDER BY FIRST_NAME, LAST_NAME;</code></pre>
<ul>
<li><code>YYYY</code> – 연도 (4자리)</li>
<li><code>MM</code> – 월 (2자리)</li>
<li><code>DD</code> – 일 (2자리)</li>
<li><code>HH24</code> – 24시간 포맷</li>
<li><code>MI</code> – 분</li>
<li><code>SS</code> – 초</li>
<li><code>DY</code> – 요일 (약어 표시 ex. SUN, MON…)</li>
<li><code>MONTH</code> – 전체 달 이름</li>
</ul>
<h3 id="4-연-월-일-추출-extract-">4. 연, 월, 일 추출 (<code>EXTRACT</code> )</h3>
<h3 id="대여-시작일에서-연도월일-추출">대여 시작일에서 연도/월/일 추출</h3>
<pre><code class="language-sql">SELECT HISTORY_ID, CAR_ID,
             EXTRACT(YEAR FROM START_DATE) AS START_YEAR,
             EXTRACT(MONTH FROM START_DATE) AS START_MONTH,
             EXTRACT(DAY FROM START_DATE) AS START_DAY
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY;</code></pre>
<h3 id="5-문자열-→-날짜-변환-to_date">5. 문자열 → 날짜 변환 (<code>TO_DATE()</code>)</h3>
<pre><code class="language-sql">SELECT 
    USER_ID,
    FIRST_NAME,
    LAST_NAME,
    JOINED_DATE
FROM 
    USERS
WHERE 
    JOINED_DATE = TO_DATE(&#39;2025-03-20&#39;, &#39;YYYY-MM-DD&#39;);


### 5. 날짜 간 차이 (`END_DATE - START_DATE` 또는 `TRUNC` , `MONTH_BETWEEN` )

### 대여 기간 (일 수 계산)

```sql
SELECT HISTORY_ID, CAR_ID,
             START_DATE,
             END_DATE,
             END_DATE - START_DATE AS RENTAL_DAYS
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY;</code></pre>
<h3 id="6-month_between---개월-단위-차이">6. <code>MONTH_BETWEEN</code>  : 개월 단위 차이</h3>
<pre><code class="language-sql">SELECT HISTORY_ID, CAR_ID,
             MONTHS_BETWEEN(END_DATE, START_DATE) AS RENTAL_MONTH_DIFF
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY;</code></pre>
<h3 id="7-월-말일-구하기-last_day-">7. 월 말일 구하기 (<code>LAST_DAY</code> )</h3>
<pre><code class="language-sql">SELECT HISTORY_ID, CAR_ID,
             START_DATE, 
             LAST_DAY(START_DATE) AS START_MONTH_END
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY; </code></pre>
<h3 id="8-다음-특정-요일-구하기-next_day">8. 다음 특정 요일 구하기 (<code>NEXT_DAY</code>)</h3>
<pre><code class="language-sql">SELECT HISTORY_ID, CAR_ID,
             START_DATE,
             NEXT_DAY(START_DATE, &#39;MONDAY&#39;) AS NEXT_MONDAY
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY;</code></pre>
<h3 id="9-몇-개월-뒤-날짜-add_months">9. 몇 개월 뒤 날짜 (<code>ADD_MONTHS</code>)</h3>
<ul>
<li>** 대여 시작일 기준 3개월 뒤 날짜**</li>
</ul>
<pre><code class="language-sql">SELECT HISTORY_ID, CAR_ID,
             START_DATE,
             ADD_MONTHS(START_DATE, 3) AS AFTER_3_MONTHS
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY;</code></pre>
<h3 id="10-특정-조건으로-날짜-비교-where--to_date-">10. 특정 조건으로 날짜 비교 (<code>WHERE</code> + <code>TO_DATE</code> )</h3>
<ul>
<li>**2022년 10월 이후에 시작한 대여</li>
<li>*<pre><code class="language-sql">SELECT *
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE START_DATE &gt;= TO_DATE(&#39;2022-10-01&#39;, &#39;YYYY-MM-DD&#39;);</code></pre>
</li>
</ul>
<h3 id="11-날짜-시간-제거-trunc">11. 날짜 시간 제거 (<code>TRUNC</code>)</h3>
<pre><code class="language-sql">SELECT HISTORY_ID, CAR_ID,
             TRUNC(START_DATE) AS START_DATE_TRUNC,
             TRUNC(END_DATE) AS END_DATE_TRUNC
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY;</code></pre>
<p>막상 정리하고 나니깐 <code>TO_CHAR()</code>, <code>TO_DATE()</code>, <code>EXTRACT()</code>, <code>MONTH_BETWEEN()</code> 이외에는 별로 안 쓰이는 것 같다 ㅎㅎ
그래도 이번 기회에 정리하니깐 이제 더 이상 까먹을 일은 없을 것 같아 다행이다.</p>
<h3 id="참고">참고</h3>
<p><a href="https://www.oracletutorial.com/oracle-date-functions/oracle-to_date/">Oracle Date Functions</a>
<a href="https://school.programmers.co.kr/learn/courses/30/parts/17047">프로그래머스 String, Date</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] RIGHT (OUTER) JOIN]]></title>
            <link>https://velog.io/@assdd_123/SQL-RIGHT-OUTER-JOIN</link>
            <guid>https://velog.io/@assdd_123/SQL-RIGHT-OUTER-JOIN</guid>
            <pubDate>Tue, 27 May 2025 03:04:59 GMT</pubDate>
            <description><![CDATA[<h2 id="right-outer-join-절-개념">RIGHT (OUTER) JOIN 절 개념</h2>
<p><code>RIGHT JOIN</code> 도 이전에 배운 <code>INNER JOIN</code> 과 <code>LEFT JOIN</code> 과 마찬가지로 <code>SELECT</code> 문의 optional 절이다. </p>
<p>단지 <code>LEFT JOIN</code> 과 차이가 있다면, <code>RIGHT JOIN</code> 은 <strong>오른쪽 테이블에 있는 모든 행들을 리턴하고, 왼쪽 테이블에 있는 매칭되는 행들을 리턴</strong> 한다는 점이다.</p>
<p>문법은 다음과 같다.</p>
<pre><code class="language-sql">SELECT COLUMN_LIST
FROM X RIGHT JOIN Y ON X.ID = Y.ID;</code></pre>
<p>RIGHT JOIN 말고도 RIGHT OUTER JOIN으로 표현해도 된다. 여기서는 표기의 편리함을 위해 RIGHT JOIN으로 표시하고자 한다.</p>
<pre><code class="language-sql">SELECT COLUMN_LIST
FROM X RIGHT OUTER JOIN Y ON X.ID = Y.ID;</code></pre>
<h2 id="right-join절-동작-원리">RIGHT JOIN절 동작 원리</h2>
<p>두 테이블 <code>X</code> 와 <code>Y</code> 가 있다고 하자. 그리고 <code>RIGHT JOIN</code> 을 이용해서 두 테이블에 있는 행들을 하나로 병합할려고 한다.</p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/c21a92d7-2f29-443f-85a7-b5584b6c9f45/image.png" alt=""></p>
<p>위와 같이 <code>X</code> 테이블에는 2개의 컬럼인 <code>id</code> (키)와 <code>x</code> 가 있다고 하자. 그리고 <code>Y</code> 테이블에는 <code>id</code> (키)와 <code>y</code> 가 있다고 하자.</p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/3f1bddbd-3ea6-4b1d-ab0d-4da5627f3dab/image.png" alt=""></p>
<p>RIGHT JOIN을 통해서 오른쪽 테이블인 <code>Y</code> 테이블에 있는 모든 행들과 왼쪽 테이블 <code>Y</code> 에서 매칭되는 행들을 반환한다. 만약, 오른쪽 테이블의 행이 왼쪽 테이블 <code>X</code> 에 있는 행과 매칭되는게 없다면, 왼쪽 테이블 <code>X</code> 의 컬럼들에 대해 <code>NULL</code> 값을 사용한다.</p>
<p>정말 말 그대로 LEFT JOIN의 반대라고 생각하면 된다. 그리고 이를 벤 다이어그램으로 표현하면 테이블 Y 전체를 표현하는 것과 같다. 모습은 아래와 같다.</p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/a7cc0787-9d60-4b6c-92ad-34c56f244ca1/image.png" alt=""></p>
<h2 id="right-join-쿼리-예시">RIGHT JOIN 쿼리 예시</h2>
<p>지난 번과 마찬가지로 <code>ORDER</code> 테이블과 <code>EMPLOYEES</code> 테이블을 사용할 것이다. 각 테이블들의 연관관계는 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/dc69b676-71e1-4305-8bf1-913061b2f84a/image.png" alt=""></p>
<p>판매 사원이 최소 1개에서 많게는 여러 개의 판매 주문을 담당할 수 있다는 것을 가정해보자. 하지만, 몇몇 주문들은 판매 사원의 담당이 아닐 수가 있다.</p>
<p>이를 쿼리로 표현하면 다음과 같다.</p>
<pre><code class="language-sql">SELECT FIRST_NAME, LAST_NAME, ORDER_ID, STATUS 
FROM ORDERS RIGHT JOIN EMPLOYEES ON EMPLOYEE_ID = SALESMAN_ID
WHERE JOB_TITLE = &#39;Sales Representative&#39;
ORDER BY FIRST_NAME, LAST_NAME;</code></pre>
<p>해당 쿼리를 실행하면 결과는 다음과 같이 나온다. </p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/19555dca-4626-4541-996f-da37d4f9ebcc/image.png" alt=""></p>
<p>여기서 주목해야 될 점은, 단 하나의 판매 주문을 담당하지 않는 판매 사원에 대해서는 <code>ORDER_ID</code> 와 <code>STATUS</code> 컬럼들에 대해 <code>NULL</code> 값을 채운다는 것이다.</p>
<h3 id="using-절을-이용한-right-outer-join-표현"><code>USING</code> 절을 이용한 RIGHT OUTER JOIN 표현</h3>
<p><code>USING</code> 절을 이용해서 INNER JOIN, LEFT JOIN을 배웠을 때와 마찬가지로 <code>RIGHT OUTER JOIN</code>을 표현할 수 있다. 문법은 다음과 같고 아래 쿼리를 실행하면 다음과 같다.</p>
<pre><code class="language-sql">SELECT COLUMN_LIST
FROM X RIGHT JOIN Y USING(ID);</code></pre>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/3b46cfb0-503a-42aa-a346-b4129d130abe/image.png" alt=""></p>
<p>고객이 판매 주문 정보를 가지지 않는다면, <code>ORDER_ID</code> 와 <code>STATUS</code> 칼럼이 <code>NULL</code> 값으로 채워져 있는 것을 알 수 있다.</p>
<p>즉, <code>RIGHT JOIN</code> 을 사용해서 오른쪽 테이블에 있는 모든 행들과 왼쪽 테이블에 이와 매칭되는 행들을 포함시킬 수 있다. </p>
<h2 id="참고">참고</h2>
<p><a href="https://www.oracletutorial.com/oracle-basics/oracle-right-join/">Oracle RIGHT OUTER JOIN Clause</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] LEFT (OUTER) JOIN]]></title>
            <link>https://velog.io/@assdd_123/SQL-LEFT-OUTER-JOIN</link>
            <guid>https://velog.io/@assdd_123/SQL-LEFT-OUTER-JOIN</guid>
            <pubDate>Tue, 27 May 2025 02:59:50 GMT</pubDate>
            <description><![CDATA[<h2 id="left-join절-개념과-동작-원리">LEFT JOIN절 개념과 동작 원리</h2>
<ul>
<li><code>SELECT</code> 문의 옵션절</li>
<li>두 테이블로부터 열들 합치도록 함</li>
<li>첫 번째 테이블이 <strong>LEFT TABLE,</strong> 두 번째 테이블이 <strong>RIGHT TABLE</strong></li>
</ul>
<p><code>LEFT JOIN</code> 은 <strong>왼쪽 테이블에 있는 모든 행(rows)을 리턴</strong>하고, <strong>오른쪽 테이블에 있는 매칭되는 행들(rows)을 리턴한다.</strong></p>
<p>문법은 다음과 같다.</p>
<pre><code class="language-sql">SELECT 
    column_list
FROM
    X
LEFT JOIN Y ON X.id = Y.id;</code></pre>
<p>여기서 <code>LEFT JOIN</code> 은 왼쪽 테이블인 <code>X</code> 의 <code>id</code> 칼럼의 값들을 오른쪽 테이블인 <code>Y</code> 의 칼럼의 값들과 매치한다.</p>
<p>여기서 값들이 같다면, 양쪽 테이블에서 두 개의 열들을 합친다. 만약 왼쪽 테이블에 있는 열이 오른쪽 테이블에 있는 열과 매칭되는게 없다면, <code>LEFT JOIN</code> 은 왼쪽 테이블에 있는 행을 오른쪽 테이블에 있는 행과 합친다. 오른쪽 테이블에 있는 열들을 <code>NULL</code> 값으로 채운다.</p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/342d8d5d-eded-446b-bbb7-4fbb2bffdc24/image.png" alt=""></p>
<ul>
<li>테이블은 2개의 컬럼인 <code>id</code> (키)와 <code>x</code></li>
<li><code>Y</code> 테이블은 2개의 컬럼인 <code>id</code> (키)와 <code>y</code></li>
</ul>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/c0d276ac-10f8-4905-b7cd-38193df0fc27/image.png" alt=""></p>
<p>left join은 왼쪽 테이블인 X 의 모든 행들과 오른쪽 테이블인 Y 에 있는 매칭되는 값들을 포함한다. </p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/a169c0d0-09f2-462b-b78a-1a5fdb80869e/image.png" alt="">
이를 벤 다이어그램으로 표현하면, 테이블 X 전체를 다 표현하는 것과 같다.</p>
<h2 id="left-join절-예시">LEFT JOIN절 예시</h2>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/330c4a5d-42b0-4fcd-8e8d-3d06e3c72d30/image.png" alt=""></p>
<p>관계형 데이터베이스는 각 테이블들의 관계를 표현하는 데이터베이스이다. 여기서 주문 정보를 나타내는 <code>ORDERS</code> 테이블과 판매 직원의 정보를 나타내는 <code>EMPLOYEES</code> 테이블이 있다고 하자. </p>
<p>여기서 <code>ORDERS</code> 테이블의 <code>SALESMAN_ID</code> 컬럼은 <code>EMPLOYEES</code> 테이블의 Primary Key인 <code>EMPLOYEE_ID</code>  를 참조한다. 즉, <code>SALESMAN_ID</code> 는 외래키이다.</p>
<pre><code class="language-sql">SELECT ORDER_ID, STATUS, FIRST_NAME, LAST_NAME
FROM ORDERS
LEFT JOIN EMPLOYEES 
ON EMPLOYEES ON EMPLOYEE_ID = SALESMAN_ID
ORDER BY ORDER_DATE DESC;</code></pre>
<p>해당 쿼리를 작성하면 쿼리 결과는 다음과 같이 나오는 것을 알 수 있다. </p>
<p>즉, <code>LEFT JOIN</code> 을 사용하면 왼쪽 테이블인 <code>ORDERS</code> 테이블에 있는 모든 행들을 리턴하고, <code>EMPLOYEES</code> 테이블과 매칭되는 행을 가지지 않는 행들에 대해서는 <code>FIRST_NAME</code>, <code>LAST_NAME</code>과 같은 컬럼에 대해서 <code>NULL</code> 값을 채운다.</p>
<h2 id="left-join-절-사용해서-3개의-테이블-합치기">LEFT JOIN 절 사용해서 3개의 테이블 합치기</h2>
<p>테이블 3개를 LEFT JOIN 절을 사용해서 합칠 때도 위와 별반 다를게 없다. 다음 쿼리를 실행한 결과는 아래와 같다. </p>
<pre><code class="language-sql">SELECT ORDER_ID, NAME AS CUSTOMER_NAME, STATUS, FIRST_NAME, LAST_NAME
FROM ORDERS
         LEFT JOIN EMPLOYEES ON EMPLOYEE_ID = SALESMAN_ID
         LEFT JOIN CUSTOMERS ON CUSTOMERS.CUSTOMER_ID = ORDERS.CUSTOMER_ID
ORDER BY 
         ORDER_DATE DESC;
</code></pre>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/63f3d754-2edd-496f-b12f-97e38e2322fe/image.png" alt=""></p>
<p>매칭되지 않는 행들에 대해서는 <code>null</code> 값으로 채워진 것을 알 수 있다.</p>
<h2 id="using-절을-사용한-left-join-표현">USING 절을 사용한 LEFT JOIN 표현</h2>
<p><code>USING</code> 절을 사용해서 테이블을 합치는 것을 표현할 수 있음을 배웠다. 그러면 <code>LEFT JOIN</code> 을 사용할 때도 이를 똑같이 적용할 수 있다.</p>
<pre><code class="language-sql">SELECT 
    COLUMN_LIST
FROM 
    X
    LEFT JOIN Y USING (id);</code></pre>
<p>여기서 <code>LEFT JOIN</code> 은 <code>X</code> 테이블의 <code>id</code> 컬럼의 값들이 <code>Y</code> 테이블의 <code>id</code> 컬럼의 값들과 같은지 체크한다.</p>
<p><code>USING</code> 절을 이용한 표현은 다음과 같다.</p>
<pre><code class="language-sql">USING (id)
ON X.id = Y.id</code></pre>
<h2 id="using-절을-이용한-쿼리-예시">USING 절을 이용한 쿼리 예시</h2>
<pre><code class="language-sql">SELECT 
    NAME, 
    ORDER_ID,
    STATUS,
    ORDER_dATE
FROM 
    CUSTOMERS
LEFT JOIN ORDERS 
USING (CUSTOMER_ID)
ORDER BY NAME; </code></pre>
<p>해당 쿼리를 실행하면 다음과 같이 결과가 나오는 것을 알 수 있다. </p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/6e38a5f0-2c45-4cf5-b4b9-8dc9bf802406/image.png" alt=""></p>
<p>고객이 어떠한 주문을 하지 않았다면, <code>LEFT JOIN</code> 을 통해 <code>ORDERS</code> 테이블의 컬럼(열)들을 <code>NULL</code> 값으로 채운 것을 알 수 있다. </p>
<p>즉, <code>LEFT JOIN</code> 절을 통해 왼쪽 테이블에 있는 모든 행들을 리턴하고 오른쪽 테이블에는 매칭되는 행들을 리턴한다. 매칭되는 행이 다면 <code>NULL</code> 값으로 채운다는 것을 알 수 있다.</p>
<p>그리고 <code>LEFT JOIN</code> 을 <code>LEFT OUTER JOIN</code> 으로 표현할 수 있다. 둘은 다른 의미가 아니고 단지 표현 방식이 다를 뿐이다. <code>LEFT OUTER JOIN</code> 을 써서 테이블을 합치고자 한다면 다음과 같이 쿼리를 작성하면 된다.</p>
<pre><code class="language-sql">SELECT ORDER_ID, STATUS, FIRST_NAME, LAST_NAME
FROM ORDERS
LEFT OUTER JOIN EMPLOYEES 
ON EMPLOYEES ON EMPLOYEE_ID = SALESMAN_ID
ORDER BY ORDER_DATE DESC;</code></pre>
<h3 id="참고">참고</h3>
<p><a href="https://www.oracletutorial.com/oracle-basics/oracle-left-join/">Oracle LEFT JOIN Clause</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] INNER JOIN ]]></title>
            <link>https://velog.io/@assdd_123/SQL-INNER-JOIN</link>
            <guid>https://velog.io/@assdd_123/SQL-INNER-JOIN</guid>
            <pubDate>Tue, 27 May 2025 02:54:39 GMT</pubDate>
            <description><![CDATA[<h2 id="inner-join-개념">INNER JOIN 개념</h2>
<p>다른 테이블과 매칭되는 열들이 있는 테이블로부터 열을 추출하고 싶을 때 <code>INNER JOIN</code> 을 사용할 수 있다. 즉, JOIN은 여러 테이블의 관련 있는 데이터를 하나로 결합해 조회하는 SQL 구문이다.</p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/73649c45-5918-4008-b2d5-20f6f4d91224/image.png" alt=""></p>
<pre><code class="language-sql">SELECT 
    column_list
FROM
    X
    INNER JOIN Y ON X.id = Y.id;</code></pre>
<ul>
<li><code>ON</code> 키워드 뒤에 join 조건을 정의한다. 여기서 join 조건이란 두 테이블을 결합하는데 필요한 조건들을 말한다.</li>
<li>Oracle은 그러면 먼저 <code>FROM</code> 절을 평가하고, 그리고 <code>INNER JOIN</code>, 마지막으로 <code>SELECT</code> 절을 평가한다.</li>
</ul>
<h2 id="inner-join-동작과정">INNER JOIN 동작과정</h2>
<ol>
<li><code>INNER JOIN</code> 이 X와 Y 테이블 모두에 존재하는 <code>id</code> 컬럼의 값을 비교한다.</li>
<li>그리고 id 컬럼의 값들이 같다면 두 테이블로부터 매칭되는 열들의 값을 합친다.</li>
<li>최종적으로 <code>SELECT</code> 절이 명시된 값(<code>column_list</code>)을 반환한다.</li>
</ol>
<p>자 그러면 어떻게 Oracle에서 INNER JOIN이 성립되는지 알아보자.</p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/c0de0009-4609-4527-b760-ad297234c3ea/image.png" alt=""></p>
<p>여기 두 개의 테이블 <code>X</code> 와 <code>Y</code> 가 있다. <code>INNER JOIN</code> 을 사용해서 두 테이블에 있는 row들을 합칠려고 한다.</p>
<ul>
<li>X 테이블은 2개의 컬럼 : <code>id</code> (키), <code>x</code> 를 가진다.</li>
<li>Y 테이블도 2개의 컬럼 : <code>id</code> (키), <code>y</code> 를 가진다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/0be1ba29-e971-4217-96e3-82c24cb11b00/image.png" alt=""></p>
<p>INNER JOIN을 통해 <code>id</code> 컬럼에서 매칭되는 값들을 가지는 두 개의 테이블로부터 rows(행들)을 포함할 수 있다. 다만, 매칭되지 않는 열들은 결과에 포함시키지 않는다.</p>
<p>이렇게 INNER JOIN을 벤 다이어그램으로 표현하면 마치 두 집합의 <strong>교집합</strong>을 찾는 것과 같다.</p>
<p><img src="https://velog.velcdn.com/images/assdd_123/post/2461bedf-d503-4917-a9af-7519b52d0b8a/image.png" alt=""></p>
<pre><code class="language-sql">SELECT *
FROM orders INNER JOIN order_items 
ON order_items.order_id = orders.order_id
ORDER BY order_date DESC;</code></pre>
<h2 id="using-절을-이용한-inner-join-표현">USING 절을 이용한 INNER JOIN 표현</h2>
<pre><code class="language-sql">SELECT 
    *
FROM
    X
INNER JOIN Y USING (c1, c2, ...);</code></pre>
<p>위에서 본 <code>ON</code> 절과 마찬가지로, 테이블을 합칠 때 어떤 칼럼이 같은 지를 표시하기 위해 <code>USING</code> 절을 활용할 수 있다.</p>
<pre><code class="language-sql">SELECT 
    *
FROM 
    orders
INNER JOIN order_items USING( order_id )
ORDER BY 
    order_date DESC;</code></pre>
<h3 id="참고">참고</h3>
<p><a href="https://www.oracletutorial.com/oracle-basics/oracle-inner-join/">Oracle INNER JOIN Clause</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[회고] 3,4월 회고]]></title>
            <link>https://velog.io/@assdd_123/%ED%9A%8C%EA%B3%A0-34%EC%9B%94-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@assdd_123/%ED%9A%8C%EA%B3%A0-34%EC%9B%94-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Tue, 22 Apr 2025 15:10:16 GMT</pubDate>
            <description><![CDATA[<p>작년 9월부터 진행했던 프디아가 지난 달 3월에 끝났다. 교육 수료 이후 벌써 1달이 지났다. 6개월이 넘는 과정동안 매일 8-9시간의 수업을 듣고 집에 와서 또 추가로 복습하고 2-3개의 프로젝트까지 하느라 정신없이 보냈던 것 같다. </p>
<p>아쉽게도 수료 이후 인턴에는 합격하지 못했지만, 그래도 프디아를 하면서 많은 것을 배웠던 것 같다. </p>
<ul>
<li>프론트를 아예 하지도 못한 내가 UI를 만들고, 백엔드 API와 연결할 수 있게 되었다.</li>
<li>그리고 AWS에 대해 어느 정도 익숙해져 아키텍처도 이제 능숙하게 그릴 줄 알고 서비스에 맞게 이를 구축할 수 있게 되었다.</li>
<li>오픈 API를 활용한 프로젝트를 2번 수행하며 금융 데이터가 어떻게 처리되고 이를 API로 구현해 어떻게 배포할 수 있게 되었는지 배웠다.</li>
</ul>
<p>*<em>- 그리고 무엇보다 단기간에 압축적으로 성장한게 가장 큰 것 같다. *</em></p>
<p>작년 이맘때쯤에 나는 전공자임에도 불구하고 그간 코딩을 등한시해 프로젝트 경험도 얼마 없던 채로 졸업 프로젝트를 진행하고 있었다. 하지만 졸업 이후, 프디아 교육과정을 수료하며 미니 프로젝트, 프론트, 파이널 프로젝트까지 진행하며 프로젝트 경험을 많이 쌓을 수 있었다. 또한, 능력있는 팀원들을 만나 너무 많은 도움을 받을 수 있었다.</p>
<p>사실 회고록을 수료하고 저번 달에 써야 되는게 맞지만, 이제라도 안 쓰면 아무것도 안 할 것 같아서 쓰게 되었다.</p>
<p>사실 프디아를 하면서 아쉬웠던 점은 다음과 같다.</p>
<ul>
<li><p>시간에 쫓겨 코드를 짜는데 깊게 생각하지 못한 것 같다.</p>
</li>
<li><p>Docker와 Linux에 대한 이해 없이 Jenkins CI/CD를 무리하게 진행한 점이 아쉬웠다.</p>
</li>
<li><p>AWS Solutions Architect Associate 시험을 한 문제 차이로 떨어진 점도 아쉬웠다.</p>
</li>
<li><p>교육과 프로젝트, 그리고 취업준비를 한다고 코딩테스트를 더 열심히 하지 못한 점이 아쉬웠다.</p>
</li>
<li><p>포트폴리오를 대충 만들기는 했지만 개선하지 안한 점이 아쉬웠다.</p>
</li>
<li><p>뭔가 나 스스로 끝까지 진행한 프로젝트가 없어서 아쉬웠다.</p>
</li>
</ul>
<p>사실 떠오르면 더 있을테지만 대충 이 정도인 것 같다. </p>
<p><strong>그러면 나는 이제 무엇을 해야될까?</strong></p>
<p>당연히 취직을 해야된다!</p>
<p>벌써 1달이란 소중한 시간이 지났다. 취직을 할려면 알다시피 코딩테스트라는 벽을 통과해야 된다. 코딩테스트를 통과해야 면접의 기회가 주어진다. 그래서 당분간은 코딩테스트를 중점적으로 공부할려고 한다.</p>
<p>그리고 자소서를 꾸준하게 작성해서 지원할려고 한다. 사실 수료하고나서도 자소서는 꾸준하게 작성했지만 여러 기업들을 더 지원할려고 한다. 그리고 남는 시간에 CS나 지난 프로젝트 등을 리팩토링 할 계획이다.</p>
<p>앞으로 나의 목표이다.</p>
<ol>
<li><p><strong>코딩테스트 통과할 실력 만들기 (백준, 프로그래머스 최대한 많이 풀고 노션이나 블로그에 정리하기)</strong> -&gt; 제일 중요하다 </p>
</li>
<li><p>토익 시험 응시하기 (금융권 IT는 토익을 더 우대하는 것 같아 응시할려고 한다.)</p>
</li>
<li><p>투자자산운용사 공부하고 합격하기 </p>
</li>
<li><p>프로젝트 리팩토링하기 (이전에 했던 프로젝트들을 정리해서 관련 있는 내용을 블로그에 정리할려고 한다. 그리고 포트폴리오에 정리할려고 한다.)</p>
</li>
<li><p>자소서 많이 쓰면서 바로 면접 준비하기 (자소서와 면접은 하나다)</p>
</li>
<li><p>반드시 올해 안에 취업하기</p>
</li>
</ol>
<p>뭐 이 정도인 것 같다. 눈에 띄는 가시적인 성과를 많이 쌓아야 더 자극이 되면서 부지런히 사는 것 같다. 그동안 너무 게으르게 산 것 같다. 다시 열심히 부지런히 움직일 때가 된 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA (1) - OOP]]></title>
            <link>https://velog.io/@assdd_123/JAVA</link>
            <guid>https://velog.io/@assdd_123/JAVA</guid>
            <pubDate>Mon, 03 Feb 2025 14:37:22 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요. </p>
<p>아마 개발을 하시다 보면 개인적으로 좋아하는 언어가 생길 것이라고 생각합니다. 다들 좋아하시는 언어가 있으신가요? 
저 같은 경우는 학부 시절 수업에서 C++을 주로 많이 사용해서 가장 편하고 익숙한 언어였던 것 같습니다 (<del>처음 포인터 배웠을 때는 엄청 싫어했습니다 ㅎㅎ</del>) </p>
<p>이후에는 주로 웹 백엔드 프로젝트를 수행하면서 JAVA라는 언어가 편해지면서 좋아하게 된 것 같습니다. 아무래도 JAVA가 C++과 비슷한 객체지향 프로그래밍의 성격을 공유하면서도 (클래스, 상속, 다형성 등) 웹과 엔터프라이즈 스케일의 애플리케이션을 주로 개발하는데 사용되기 때문에 그런 것 같다고 생각이 듭니다.</p>
<p>그러면 제가 생각했을 때 중요하다고 생각한 JAVA의 대표적인 특징들을 살펴보고자 합니다. 책이나 블로그, 유튜브에서도 많이 나오는 내용들이지만 제 나름대로 한번 정리하겠습니다. C++을 주로 사용했기에 C++ 기준으로 신기하거나 중요하다고 느꼈던 JAVA의 특징들을 나열하겠습니다.</p>
<h2 id="1-객체지향-프로그래밍-언어">1. 객체지향 프로그래밍 언어</h2>
<p>맞습니다. JAVA는 _<strong>&quot;객체지향 프로그래밍(OOP, Object Oriented Programming) 언어&quot;</strong>_입니다. 그러면 객체지향 프로그래밍이란 무엇일까요? 대부분의 컴퓨터 공학도분들이 단순히 객체를 추상적으로 이해하는 경향이 있을 것이라고 생각합니다. 왜냐하면 학부 입학 시 1학년부터 파이썬이나 C++ 같은 객체지향 언어를 먼저 배우면서 객체지향 패러다임을 당연시 여기기 때문입니다. </p>
<p>그러면 객체(Object)란 무엇일까요? 먼저 객체를 본격적으로 설명하기 전에 클래스(Class)에 대해 설명하고자 합니다. 먼저, JAVA나 SPRING을 공부할 때 많이 참고하는 사이트인 <a href="https://www.baeldung.com/java-classes-objects">Baeldung</a>의 설명을 인용해서 설명하도록 하겠습니다. 본문에는 아래와 같이 클래스에 대해 설명하고 있습니다.</p>
<pre><code>In OOP, classes are blueprints or templates for objects. 
We use them to describe types of entities.

Simply put, a class represent a definition or a type of object. 
In Java, classes can contain fields, constructors, and methods.
</code></pre><p><em><strong>객체에 대한 템플릿</strong>_이니, _<strong>객체의 정의 또는 타입을 표현</strong></em> 등등 이래도 이해하기가 힘드실 것이라고 생각합니다. 저 또한 이 클래스라는 개념을 이해하는데 상당한 시간이 걸렸던 것 같습니다. 하지만 학부 JAVA 수업에서 교수님이 클래스란 _<strong>&quot;사용자가 정의한 타입&quot;</strong>_이라는 설명을 듣고 정말 명쾌하게 이해가 된 경험이 있습니다. </p>
<p>맞습니다. C++이나 JAVA는 꽤나 타입에 엄격한 언어입니다. 이유를 생각하자면 그 당시 80, 90년대 하드웨어 용량과 성능이 지금보다 상당히 제약되어 있었기에 이러한 타입마다 바이트 수를 달리해 성능을 최대한 끌어올리는 것이 그 당시 최선이었다는게 저의 합리적인 추측이라고 생각합니다. 아무튼 JAVA는 정수, 실수, 문자열 등의 다양한 타입이 존재합니다. 그래서 _<strong>객체의 속성(state = 필드(field))과 행동(behavior = 메서드(method))</strong>_을 포함하는 클래스는 타입으로 표현할 수 있습니다. 예시는 다음과 같습니다. </p>
<pre><code class="language-java">public class Cat {
    // 필드 선언
    String name;
    int age;

    // 매개변수 name과 age를 가지는 생성자 선언 
    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }

       // 메서드 선언 
    public void walk() {
        System.out.println(&quot;사뿐사뿐&quot;);
    }
}</code></pre>
<p>이렇게 선언한 Cat 클래스를 main문에서 new 명령어를 이용해 Cat 타입의 객체를 생성할 수 있습니다. </p>
<pre><code class="language-java">public Class Main {
    public static void main(String[] args) {
        // Cat 타입의 객체 생성
        Cat cat1 = new Cat(&quot;깜이&quot;, 4);
        Cat cat2 = new Cat(&quot;냥이&quot;, 5);

        // 객체의 메서드 호출
        cat1.walk();
        cat2.walk();
    }
}
</code></pre>
<p>앞서 설명한 부분을 이어 객체(Object)란 클래스, 즉 <strong>내가 정의한 타입으로 만들어낸 실체</strong>라고 볼 수 있습니다. 위 코드에서 보이듯이 Cat 클래스를 선언함으로써 Cat 타입의 객체인 cat1, cat2를 생성한 것을 확인할 수 있습니다. 학부 수업 때 교수님이 객체를 설명하시기로는 _<strong>&quot;클래스를 가지고 실제로 메모리에서 만들어진 것&quot;</strong>_이라고 하셨는데 해당 설명이 더 잘 와닿는 것 같습니다. 실제로 <a href="https://www.baeldung.com/java-classes-objects">Baeldung</a>에서도 객체를 다음과 같이 설명하고 있습니다.</p>
<pre><code>While classes are translated during compile time, 
objects are created from classes at runtime.

Objects of a class are called instances, 
and we create and initialize them with constructors:</code></pre><p>여기서 객체랑 인스턴스를 헷갈릴 수 있는데 사실상 동의어라고 생각하시면 됩니다. </p>
<p>네, 이렇게 JAVA가 가진 객체지향 프로그래밍의 특징을 간단하게 살펴보았습니다. C++을 주로 코딩 테스트 문제 풀 때 사용했기에 객체지향적인 느낌을 많이 못 느꼈지만 JAVA로 백엔드 개발을 하면서 클래스와 객체에 대해 더욱 자세히 이해할 수 있던 것 같습니다. 인터페이스와 다형성에 대한 글을 이 포스트에 한꺼번에 작성할려고 했는데 <del>분량조절 실패</del>로 다음 포스트에 올리도록 하겠습니다. 그러면 긴 글 읽어주셔서 감사합니다 :) </p>
]]></description>
        </item>
    </channel>
</rss>