<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>RAD.log</title>
        <link>https://velog.io/</link>
        <description>이것저것하고 싶은 개발자</description>
        <lastBuildDate>Mon, 03 Feb 2025 14:28:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>RAD.log</title>
            <url>https://velog.velcdn.com/images/peten_1105/profile/dd3c1ff0-8bdc-4200-ad3f-e3478b68d126/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. RAD.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/peten_1105" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[스파르타 스터디] 암호화폐 분석 완강 후기]]></title>
            <link>https://velog.io/@peten_1105/%EC%8A%A4%ED%8C%8C%EB%A5%B4%ED%83%80-%EC%8A%A4%ED%84%B0%EB%94%94-%EC%95%94%ED%98%B8%ED%99%94%ED%8F%90-%EB%B6%84%EC%84%9D-%EC%99%84%EA%B0%95-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@peten_1105/%EC%8A%A4%ED%8C%8C%EB%A5%B4%ED%83%80-%EC%8A%A4%ED%84%B0%EB%94%94-%EC%95%94%ED%98%B8%ED%99%94%ED%8F%90-%EB%B6%84%EC%84%9D-%EC%99%84%EA%B0%95-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Mon, 03 Feb 2025 14:28:24 GMT</pubDate>
            <description><![CDATA[<h1 id="수강한-이유">수강한 이유</h1>
<p>암호화폐관련해서 인공지능 봇을 만들려고 하던 와중에 Instagram에서 광고가 계속 떠서 한번 해볼까? 하고 수강하게 되었습니다. 커리큘럼이 좋아서 제가 몰랐던 부분을 알 수 있어서 도움이 됐습니다.</p>
<h1 id="수강-후기">수강 후기</h1>
<p>리얼 수강 후기.</p>
<p>아래가 사진이 커리큘럼 내용인데 파이썬 기초부터 Upbit API를 사용해서 데이터를 가져오는 법, 그래프 그리는 법, 머신러닝 방법 등을 강의에 포함 되어있다. </p>
<p><img src="https://velog.velcdn.com/images/peten_1105/post/34e621d6-29ff-4f02-bb1f-a7d73773b45b/image.png" alt="">
<img src="https://velog.velcdn.com/images/peten_1105/post/8bd3b291-bcf3-4b26-9db2-a220aec725cc/image.png" alt="">
<img src="https://velog.velcdn.com/images/peten_1105/post/c8ebacfe-99af-4d69-b323-3507ba203b58/image.png" alt="">
<img src="https://velog.velcdn.com/images/peten_1105/post/142cbc14-88f2-4bb6-b9bd-b9d84bfe896e/image.png" alt="">
<img src="https://velog.velcdn.com/images/peten_1105/post/3717f9ee-d308-4d2a-8da2-f0ec0b4f6814/image.png" alt=""></p>
<p>솔직히 코딩을 전혀 접하지 않았다면, 조금은 어려울 수 있을거 같다. 특히나 마지막 5주차의 머신러닝과 딥러닝 강의에서는 더더욱 그럴거 같은데 잘 따라오면 python으로 암호화폐 자동거래 봇은 만들 수 있지 않을까? 생각한다. 이 강의에서 안다룬 내용은 python 프로그램을 daemon으로 띄우는 방법이라던가, 혹은 Window 환경에서 GUI로 만들어서 실행하기 간편하게 만드는 부분, upbit API를 사용해서 실제 거래를 하는 부분 등은 따로 공부하면 얼마든지 하기 쉽기 때문에,, 그 부분은 놓쳐도 될 거 같다. </p>
<p>나 같은 경우에는 Linux 서버에서 python 소스 코드를 crontab으로 돌려서 하루 단위로 데이터를 수집하고, 해당 데이터들을 수집하여 머신러닝을 통해서 예측하고, 그 예측한 결과로 매수/매도를 하는 방식으로 개발하고, 백테스팅을 하고 있는 중인데, 역시 잘 되지않는거 같다. ㅎㅎ...</p>
<p>앞으로 좀 더 시행착오를 겪으면 제대로된 자동 거래봇이 되지 않을까 생각하며.. </p>
<p>결론 : 강의는 너무 좋았음, 하지만 실제 거래 봇을 만들기 위해선 조금의 공부가 더 필요함.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JSP] 쿠키]]></title>
            <link>https://velog.io/@peten_1105/JSP-%EC%BF%A0%ED%82%A4</link>
            <guid>https://velog.io/@peten_1105/JSP-%EC%BF%A0%ED%82%A4</guid>
            <pubDate>Tue, 07 May 2024 18:57:41 GMT</pubDate>
            <description><![CDATA[<h3 id="1-쿠키cookie">1. 쿠키(cookie)</h3>
<p>-&gt; 웹 브라우저가 보관하는 데이터
웹 브라우저는 웹 서버에 요청을 보낼 때 쿠키를 함께 전송하며, 웹 서버는 웹 브라우저가 전송한 쿠키를 사용해서 필요한 데이터를 읽을 수 있다. 쿠키는 웹 서버와 웹 브라우저 양쪽에서 생성할 수 있는데, JSP에서 생성하는 쿠키는 웹 서버에서 생성하는 쿠키이다. 쿠키의 동작 방식은 아래와 같다.</p>
<h4 id="1-쿠키-생성">(1) 쿠키 생성</h4>
<ul>
<li>JSP 프로그래밍에서 쿠키는 웹 서버측에서 생성한다. 생성한 쿠키를 응답 데이터의 헤더에 저장해서 웹 브라우저로 전송한다.<h4 id="2-쿠키-저장">(2) 쿠키 저장</h4>
</li>
<li>웹 브라우저는 웹 서버에서 보내온 쿠키를 쿠키 보관서에 저장한다. 쿠키는 종류에 따라서 메모리나 파일에 저장하게 된다.<h4 id="3-쿠키-전송">(3) 쿠키 전송</h4>
</li>
<li>웹 브라우저는 저장한 쿠키를 요청이 있을 때마다 웹 서버에 전송한다. 웹 서버는 웹 브라우저가 전송한 쿠키를 사용해서 필요한 작업을 수행한다.</li>
</ul>
<h3 id="2-쿠키의-구성">2. 쿠키의 구성</h3>
<ul>
<li>쿠키를 구성하는 요소는 이름, 값, 유효시간, 도메인, 경로 등이 있다.</li>
<li><blockquote>
<p>여기서 주요 핵심 요소는 이름과 값이다. 하나의 웹 브라우저는 여러 개의 쿠키를 가질 수 있는데, 이 때 각 쿠키를 구분하기 위해서 사용되는 것이 이름이다. </p>
</blockquote>
</li>
<li>쿠키 이름은 콤마, 세미콜론, 공백, 등호기호(=)를 제외한 출력 가능한 아스키 문자로 구성된다.</li>
</ul>
<h3 id="3-쿠키-생성하기">3. 쿠키 생성하기</h3>
<pre><code>&lt;%
// 쿠키 생성
Cookie userCookie = new Cookie(&quot;user_id&quot;, &quot;12345&quot;);
// 쿠키 속성 설정
userCookie.setMaxAge(86400); // 24시간 동안 유효
userCookie.setSecure(true);
userCookie.setHttpOnly(true);
userCookie.setPath(&quot;/&quot;);
// 쿠키를 HTTP 응답에 추가
response.addCookie(userCookie);
%&gt;</code></pre><ul>
<li>위 소스 코드는 사용자 ID를 저당하는 쿠키를 생성하고, 이를 보안 쿠키로 설정한 후, 응답에 추가하는 과정을 보여준다. 이 쿠키는 24시간 동안 유효하며, HTTPS를 통해서만 전송되고, JavaScript를 통한 접근이 차단된다.</li>
</ul>
<h3 id="4-쿠키-값-읽어오기">4. 쿠키 값 읽어오기</h3>
<ul>
<li>웹 브라우저는 요청 헤더에 쿠키를 저장해서 보내며, JSP는 아래와 같은 소스 코드를 사용해서 쿠키 값을 읽어올 수 있다.</li>
</ul>
<pre><code>Cookie[] cookies = request.getCookies();</code></pre><p>request.getCookies() 메서드는 Cookie 배열을 리턴한다. 이 메서드는 읽어올 쿠키가 존재하지 않으면 null을 리턴한다. null 여부를 확인하지 않고 쿠키를 사용하면 NullPointerException이 발생하므로, 항상 null 여부를 확인하자.</p>
<h3 id="5-쿠키-값-변경-및-쿠키-삭제하기">5. 쿠키 값 변경 및 쿠키 삭제하기</h3>
<ul>
<li>쿠키 값 변경은 같은 이름의 쿠키를 새로 생성해서 응답 데이터로 보내면 된다.</li>
<li>쿠키를 삭제하려면 setMaxAge() 메서드를 호출할 때 매개변수를 0으로 지정하면 된다.</li>
</ul>
<h3 id="6-쿠키의-도메인">6. 쿠키의 도메인</h3>
<ul>
<li>기본적으로 쿠키는 그 쿠키를 생성한 서버에만 전송된다.</li>
<li>예를 들어 <a href="https://mail.naver.com">https://mail.naver.com</a>  에 연결해서 생성된 쿠키는 다른 사이트(<a href="https://map.naver.com)%EB%A1%9C">https://map.naver.com)로</a> 연결할 때에는 전송되지 않으며 <a href="https://mail.naver.com%EC%97%90">https://mail.naver.com에</a> 연결할 때에만 전송되게 된다.</li>
<li>하지만 같은 도메인을 사용하는 모든 서버에 쿠키를 보내야할 때가 있을 수 있는데, 이때는 setDomain() 메소드를 사용하여 전송한다. 이 때 주의할 점은 현재 도메인 및 상위 도메인에만 전달할 수 있는 것이다.</li>
</ul>
<pre><code>&lt;%@ page contentType=&quot;text/html; charset=utf-8&quot; %&gt;
&lt;%@ page import = &quot;java.net/URLEncoder&quot; %&gt;
&lt;%
    Cookie cookie1 = new Cookie(&quot;id&quot;,&quot;modvirus&quot;);
    cookie1.setDomain(&quot;.somehost.com&quot;);
    response.addCookie(cookie1);

    Cookie cookie2 = new Cookie(&quot;only&quot;,&quot;onlycookie&quot;);
    response.addCookie(cookie2);

    Cookie cookie3 = new Cookie(&quot;invalid&quot;,&quot;invalidcookie&quot;);
    cookie3.setDomain(&quot;javacan.tistory.com&quot;);
    response.addCookie(cookie3);
%&gt;
&lt;html&gt;
&lt;head&gt;&lt;title&gt; 쿠키 생성 &lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
다음과 같이 쿠키를 생성했습니다.〈br〉
&lt;%= cookiel.getName() %&gt;=&lt;%= cookiel.getValue() %&gt;
[&lt;%= cookie1.getDomain() %&gt;]
&lt;br&gt;
&lt;%= cookie2.getName() %&gt;=&lt;%= cookie2.getValue() %&gt;
[&lt;%= cookie2.getDomain() %&gt;]
&lt;br&gt;
&lt;%= cookie3.getName() %&gt;=&lt;%= cookie3.getValue() %&gt;
[&lt;%= cookie3.getDomain() %&gt;]
&lt;/body&gt;
&lt;/html&gt;</code></pre><h3 id="7-쿠키의-경로">7. 쿠키의 경로</h3>
<ul>
<li>도메인이 쿠키를 공유할 도메인 범위를 지정한다면, 경로는 쿠키를 공유할 기준 경로를 지정한다.</li>
<li>쿠키의 경로를 지정할 때에는 Cookie 클래스의 setPath() 메서드를 사용한
다.<pre><code>Cookie cookie = new Cookie(&quot;name&quot;,&quot;value&quot;);
cookie.setPath(&quot;/chap09&quot;);</code></pre></li>
<li>위 소스 코드는 쿠키 경로를 &quot;/chap09&quot;로 지정한다. 이 경우 웹브라우저는 name 쿠키를 /chap09 또는 그 하위 경로에만 전송한다.</li>
</ul>
<h3 id="8-쿠키의-유효시간">8. 쿠키의 유효시간</h3>
<ul>
<li>쿠키는 유효시간이 있는데, 따로 지정해주지 않으면 웹 브라우저 종료시에 삭제된다.</li>
<li>쿠키의 유효시간을 설정해 놓으면 웹 브라우저를 종료했어도 쿠키가 삭제되지 않는다.</li>
<li>유효시간은 setMaxAge() 메소드를 통해서 설정한다.</li>
</ul>
<h3 id="9-쿠키와-헤더">9. 쿠키와 헤더</h3>
<ul>
<li>response.addCookie()로 쿠키를 추가하면 실제로 Set-Cookie 헤더를 통해서 전달된다. 한 개의 Set-Cookie 헤더는 한 개의 쿠키 값을 전달한다.</li>
<li>한 개의 Set-Cookie 헤더 구성은 다음과 같다.<blockquote>
<p>쿠키이름=쿠키값; Domain=도메인값; Path=경로값; Expires=GMT형식의 만료일시</p>
</blockquote>
</li>
</ul>
<h3 id="10-쿠키를-사용한-로그인-상태-유지">10. 쿠키를 사용한 로그인 상태 유지</h3>
<ul>
<li>쿠키를 사용하면 다음과 같은 방법으로 로그인 상태를 유지할 수 있다.
(1) 로그인에 성공하면 특정 이름을 갖는 쿠키를 생성한다.
(2) 해당 쿠키가 존재하면 로그인한 상태라고 판단한다.
(3) 로그아웃 하면 해당 쿠키를 삭제한다.<blockquote>
<p>예를 들어, 로그인에 성공하면 &quot;AUTH&quot;라는 쿠키를 생성하고, &quot;AUTH&quot; 쿠키가 존재하면 로그인한 상태라고 인식하는 것이다.</p>
</blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JSP] 필수 이해 요소]]></title>
            <link>https://velog.io/@peten_1105/JSP-%ED%95%84%EC%88%98-%EC%9D%B4%ED%95%B4-%EC%9A%94%EC%86%8C</link>
            <guid>https://velog.io/@peten_1105/JSP-%ED%95%84%EC%88%98-%EC%9D%B4%ED%95%B4-%EC%9A%94%EC%86%8C</guid>
            <pubDate>Tue, 07 May 2024 17:50:48 GMT</pubDate>
            <description><![CDATA[<h3 id="1-jsp-처리-과정">1. JSP 처리 과정</h3>
<p>웹브라우저에 주소를 입력하면 JSP가 실행되는 것 처럼 보이지만, 실제로 JSP를 실행하는 과정은 꽤 복잡하다. </p>
<p><img src="https://velog.velcdn.com/images/peten_1105/post/b15e90b7-232c-43ce-bdaa-14657a5352d8/image.png" alt="">
(그림 출처 : <a href="https://medium.com/@js230023/jsp-%EC%B2%98%EB%A6%AC-%EA%B3%BC%EC%A0%95-105ad49c5810">blog</a> )</p>
<h4 id="1-클라이언트-요청-수신">(1) 클라이언트 요청 수신</h4>
<ul>
<li>웹 브라우저(클라이언트)에서 사용자가 URL을 통해 JSP 페이지에 접근한다. 예를 들어, 사용자가 &#39;<a href="https://example.com/app/page.jsp&#39;">https://example.com/app/page.jsp&#39;</a> 주소를 입력한다.</li>
<li>클라이언트는 HTTP 프로토콜을 사용하여 웹 서버에 요청을 보낸다. 이 요청은 HTTP 메서드(GET, POST등), Header(컨텐츠 타입, 쿠키 정보, 사용자 에이전트 등), URL 및 필요한 경우 Body(POST 데이터)를 포함한다.</li>
</ul>
<h4 id="2-웹-서버에서-서블릿-컨테이너로-요청-전달">(2) 웹 서버에서 서블릿 컨테이너로 요청 전달</h4>
<ul>
<li>웹 서버(Apache, Nginx 등)는 요청을 받고, 이를 처리하기 위해 서블릿 컨테이너(Tomcat, Jetty 등)로 전달한다.</li>
<li>데이터 전달 : 웹 서버는 HTTP 요청을 파싱하여 서블릿 컨테이너에 전달한다. 이 때, 요청 정보는 서블릿 API를 통해 &#39;HttpServletRequest&#39; 객체로 변환된다.</li>
</ul>
<h4 id="3-서블릿-컨테이너-내-jsp-처리">(3) 서블릿 컨테이너 내 JSP 처리</h4>
<ul>
<li>서블릿 컨테이너는 요청된 URL과 매핑된 JSP 파일을 확인한다. JSP 파일이 이미 서블릿으로 컴파일된 경우, 해당 서블릿을 실행한다. 처음 요청된 JSP의 경우, 서블릿으로 변환 및 컴파일 과정이 이루어진다.</li>
<li>JSP 파일은 Java 코드로 변환되고, 이 코드는 서블릿으로 컴파일된다. 컴파일된 서블릿은 요청 데이터를 처리하여 동적으로 HTML을 생성한다.</li>
</ul>
<h4 id="4-서블릿-실행-및-응답-생성">(4) 서블릿 실행 및 응답 생성</h4>
<ul>
<li>변환된 서블릿이 실행되며, 이 과정에서 서블릿은 &#39;service()&#39;메소드를 호출하여 요청을 처리한다. 서블릿은 요청 정보를 분석하고, 필요한 비즈니스 로직을 수행한 후 응답 데이터를 생성한다.</li>
<li>서블릿 HTML, CSS, JavaScript 등을 포함한 응답 데이터를 생선한다. 이 데이터는 &#39;HttpServletResponse&#39;객체에 저장되며, HTTP 응답 형태로 클라이언트에 전송된다.</li>
</ul>
<h4 id="5-응답-전송">(5) 응답 전송</h4>
<ul>
<li>서블릿 컨테이너는 생성된 응답 데이터를 웹 서버로 전송하고, 웹 서버는 이를 클라이언트에게 전달한다. </li>
<li>생성된 HTML 응답은 HTTP 응답 포맷(상태 코드, 헤더, 바디)으로 클라이언트에게 전송된다. 이 응답은 최종적으로 클라이언트의 웹 브라우저에서 렌더링되어 사용자에게 표시된다.</li>
</ul>
<h4 id="6-세션-및-쿠키-관리">(6) 세션 및 쿠키 관리</h4>
<ul>
<li>서블릿 실행 중 세션 및 쿠키를 관리하여 사용자의 상태를 유지한다. 쿠키는 클라이언트와 서버 간에 상태 정보를 저장하는 데 사용된다.</li>
<li>필요한 경우, 서블릿은 쿠키 정보를 생성하거나 수정하고, 이 정보를 HTTP 응답의 헤더에 포함시켜 클라이언트에게 전송한다.</li>
</ul>
<p>이 과정을 통해 JSP 페이지는 동적 웹 컨텐츠를 생성하고, 이를 클라이언트에게 효과적으로 제공한다. 각 단계는 웹 어플리케이션의 성능, 확장성 및 사용자 경험을 최적화하는 데 중요한 역할을 한다.</p>
<h3 id="2-출력-버퍼와-응답">2. 출력 버퍼와 응답</h3>
<p><img src="https://velog.velcdn.com/images/peten_1105/post/9607937a-cae0-4c61-95da-58cc2a5a26ea/image.png" alt=""></p>
<ul>
<li><p>JSP 페이지는 응답 결과를 곧바로 웹 브라우저에 전송하지 않는다. 대신 출력 버퍼에 임시로 응답 결과를 저장했다가 한 번에 웹 브라저에 전송한다.</p>
</li>
<li><p>출력버퍼(Output Buffer) : JSP 페이지의 응답 내용을 임시로 저장하는 메모리 영역, 웹 서버가 최종 응답을 클라이언트에게 전송하기 전에 데이터를 버퍼링한다.</p>
</li>
<li><p>이러한 버퍼링 과정의 장점은 다음과 같다.</p>
</li>
<li><p>-&gt; 데이터 전송 성능 향상</p>
</li>
<li><p>-&gt; JSP 실행 도중에 버퍼를 비우고 새로운 내용 전송 가능</p>
</li>
<li><p>-&gt; 버퍼가 다 차기 전까지 헤더 변경 가능</p>
</li>
<li><p>buffer 속성 : JSP 페이지의 출력 버퍼 크기를 설정한다. 기본 값은 보통 8KB이지만, 페이지 디렉티브를 사용하여 이 크기를 조정할 수 있다.</p>
</li>
<li><p>autoFlush 속성 : 버퍼가 가득 차면 자동으로 플러시(비우고, 데이터를 전송)할지 여부를 결정한다. &#39;true&#39;로 설정하면 버퍼가 자동으로 flush되고, &#39;false&#39;로 설정하면 버퍼 오버플로우시 예외가 발생한다.</p>
</li>
</ul>
<pre><code>&lt;%@ page contentType=&quot;text/html; charset=UTF-8&quot; %&gt;
&lt;%@ page buffer=&quot;1kb&quot; autoFlush=&quot;true&quot; %&gt;
&lt;html&gt;
&lt;head&gt;&lt;title&gt;autoFlush 속성값 true 예제&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
&lt;% for (int i = 0; i &lt; 1000; i++) { %&gt;
1234
&lt;% } %&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><ul>
<li>Line2 : buffer 속성을 &#39;1KB&#39;로 설정하여 출력 버퍼의 크기를 1KB로 지정하고, autoFlush 속성을 true로 설정하여 버퍼가 가득 차면 자동으로 플러시하도록 설정된다. 버퍼를 사용하고 싶지 않다면 buffer 속성의 값은 &quot;none&quot;으로 지정하면 된다.</li>
<li>Line3-12 : HTML 문서의 기본 구조를 정의하고, 간단한 반복문을 사용하여 1000번 &#39;1234&#39; 문자열을 출력한다. 이 코드는 버퍼 크기를 초과하는 응답 데이터를 생성하므로, &#39;autoFlush&#39;가 &#39;true&#39;이기 때문에 버퍼가 자동으로 비워지고 클라이언트로 데이터가 전송된다.
( 일반적으로 JSP 페이지를 작성할 때에는 buffer 속성을 지정하지 않는다. JSP 규약은 butter 속성을 지정하지 않으면 최소한 8KB 이상의 크기를 갖는 버퍼를 사용하도록 규정하고 있다. )</li>
</ul>
<h3 id="3-웹-어플리케이션-폴더-구성과-url-매핑">3. 웹 어플리케이션 폴더 구성과 URL 매핑</h3>
<ul>
<li>웹 어플리케이션 폴더 구성 : 웹 어플리케이션의 구조화된 폴더 시스템으로, 소스 파일, 클래스, 라이브러리, 정적 자원 등이 포함된다.</li>
<li>URL 매핑 : 웹 어플리케이션에서 특정 요청 URL이 실제 서버의 어떤 리소스나 서블릿과 연결되는 방식을 정의하는 설정.</li>
<li>웹 어플리케이션 폴더 구성은 URL 매핑과 직접 연결된다. 예를 들어 &#39;WEB-INF&#39; 내부의 리소스는 외부에서 직접 접근할 수 없으며, 서블릿이나 JSP를 통해 간접적으로 접근된다.</li>
</ul>
<h3 id="4-웹-어플리케이션-배포">4. 웹 어플리케이션 배포</h3>
<ul>
<li>웹 어플리케이션 배포는 웹 서버에 애플리케이션을 설치하여 외부에서 접근 가능하게 만드는 과정이다. 이 과정에는 애플리케이션의 구성 파일, 서블릿, 클래스, 라이브러리 및 자원을 포함하는 WAR 파일 생성이 포함된다.</li>
<li>WAR 파일(Web Application Archive) : 웹 어플리케이션의 모든 컴포넌트를 포함하는 압축 파일 형식, JSP, 서블릿, 자바 클래스, XML 등이 포함될 수 있다.</li>
<li>WAR 파일은 WEB-INF 폴더 내에 배포 디스크립터와 라이브러리를 포함하며, 이 폴더는 외부에서 직접적인 접근이 제한된다. 배포 후, 웹 서버는 WAR 파일을 압축 해제하고, 애플리케이션을 호스트하여 요청에 응답할 수 있도록 준비한다.</li>
</ul>
<p>톰캣에서 WAR 파일 배포는 간단한데, WAR 파일을 톰캣의 &#39;webapps&#39; 디렉토리에 복사하기만 하면, 톰캣이 서버를 다시 시작할 때 자동으로 WAR 파일을 인식하고 애플리케이션을 배포한다.</p>
<p>자세하게 적어보면 다음과 같은 과정으로 진행된다.</p>
<h4 id="1-웹-어플리케이션의-패키징">(1) 웹 어플리케이션의 패키징</h4>
<ul>
<li>WAR 파일 :  웹 어플리케이션의 모든 구성요소는 WAR 파일안에 패키징된다. 이 파일은 Java 클래스, JSP, HTML, CSS, JavaScript 파일,  메타데이터(XML 설정 파일), 그리고 의존성 라이브러리(JAR파일들)을 포함한다.</li>
<li>패키징 도구 : 이 패키징 과정은 Maven이나 Gradle 같은 빌드 도구를 사용하여 자동화할 수 있다. 이 도구들은 의존성 관리를 자동화하고, 빌드 및 패키징 과정을 표준화한다.</li>
</ul>
<h4 id="2-배포-및-초기화">(2) 배포 및 초기화</h4>
<ul>
<li>배포 : 생성된 WAR 파일은 웹 서버의 &#39;webapps&#39; 디렉토리에 복사되어 배포된다. Apache Tomcat 같은 서버는 이 디렉토리를 주기적으로 확인하고 새로운 WAR 파일을 자동으로 감지한다.</li>
<li>압축 해제 및 로드 : 서버는 WAR파일을 압축 해제하고, 파일 내의 애플리케이션 구성을 읽기 시작한다. &#39;WEB-INF&#39;폴더에 위치한 &#39;web.xml&#39;파일은 애플리케이션의 배포 디스크립터로서, 서블릿 매핑, 세션 구성, 보안 설정 등을 정의한다.</li>
</ul>
<h4 id="3-클래스-로딩">(3) 클래스 로딩</h4>
<ul>
<li>클래스 로더 계층 : JAVA의 클래스 로딩은 계층적으로 이루어지는데, Tomcat의 경우에는 각 웹 어플리케이션 마다 별도의 클래스 로더를 생성하여 어플리케이션 간의 클래스 충돌을 방지하게 한다.</li>
<li>로드 과정 : 클래스 로더는 &#39;WEB-INF/classes&#39;와 같이 &#39;WEB-INF/lib&#39;디렉토리에 있는 클래스와 JAR파일들을 JVM에 로드한다. 이 과정에서 보안 매니저가 활성화 되어있으면, 각 클래스의 로딩은 보안 정책에 따라 검사된다.</li>
</ul>
<h4 id="4-서블릿-및-jsp-컴파일">(4) 서블릿 및 JSP 컴파일</h4>
<ul>
<li>서블릿 초기화 : 최초 요청이 서블릿에 도달하면, 서블릿의 &#39;init()&#39; 메소드가 호출되어 필요한 리소스를 초기화한다.</li>
<li>JSP 처리 : JSP파일은 서블릿으로 변환되고, 이 변환된 서블릿은 컴파일되어 JVM에서 실행 가능한 바이트 코드로 변환된다. JSP 페이지에 대한 첫 요청이 처리되는 동안, 이 컴파일 과정이 일어난다.</li>
</ul>
<h4 id="5-요청-처리-및-응답-생성">(5) 요청 처리 및 응답 생성</h4>
<ul>
<li>요청 처리 : 서블릿은 &#39;service()&#39;메소드를 통해 들어오는 요청을 처리한다. 이 메소드는 요청 유형(GET, POST)에 따라 적절한 메소드(doGet, doPost)를 호출한다.</li>
<li>응답 생성 : 처리 결과는 응답 스트림을 통해 클라이언트로 전송된다. HTTP 응답 헤더가 설정되며, 컨텐츠 타입, 캐싱 정책, 쿠키 등이 포함될 수 있다.</li>
</ul>
<h4 id="6-세션-및-리소스-관리">(6) 세션 및 리소스 관리</h4>
<ul>
<li>세션 관리 : 웹 서버는 사용자의 세션과 쿠키들을 관리하고, 세션 타임아웃, 세션 데이터 저장등을 처리한다.</li>
<li>리소스 정리 : 애플리케이션 종료시, &#39;destory()&#39;메소드가 호출되어 개방된 리소스를 해제하고, 가비지 컬렉션을 통해 불필요한 메모리를 정리한다.</li>
</ul>
<p>이러한 과정을 통해 JAVA 웹 어플리케이션은 효율적으로 배포되고, 유지보수가 이루어지며, 클라이언트에 안정적으로 서비스를 제공한다. 이 모든 과정은 웹 어플리케이션의 성능, 안정성, 보안을 보장하는 데 중요한 역할을 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JSP] 기본 코드 구조]]></title>
            <link>https://velog.io/@peten_1105/JSP-%EA%B8%B0%EB%B3%B8-%EC%BD%94%EB%93%9C-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@peten_1105/JSP-%EA%B8%B0%EB%B3%B8-%EC%BD%94%EB%93%9C-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Tue, 07 May 2024 15:21:39 GMT</pubDate>
            <description><![CDATA[<h3 id="1-디렉티브directives">1. 디렉티브(Directives)</h3>
<ul>
<li>디렉티브는 JSP 페이지에 대한 설정 정보를 제공한다. 주로 페이지의 문서 타입, 인코딩 방식, 사용할 자바 패키지 등을 지정한다.</li>
<li>예를 들어, 페이지의 콘텐츠 타입을 HTML로 지정하고 UTF-8 인코딩을 사용하는 경우 아래와 같이 작성할 수 있다.<pre><code>&lt;%@ page contentType=&quot;text/html;charset=UTF-8&quot; %&gt;</code></pre></li>
</ul>
<h3 id="2-스크립트-요소script-elements">2. 스크립트 요소(Script Elements)</h3>
<ul>
<li><p>스크립트 요소는 실제 자바 코드를 포함하여 서버에서 데이터를 처리하고 동적 컨텐츠를 생성한다. </p>
</li>
<li><p>스크립트릿 (Scriptlets)
--&gt; 자바 코드를 사용하여 로직을 처리하고 데이터를 조작한다. 예를 들어, 현재 날짜를 표시하는 스크립트릿은 다음과 같다.</p>
<pre><code>&lt;%
java.util.Date date = new java.util.Date();
out.println(&quot;&lt;h2&gt;Today&#39;s date: &quot; + date + &quot;&lt;/h2&gt;&quot;);
%&gt;</code></pre></li>
<li><p>표현식(Expressions)</p>
</li>
<li><p>-&gt; 화면에 값을 출력하기 위해 사용되며, 주로 변수의 값을 직접 출력할 때 사용한다. 예를 들어, 사용자의 이름을 출력하고자 할 때 다음과 같이 사용할 수 있다.</p>
<pre><code>&lt;p&gt;Hello, &lt;%= userName %&gt;&lt;/p&gt;</code></pre></li>
<li><p>선언부(Declarations)</p>
</li>
<li><p>-&gt; JSP 페이지 내에서 메소드나 변수를 선언하는 데 사용된다. 예를 들어, 정수의 제곱을 계산하는 메소드를 선언하고 사용할 수 있다.</p>
<pre><code>&lt;%! 
int square(int x) {
  return x * x;
}
%&gt;
&lt;p&gt;Square of 5 is &lt;%= square(5) %&gt;&lt;/p&gt;</code></pre></li>
</ul>
<h3 id="3-기본-객체">3. 기본 객체</h3>
<ul>
<li>JSP에서 제공하는 기본 객체를 사용하여 요청, 응답 등을 처리할 수 있다. 예를 들어, 클라이언트로부터 받은 파라미터를 출력하는 코드는 다음과 같다.<pre><code>&lt;%
  String username = request.getParameter(&quot;username&quot;);
  out.println(&quot;Hello, &quot; + username);
%&gt;</code></pre></li>
</ul>
<h3 id="4-표현-언어expression-language">4. 표현 언어(Expression Language)</h3>
<ul>
<li>JSP 2.0 이상에서 사용되며, 간단하게 객체의 속성이나 컬렉션에 접근할 수 있다. 예를 들어, &#39;user&#39;객체의 &#39;name&#39;속성을 표시하고자 할 때 다음과 같이 작성할 수 있다.<pre><code>&lt;p&gt;User Name: ${user.name}&lt;/p&gt;</code></pre></li>
</ul>
<h3 id="5-표준-액션-태그와-태그-라이브러리">5. 표준 액션 태그와 태그 라이브러리</h3>
<ul>
<li>JSP에서 제공하는 표준 액션을 사용하여 다른 리소스를 포함하거나 조건에 따라 다른 작업을 수행할 수 있다. 예를 들어, 다른 페이지를 포함하는 코드는 다음과 같다.</li>
</ul>
<pre><code>&lt;jsp:include page=&quot;header.jsp&quot; /&gt;</code></pre><h3 id="5-예제">5. 예제</h3>
<p>아래는 JSP 파일의 예제 소스코드이고, 주요 기본 구성 요소들을 모두 포함하고 있으며, 각 라인별로 설명을 추가하였다.</p>
<pre><code>&lt;%@ page contentType=&quot;text/html;charset=UTF-8&quot; language=&quot;java&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Sample JSP Page&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;%
    // 자바 코드를 사용한 스크립트릿 예제
    String userName = &quot;John Doe&quot;;
    java.util.Date date = new java.util.Date();
%&gt;
&lt;h1&gt;Welcome to Our Website&lt;/h1&gt;
&lt;p&gt;Hello, &lt;%= userName %&gt;!&lt;/p&gt; &lt;!-- 표현식을 사용하여 사용자 이름 출력 --&gt;
&lt;p&gt;Today&#39;s date: &lt;%= date %&gt; &lt;/p&gt; &lt;!-- 표현식을 사용하여 날짜 출력 --&gt;

&lt;%! 
    // 선언을 사용한 메소드 예제
    int square(int x) {
        return x * x;
    }
%&gt;
&lt;p&gt;Square of 4 is &lt;%= square(4) %&gt;&lt;/p&gt; &lt;!-- 선언한 메소드를 표현식을 통해 사용 --&gt;

&lt;p&gt;User Name from EL: ${userName}&lt;/p&gt; &lt;!-- 표현 언어를 사용하여 사용자 이름 출력 --&gt;

&lt;!-- 표준 액션을 사용한 다른 JSP 페이지 포함 --&gt;
&lt;jsp:include page=&quot;footer.jsp&quot;/&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>설명
Line 1:  페이지의 콘텐츠 타입과 문자 인코딩을 지정하고, 자바 프로그래밍 언어를 사용한다는 것을 선언한다.
Line 2<del>5: HTML 문서의 기본 구조를 정의한다.  head 태그 내에 문서의 제목을 설정한다.
Line 6</del>10: HTML body 섹션의 시작이다. 여기서 자바 코드를 스크립트릿을 사용하여 실행한다. 사용자 이름과 날짜를 변수로 선언하고 초기화한다.
Line 11: h1 태그를 사용하여 웹페이지의 제목을 출력한다.
Line 12-13: 표현식(&lt;%= %&gt;)을 사용하여 스크립트릿에서 선언한 변수들을 HTML 문서에 출력한다.
Line 15-19: JSP 내에서 자바 메소드를 선언한다. 이 메소드는 정수의 제곱을 계산하여 반환한다.
Line 20: 선언한 square 메소드를 호출하고 그 결과를 웹 페이지에 출력한다.
Line 22: 표현 언어를 사용하여 userName 변수의 값을 출력한다. 표현 언어는 객체의 속성에 간단하고 깔끔하게 접근할 수 있게 해준다.
Line 24: <a href="jsp:include">jsp:include</a> 표준 액션을 사용하여 다른 JSP 페이지 (footer.jsp)를 현재 페이지에 포함한다. 이를 통해 페이지의 모듈화를 달성할 수 있게 된다.
Line 25-27: HTML 문서의 닫는 태그이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JSP] JSP]]></title>
            <link>https://velog.io/@peten_1105/JSP-JSP</link>
            <guid>https://velog.io/@peten_1105/JSP-JSP</guid>
            <pubDate>Tue, 07 May 2024 14:55:52 GMT</pubDate>
            <description><![CDATA[<h3 id="웹-프로그래밍이란">웹 프로그래밍이란?</h3>
<ul>
<li>웹 프로그래밍은 웹 페이지와 웹 애플리케이션을 생성, 관리 및 유지보수하는 과정이다. 사용자가 웹 브라우저를 통해 접근할 수 있는 대화형 웹 사이트를 만드는 것이 주요 목적이다. 이를 위해 HTML, CSS, JavaScript와 같은 프론트엔드 언어와 PHP, Python, JAVA 등의 백엔드 언어가 사용된다.</li>
</ul>
<h3 id="웹-프로그래밍에서의-웹-서버란">웹 프로그래밍에서의 웹 서버란?</h3>
<ul>
<li>웹 서버는 웹 페이지, 사이트 또는 앱을 인터넷에 호스팅하고, 외부 요청에 대해 HTML 문서나 기타 리소스를 제공하는 소프트웨어 및 하드웨어의 조합이다. 사용자의 요청을 받아 처리한 후, 결과를 다시 사용자의 브라우저로 전송한다. Apache, Nginx와 같은 웹 서버 소프트웨어는 이러한 처리 과정을 관리하며, 정적 컨텐츠를 제공하는 역할을 한다.</li>
</ul>
<h3 id="jsp">JSP?</h3>
<ul>
<li>JAVA Server Pages(JSP)는 JAVA 기술을 사용하여 웹 페이지를 동적으로 생성하는 서버 사이드 프로그래밍 기술이다. JSP는 HTML 내에 JAVA 코드를 삽입할 수 있게 하여, 웹 페이지가 사용자의 요청에 따라 실시간으로 내용을 변경할 수 있다. 서버에서 실행되며, 결과는 HTML 형태로 클라이언트에 전송된다.</li>
</ul>
<h3 id="was">WAS?</h3>
<ul>
<li>WAS(Web Application Server)는 웹 기반 애플리케이션을 실행하기 위해 필요한 소프트웨어 환경이다. 웹 서버와의 차이점은, WAS가 동적인 콘텐츠를 생성하여 제공한다는 점이다. 일반적으로 데이터베이스 서버와의 상호 작용과 같은 복잡한 트랜잭션을 처리한다. 대표적인 예로는 Tomcat, WebLogic, JBoss 등이 있다.</li>
</ul>
<h3 id="jsp를-실행하기-위한-환경">JSP를 실행하기 위한 환경</h3>
<ul>
<li>JSP를 실행하기 위해선 JAVA를 지원하는 웹 서버와 서블릿 컨테이너가 필요하다. 가장 일반적으로 사용되는 서블릿 컨테이너는 Apache Tomcat이며, 이 외에도 Jetty, GlassFish 등이 사용될 수 있다. 이러한 환경은 JSP 파일을 서블릿으로 변환하고, 서블릿이 JAVA 코드를 실행하여 결과를 웹 페이지로 반환하게 한다.</li>
</ul>
<h3 id="소스-폴더-구조">소스 폴더 구조</h3>
<p>JSP 애플리케이션의 폴더 구조는 아래와 같다.
-WebContent : 클라이언트에게 제공될 웹 페이지와 JSP 파일.
-WEB-INF : 애플리케이션의 설정 파일과 보안이 중요한 리소스를 포함.
--classes : 컴파일된 JAVA 클래스 파일
--lib : 애플리케이션에서 사용되는 라이브러리(JAR 파일)
--web.xml : 서블릿 매핑과 기타 구성 정보를 담은 파일</p>
<h3 id="was-구성">WAS 구성</h3>
<p>웹 애플리케이션 서버 구성은 다음과 같다.</p>
<ul>
<li>웹 서버 : Apache, Nginx 등이 정적 파일을 처리하고, 필요에 따라 요청을  WAS로 전달한다.</li>
<li>서블릿 컨테이너 : Tomcat, Jetty 등이 JSP와 서블릿을 실행한다.</li>
<li>데이터베이스 서버 : MySQL, Oracle 등이 데이터 관리를 담당한다.</li>
</ul>
<p>이러한 구성을 통해 JSP 기반의 웹 애플리케이션은 효율적으로 동작하며, 사용자에게 동적이고 상호작용이 풍부한 웹 경험을 제공할 수 있다. JSP와 관련된 기술을 활용하면 복잡하고 다기능적인 웹 애플리케이션 개발이 가능해진다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] Diamond Type과 Non reifiable vararags 타입 ]]></title>
            <link>https://velog.io/@peten_1105/JAVA-Diamond-Type</link>
            <guid>https://velog.io/@peten_1105/JAVA-Diamond-Type</guid>
            <pubDate>Mon, 29 Apr 2024 15:57:30 GMT</pubDate>
            <description><![CDATA[<h3 id="diamond-type">Diamond Type</h3>
<p>JAVA7에서는 Generic을 사용할 때 아래 처럼 생성자에 해당 타입을 상세하게 명시하지 않아도 된다.</p>
<pre><code>HashMap&lt;String?Integer&gt; map=new HashMap&lt;String,Integer&gt;();
// 아래는 JAVA7에서 타입을 상세하게 적어주지 않아도 되는 예
HashMap&lt;String,Integer&gt; map = new HashMap&lt;&gt;();</code></pre><p>왜냐하면, 이미 변수를 선언할 때 필요한 타입들을 지정해 놓았기 때문이다. 그래서 &quot;&lt;&gt;&quot;로 표시하면 컴파일러가 알아서 해당 생성자 타입을 지정해버린다.
이처럼 편리한 다이아몬드는 편한 만큼 다음과 같은 제약이 있다.</p>
<ul>
<li>다이아몬드 미 지정시 컴파일 경고 발생</li>
<li>다이아몬드 생성시 유의 사항 1 - 메소드 내에서 객체 생성시</li>
<li>다이아몬드 생성시 유의 사항 2 - 제너릭하면서도 제너릭하지 않은 객체 생성시</li>
</ul>
<pre><code>package f.generic;
public class GenericClass &lt;X&gt; {
    private X x;
    private Object o;
    public &lt;T&gt; GenericClass (T t) {
        this.o=t;
        System.out.println(&quot;T type=&quot;+t.getClass().getName());
    }

    public void setValue(X x) {
        this.x=x;
        System.out.println(&quot;X type=&quot;+x.getClass().getName());
    }
}

package f.generic;
public class TypeInference {
    public static void main(String args[]) {
        TypeInference type = new TypeInference();
        type.makeObject1();
    }

    // 제네릭하면서도 제네릭하지 않은 객체 생성시
    public void makeObject1(){
        GenericClass&lt;Integer&gt; generic1 = new GenericClass&lt;&gt;(&quot;String&quot;);
        generic1.setValue(999);
    }

    // 다이아몬드 미 지정시 컴파일 경고 발생
    public void makeObject2(){
        GenericClass&lt;Integer&gt; generic1 = new GenericClass(&quot;String&quot;);
        generic1.setValue(999);
    }

    // 다이아몬드를 안쓰고 명시적으로 지정할 때
    public void makeObject3(){
        GenericClass&lt;Integer&gt; generic1 = new GenericClass&lt;Integer&gt;(&quot;String&quot;);
        generic1.setValue(999);
    }

    // X 타입을 다이아몬드로 선언할 때
    public void makeObject4(){
        GenericClass&lt;Integer&gt; generic1 = new &lt;String&gt; GenericClass&lt;&gt;(&quot;String&quot;);
        generic1.setValue(999);
    }
}</code></pre><p>X와 T, 두가지의 제너릭한 타입이 선언되어있는 클래스이다. 여기서 makeObject4 함수를 컴파일하게 되면 아래와 같은 에러가 발생한다.</p>
<blockquote>
<p>error: cannot infer type arguments for GenericClass<X>
        GenericClass<Integer> generic1 = new <String> GenericClass&lt;&gt;(&quot;String&quot;);
  reason: cannot use &#39;&lt;&gt;&#39; with explicit type parameters for constructor
  where X is a type-variable:
    X extends Object declared in class GenericClass
1 error</p>
</blockquote>
<p>이렇게 명시적으로 타입 T에 대해서 선언한 상태에서, 타입 X에 대해서는 다이아몬드로 선언하여 컴파일러에게 맡겨버리면 컴파일이 정상적으로 되지 않는다. 따라서, <strong><em>생성자에 있는 new와 클래스 이름 사이에 타입 이름을 명시적으로 두려면, 다이아몬드를 사용하면 안된다는 것을 기억</em></strong>하자.</p>
<h3 id="non-reifiable-vararags-타입">Non reifiable vararags 타입</h3>
<p>자바의 제너릭을 사용하면서, 발생 가능한 문제 중 하나가 &quot;reifiable 하지 않은 vararge 타입(non reifiable varargs type)&quot;이다. 이 문제는 자바에서 제너릭을 사용하지 않는 버전과의 호환성을 위해서 제공했던 기능 때문에 발생한다.</p>
<blockquote>
<p>reifiable : 실행시에도 타입정보가 남아있는 타입을 의미
non reifiable : 컴파일시 타입 정보가 손실되는 타입을 의미</p>
</blockquote>
<p>  자바에서 varargs를 사용하면 메소드에 여러 인자를 쉽게 넘길 수 있다. 예를 들어, 여러 리스트를 하나로 합치고 싶을 때 varargs를 사용하는 것이 매우 편리한데, 이 리스트들이 제네릭 타입일 경우 문제가 발생할 수 있다.</p>
<pre><code>public class VarargsExample {
    public static &lt;T&gt; List&lt;T&gt; mergeLists(List&lt;T&gt;... lists) {
        List&lt;T&gt; mergedList = new ArrayList&lt;&gt;();
        for (List&lt;T&gt; list : lists) {
            mergedList.addAll(list);
        }
        return mergedList;
    }
}</code></pre><p>  위 코드에서 mergedLists 메소드는 제너릭 타입의 리스트를 varargs(가변 매개변수) 인자로 받고 있다. 이 소스코드는 컴파일은 되지만, 경고 메시지를 아래와 같이 출력한다.</p>
<blockquote>
<p>Note: VarargsExample.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.</p>
</blockquote>
<p>  왜냐하면, &#39;List<T>... lists&#39;는 내부적으로 List<T>[]로 처리되는데, 제네릭 타입의 배열은 타입 안전성을 보장받지 못하기 때문이다. 배열은 런타임에 타입 정보를 유지하지만, 제네릭은 타입 정보가 런타임에 사라지므로(non-reifiable), 잘못된 타입의 객체가 배열에 추가될 수 있다. 이런 상황을 힙 오염(heap pollution)이라고 한다.</p>
<p>  이러한 문제의 해결책은 자바7에서 도입된 @SafeVararge 어노테이션을 사용하면 된다. 이 어노테이션은 개발자가 해당 메소드의 사용이 타입 안전하다고 명시적으로 선언할 수 있도록 해준다. 이는 컴파일러에게 불필요한 경고를 발생시키지 않도록 지시한다. 위 예제에서 mergeLists 메소드위에 @SafeVarages를 추가시켜주면 해결된다.</p>
<p>  이 애노테이션은 다음과 같은 경우에서만 사용할 수 있다.</p>
<blockquote>
<ul>
<li>가변 매개 변수를 사용</li>
<li>final 이나 static으로 선언되어야 함</li>
</ul>
</blockquote>
<p>  그리고 해당 애노테이션은 아래의 경우에는 컴파일러에서 경고가 발생한다.</p>
<blockquote>
<ul>
<li>가변 매개 변수가 reifiable 타입</li>
<li>매소드 내에서 매개 변수를 다른 변수에 대입하는 작업을 수행하는 경우</li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] JAVA9에서 추가된 내용]]></title>
            <link>https://velog.io/@peten_1105/JAVA-JAVA9%EC%97%90%EC%84%9C-%EC%B6%94%EA%B0%80%EB%90%9C-%EB%82%B4%EC%9A%A9</link>
            <guid>https://velog.io/@peten_1105/JAVA-JAVA9%EC%97%90%EC%84%9C-%EC%B6%94%EA%B0%80%EB%90%9C-%EB%82%B4%EC%9A%A9</guid>
            <pubDate>Sun, 28 Apr 2024 17:09:44 GMT</pubDate>
            <description><![CDATA[<p>JAVA 9에서의 중요한 업데이트와 기능들을 정리하였다.</p>
<ol>
<li>String 클래스</li>
</ol>
<ul>
<li>JAVA9부터는 문자열에 있는 값들을 char 배열에서 byte배열로 변경됨, 변경된 이유는 성능 개선과 메모리 효율을 위함</li>
<li>영문, 숫자, 키보드에 있는 특수문자 : Latin-1 (1byte), 다른 한글, 한자와 같은 문자 : UTF16 (2byte)</li>
<li>내부적으로 coder값을 사용하여 문자열에 따른 coder 방식을 변경하는 것을 자바에서는 Compact String이라고 함.<pre><code>private final byte coder;
static final byte LATIN1 = 0;
static final byte UTF16 = 1;</code></pre></li>
</ul>
<ol start="2">
<li>Interface의 private 메소드를 추가할 수 있음</li>
</ol>
<ul>
<li><p>private 메소드를 추가하게 되면 해당 인터페이스를 구현하는 개발자에게는 노출하고 싶지 않은, 인터페이스 내부에서만 사용 가능한 메소드를 생성할 수 있음</p>
</li>
<li><p>private 메소드는 아래와 같은 규칙이 있음
(1) abstract 메소드로 선언은 안됨, private과 abstract 접근제어자를 같이 사용해도 안됨
(2) 인터페이스 내에 선언한 메소드와 static이나 static이 아닌 인터페이스 메소드에서만 사용 가능함
(3) private로 선언한 static이 아닌 메소드는 다른 private static 메소드에서 사용 불가능함
(4) private으로만 선언해야함</p>
<ol start="3">
<li>새로운 HTTP 클라이언트</li>
</ol>
<ul>
<li>오픈소스 라이브러리처럼 편하게 서버를 호출해서 결과를 받아올 수 있음</li>
<li>HttpClient, HttpRequest, HttpResponse</li>
</ul>
</li>
</ul>
<pre><code>public void newHttpClient(){
    try {
        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(5))
                .build();
        HttpRequest request = HttpRequest.newBuilder()
                .GET()
                .timeout(Duration.ofSeconds(10))
                .uri(URI.create(&quot;https://www.google.com&quot;))
                .build();
        HttpResponse&lt;String&gt; response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
    } catch( Exception e ) {
        e.printStackTrace();
    }
}</code></pre><ol start="4">
<li>Publish-Subscribe 프레임워크<blockquote>
<p>풀링 : 필요시 데이터를 처리하도록 요청하는 것
폴링 : 주기적으로 요청을 해서 변경된 것이 있는지 확인하고 없으면 아무런 작업을 않고, 변경된 것이 있으면 해당 작업을 처리하는 것.</p>
</blockquote>
</li>
</ol>
<ul>
<li>펍섭, 대부분의 메신저가 이러한 개념, 풀링에 해당함</li>
<li>Publisher: 데이터의 생산자로, 구독자가 구독을 요청하면 데이터 항목을 발행(publish)함</li>
<li>Subscriber: 데이터의 소비자로, 필요한 데이터를 받기 위해 퍼블리셔에 구독하여 받은 데이터를 처리하고, 처리할 수 있는 데이터의 양을 퍼블리셔에 알려주어 데이터의 흐름을 제어</li>
<li>Subscription: 퍼블리셔와 구독자 사이의 계약으로, 구독자는 이 객체를 사용해 얼마나 많은 데이터를 받을 준비가 되었는지를 퍼블리셔에 요청함</li>
<li>Processor: 퍼블리셔와 구독자 역할을 동시에 수행하는 요소로, 입력 데이터 스트림을 받아 처리한 후 새로운 데이터 스트림으로 출력할 수 있음</li>
<li>메시지를 보낸 순서를 보장하면서 처리 가능</li>
<li>비동기 처리 : 데이터 스트림의 처리를 비동기적으로 수행할 수 있어, 시스템의 확장성과 반응성을 향상 시킬 수 있음</li>
<li>백 프레셔 관리 : 구독자는 자신이 처리할 수 있는 데이터의 양을 퍼블리셔에게 알려주서 데이터의 과부하를 방지함, 이를 통해서 퍼블리셔와 구독자 간의 데이터 처리 속도 차이를 효과적으로 관리할 수 있음</li>
</ul>
<ol start="5">
<li>자바의 모듈화-직소 프로젝트</li>
</ol>
<ul>
<li>직소 퍼즐과 같이 서로 끼워 맞춰 사용할 수 있도록 모듈화하기 위한 프로젝
트</li>
<li>module-info.java라는 파일이 자바 패키지 최상단에 위치해야함</li>
<li>모듈성, 명시적인 의존성, 강력한 캡슐화등의 특징이 있음.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] JAVA8에서 추가된 내용
]]></title>
            <link>https://velog.io/@peten_1105/JAVA-JAVA8%EC%97%90%EC%84%9C-%EC%B6%94%EA%B0%80%EB%90%9C-%EB%82%B4%EC%9A%A9</link>
            <guid>https://velog.io/@peten_1105/JAVA-JAVA8%EC%97%90%EC%84%9C-%EC%B6%94%EA%B0%80%EB%90%9C-%EB%82%B4%EC%9A%A9</guid>
            <pubDate>Sun, 28 Apr 2024 17:01:46 GMT</pubDate>
            <description><![CDATA[<p>JAVA 8에서의 중요한 업데이트와 기능들을 정리하였다.</p>
<ol>
<li>람다 표현식(Lambda Expressions)</li>
</ol>
<ul>
<li>JAVA8에서 가장 주목 받는 기능 중 하나가 바로 람다 표현식.</li>
<li>간결한 코드 작성을 가능하게 하며, 함수형 프로그래밍을 지원함.</li>
<li>람다 표현식을 사용하면 간단한 클래스들 작성하지 않고도 코드 블록을 쉽고 간결하게 표현할 수 있음<pre><code>// 람다 표현식을 사용하여 리스트의 각 요소 출력
List&lt;String&gt; items = Arrays.asList(&quot;Apple&quot;, &quot;Banana&quot;, &quot;Cherry&quot;, &quot;Date&quot;);
items.forEach(item -&gt; System.out.println(item));
</code></pre></li>
</ul>
<p>// 람다 표현식을 사용하여 두 수의 합을 계산하고 출력
BiFunction&lt;Integer, Integer, Integer&gt; add = (a, b) -&gt; a + b;
System.out.println(&quot;Sum: &quot; + add.apply(10, 20));</p>
<pre><code>
2. 스트림 API(Stream API)
- 스트림 API는 데이터 컬렉션을 함수형 접근 방식으로 처리할 수 있게 해줌
- 이 API를 사용하면 필터링, 매핑, 정렬, 그룹화 등의 연산을 선언적으로 처리할 수 있으며, 멀티스레드 환경에서도 쉽게 병렬 처리를 구현할 수 있음
</code></pre><p>// Stream API를 사용하여 짝수만 필터링하고, 각 숫자의 제곱을 계산한 후 결과를 리스트로 수집
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println(&quot;Squares of even numbers: &quot; + squaresOfEvenNumbers);</p>
<pre><code>
3. 인터페이스의 디폴트 메서드(Default Methods)
- 인터페이스에서 메서드 구현을 포함할 수 있게 되었음
- default 키워드를 사용하여 인터페이스 내에 메서드를 구현할 수 있으며, 이 기능은 기존 JAVA 코드를 유지하면서 새 기능을 추가하는데 유용함

4. 날짜와 시간 API(Date and Time API)
- 기존의 복잡하고 비효율적인 날짜 및 시간 관리 방식을 대체하기 위해 새로운 날짜와 시간 API가 도입되었음(java.time 패키지)
- 이 API는 불변성(immutable)을 기반으로 설계되었으며, 다양한 시간대를 처리할 수 있는 강력한 기능을 제공함</code></pre><p>// 현재 날짜와 시간 가져오기
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();</p>
<p>System.out.println(&quot;Current Date: &quot; + date);
System.out.println(&quot;Current Time: &quot; + time);
System.out.println(&quot;Current Date and Time: &quot; + dateTime);</p>
<pre><code>
5. Optional 클래스
- Optional클래스는 null을 다루는 새로운 방법을 제공함
- 이 클래스를 사용하면, NullPointerException을 보다 쉽게 예방할 수 있음. Optional 객체는 값을 포함하거나 포함하지 않을 수 있으며, 값의 존재 여부에 따라 코드를 실행할 수 있음</code></pre><p>import java.util.Optional;</p>
<p>public class OptionalExample {
    public static void main(String[] args) {
        // 사용자 이름을 Optional 객체로 받기
        Optional<String> optionalName = getUsername();</p>
<pre><code>    // Optional 객체가 값이 있는지 확인하고 값을 사용하거나, 값이 없는 경우 기본 값을 제공하기
    String username = optionalName.orElse(&quot;Guest&quot;);

    System.out.println(&quot;Username: &quot; + username);
}

// 사용자 이름을 반환할 수도 있고, 반환하지 않을 수도 있는 메소드
public static Optional&lt;String&gt; getUsername() {
    String name = null; // 여기서 사용자 이름을 데이터베이스나 API에서 가져오는 것으로 가정

    // name이 null이면 Optional.empty()를 반환하고, 그렇지 않으면 Optional.of()로 값을 감싸서 반환
    return (name != null) ? Optional.of(name) : Optional.empty();
}</code></pre><p>}</p>
<pre><code>
6. 나선형 병렬 배열 정렬(Parallel Arrays Sorting)
- JAVA8에서는 배열을 병렬로 정렬하는 기능을 포함하여 성능을 향상시킴
  ( 여러부분으로 나누어 각각의 부분을 동시에(병렬)처리함으로써 정렬 작업을 더 빠르게 완료할 수 있게 함, JAVA7에서 소개된 Fork-Join프레임워크를 내부적으로 사용함 )
- Arrays.parallelSort() 메서드를 사용하면 멀티스레드 환경에서 배열의 정렬이 효율적으로 이루어짐
- sort()는 단일스레드로 수행되며, parallelSort()는 필요에 따라 멀티스레드로 수행됨. 대략적으로 5000개 정도부터 parallelSort()의 성능이 더 빨라짐.</code></pre><p>int[] array = {9, 3, 1, 5, 13, 12, 7, 4, 11, 6};
// 배열을 병렬로 정렬
Arrays.parallelSort(array);</p>
<pre><code>
7. StringJoiner
- 순차적으로 나열되는 문자열을 처리할 때 사용됨
- 아래의 배열을 그 밑줄 처럼 변환하기 위해서 사용됨
&gt;String[] stringArray=new String[]{”StudyHard&quot;,&quot;GodOf3ava&quot;,&quot;Book&quot;};
=&gt; (StudyHard,GodOfJ ava,Book)
</code></pre><p>public void joinString(String[] stringArray) {
    StringJoiner joiner = new StringJoiner(&quot;,&quot;,&quot;(&quot;,&quot;)&quot;);
    for( String string:stringArray ) {
        joiner.add(string);
    }
    System.out.println(joiner);
}</p>
<pre><code></code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] Fork/Join Framework]]></title>
            <link>https://velog.io/@peten_1105/JAVA-ForkJoin-Framework</link>
            <guid>https://velog.io/@peten_1105/JAVA-ForkJoin-Framework</guid>
            <pubDate>Sat, 27 Apr 2024 07:51:38 GMT</pubDate>
            <description><![CDATA[<p>JAVA7에서 추가된 Fork/Join Framework를 설명하기 전에 기존에 ThreadPool에 대해서 설명해보면 다음과 같다.</p>
<h3 id="threadpool">ThreadPool</h3>
<p>ThreadPool은 여러 스레드들 미리 생성하고 관리하는 프로그래밍 구조이다. 이를 통해서 멀티 스레드 애플리케이션에서의 성능을 향상 시킬수 있는데, 스레드를 필요할 때마다 생성하고, 소멸시키는 비용은 상당히 높기 때문에, 미리 생성된 스레드들을 재사용함으로써 이러한 비용을 절감할 수 있다는 장점이 있다.</p>
<h3 id="threadpool의-기본-작동-방식">ThreadPool의 기본 작동 방식</h3>
<ol>
<li>스레드 생성 : 애플리케이션이 시작할 대 스레드 풀은 설정된 수만큼의 스레드를 생성한다.</li>
<li>작업 요청 처리 : 작업 요청이 들어오면, 스레드 풀은 이용가능한 스레드 중 하나를 할당하여 작업을 처리하도록한다.</li>
<li>스레드 재사용 : 작업을 완료한 스레드는 다시 스레드 풀로 반환되어 다음 작업을 대기한다/</li>
</ol>
<h3 id="threadpool의-장점">ThreadPool의 장점</h3>
<ul>
<li>리소스 효율성 : 스레드의 생성과 소멸에 필요한 자원과 시간을 절약할 수 있다.</li>
<li>응답성 향상 : 작업을 즉시 처리할 수 있는 스레드가 이미 존재하기 때문에, 응답시간이 단축된다.</li>
<li>스레드 관리 : 스레드의 최대 개수를 제어하여 시스템 자원의 과도한 사용을 방지할 수 있다.</li>
</ul>
<h3 id="threadpool의-단점">ThreadPool의 단점</h3>
<ul>
<li>오버헤드 : 스레드 풀을 관리하는데에는 약간의 오버헤드가 발생한다.</li>
<li>자원 공유 문제 : 여러 스레드가 자원을 공유하므로, 동기화 문제가 발생할 수 있다.</li>
</ul>
<p>JAVA에서는 &#39;java.util.concurrent&#39; 패키지 안에 &#39;ExecutorService&#39; 인터페이스와 &#39;Excutors&#39; 유틸리티 클래스를 통해 스레드 풀을 쉽게 사용할 수 있다.</p>
<h3 id="forkjoin-framework">Fork/Join Framework</h3>
<p>Fork/Join Framwork는 JAVA 7에서 도입된 병렬 처리를 위한 프레임워크이고, 주로 큰 작업을 작은 작업으로 나누고 작업을 병렬로 처리한 후 그 결과를 합치는 분할 정복 방식에 최적화 되어 있다. 이 프레임워크는 &#39;java.util.concurrent&#39; 패키지의 일부로 특히 RecursiveAction과 RecursiveTask 두 가지 주요 추상 클래스를 제공한다.</p>
<p>작업 훔치기(Work-Stealing) 알고리즘을 사용하여, 각 스레드는 자신의 큐에 할당된 작업을 수행하다가 일을 마치면 다른 스레드의 큐에서 대기 중인 작업을 훔쳐와서 실행한다. 이 방식은 모든 스레드가 계속해서 작업을 처리할 수 있도록 하고 있기 때문에 리소스의 활용도를 높인다.</p>
<h3 id="threadpool과-forkjoin-framework-비교">ThreadPool과 Fork/Join Framework 비교</h3>
<h4 id="--forkjoin-framework">- Fork/Join Framework</h4>
<ol>
<li>효율적인 작업 분배 : 작업 훔치기 알고리즘을 통해 유휴 상태의 스레드가 발생할 확률을 최소화하고, 모든 스레드가 균등하게 작업을 처리함</li>
<li>높은 병렬 처리 성능 : 분할 정복 알고리즘에 적합하며, 복잡한 계산 작업을 빠르게 처리할 수 있음</li>
<li>구현 복잡성 : 기본적인 스레드 풀 사용에 비해 작업 분할 및 결합 로직을 직접 구현해야하므로 복잡할 수 있음</li>
<li>특정 상황에 제한적 : 주로 분할 정복 방식에 적합하므로, 모든 종류의 작업에 이 프레임워크를 사용하는 것은 적절하지 않을 수 있음</li>
</ol>
<h4 id="--threadpool">- ThreadPool</h4>
<ol>
<li>간단한 사용법 : ExecutorService 인터페이스를 사용하여 스레드 풀을 쉽게 구현하고 관리할 수 있음</li>
<li>다양한 유형지원 : 고정 크기, 캐시된 스레드 풀, 단일 스레드 실행자 등 다양한 스레드 풀을 선택할 수 있음</li>
<li>리소스 낭비 가능성 : 고정된 수의 스레드를 사용하기 때문에, 일부 스레드가 유휴 상태가 되거나 반대로 과부하가 발생할 수 있음</li>
<li>동적 조정 미지원 : 스레드 수를 동적으로 조정하는 것이 어렵거나 불가능할 수 있어, 변동적인 작업 부하에 대응하기 어려움</li>
</ol>
<p>Fork/Join Framework는 복잡한 계산이나 대량의 데이터 처리에 적합하고, 일반적인 ThreadPool은 간단하고 반복적인 작업에 더 적합할 수 있다. ThreadPool과 Fork/Join Framework를 사용하는 예제 소스를 보면서 비교해보자.</p>
<pre><code>import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExample {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(4); // 4개의 스레드를 가진 풀 생성

        for (int i = 0; i &lt; 20; i++) {
            int taskNumber = i;
            executor.execute(() -&gt; {
                System.out.println(&quot;Executing Task &quot; + taskNumber + &quot; on thread &quot; + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 시뮬레이션을 위한 1초 대기
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }

        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.HOURS);
    }
}</code></pre><p>출력 결과</p>
<blockquote>
<p>Executing Task 3 on thread pool-1-thread-4
Executing Task 0 on thread pool-1-thread-1
Executing Task 2 on thread pool-1-thread-3
Executing Task 1 on thread pool-1-thread-2
Executing Task 5 on thread pool-1-thread-1
Executing Task 4 on thread pool-1-thread-3
Executing Task 6 on thread pool-1-thread-2
Executing Task 7 on thread pool-1-thread-4
Executing Task 8 on thread pool-1-thread-1
Executing Task 9 on thread pool-1-thread-3
Executing Task 10 on thread pool-1-thread-2
Executing Task 11 on thread pool-1-thread-4
Executing Task 12 on thread pool-1-thread-1
Executing Task 13 on thread pool-1-thread-3
Executing Task 14 on thread pool-1-thread-2
Executing Task 15 on thread pool-1-thread-4
Executing Task 16 on thread pool-1-thread-1
Executing Task 17 on thread pool-1-thread-3
Executing Task 18 on thread pool-1-thread-2
Executing Task 19 on thread pool-1-thread-4</p>
</blockquote>
<p>기존 JAVA에서 ExecutorService를 사용하여 간단한 작업을 병렬로 처리하는 예제이다.
이 코드는 20개의 작업을 생성하고, 고정된 크기(4개)의 스레드 풀에서 이 작업들을 실행한다. 각 작업은 현재 실행중인 스레드의 이름을 출력하고, 1초간 대기한다.</p>
<h3 id="threadpool의-한계점">ThreadPool의 한계점</h3>
<ul>
<li>부하 균형 문제 : 위 예제에서 스레드 풀은 고정된 수의 스레드(4개)를 가진다. 모든 스레드가 동시에 작업을 처리하지만, 특정 시점에서 작업의 수가 스레드 수보다 적거나 많을 수 있다. 이 경우 일부 스레드 유휴 상태가 되거나, 작업이 균등하게 분배되지 않아 효율성이 떨어질 수 있다.</li>
<li>동적 조정 미지원 : 고정된 수의 스레드를 사용하므로, 시스템의 부하에 따라 스레드 수를 동적으로 조정할 수 없다. 이는 리소스 활용도와 성능에 제한을 준다.</li>
</ul>
<pre><code>import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

public class ForkJoinExample extends RecursiveAction {
    private final int start;
    private final int end;
    private static final int THRESHOLD = 5;

    public ForkJoinExample(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected void compute() {
        if (end - start &lt;= THRESHOLD) {
            for (int i = start; i &lt; end; i++) {
                System.out.println(&quot;Processing &quot; + i + &quot; on thread &quot; + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        } else {
            int mid = start + (end - start) / 2;
            ForkJoinExample left = new ForkJoinExample(start, mid);
            ForkJoinExample right = new ForkJoinExample(mid, end);
            invokeAll(left, right);
        }
    }

    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();
        pool.invoke(new ForkJoinExample(0, 20));
        pool.shutdown();
    }
}</code></pre><p>출력 결과</p>
<blockquote>
<p>Processing 15 on thread ForkJoinPool-1-worker-4
Processing 5 on thread ForkJoinPool-1-worker-3
Processing 10 on thread ForkJoinPool-1-worker-2
Processing 0 on thread ForkJoinPool-1-worker-1
Processing 16 on thread ForkJoinPool-1-worker-4
Processing 6 on thread ForkJoinPool-1-worker-3
Processing 11 on thread ForkJoinPool-1-worker-2
Processing 1 on thread ForkJoinPool-1-worker-1
Processing 17 on thread ForkJoinPool-1-worker-4
Processing 12 on thread ForkJoinPool-1-worker-2
Processing 7 on thread ForkJoinPool-1-worker-3
Processing 2 on thread ForkJoinPool-1-worker-1
Processing 13 on thread ForkJoinPool-1-worker-2
Processing 8 on thread ForkJoinPool-1-worker-3
Processing 3 on thread ForkJoinPool-1-worker-1
Processing 18 on thread ForkJoinPool-1-worker-4
Processing 14 on thread ForkJoinPool-1-worker-2
Processing 9 on thread ForkJoinPool-1-worker-3
Processing 19 on thread ForkJoinPool-1-worker-4
Processing 4 on thread ForkJoinPool-1-worker-1</p>
</blockquote>
<p>이 코드는 비슷한 작업을 분할 정복 방식으로 처리하는 예제이다. 작업을 더 작은 단위로 나누고 각 부분을 별도의 스레드에서 처리한다. invokeAll 메소드는 분할된 작업들을 병렬로 실행하고 완료될 때까지 기다린다. 이 방식은 작업이 균등하게 분배되고, 스레드 풀의 스레드가 최대한 효율적으로 사용된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] JAVA7에서 추가된 내용]]></title>
            <link>https://velog.io/@peten_1105/JAVA-JAVA7%EC%97%90%EC%84%9C-%EC%B6%94%EA%B0%80%EB%90%9C-%EB%82%B4%EC%9A%A9</link>
            <guid>https://velog.io/@peten_1105/JAVA-JAVA7%EC%97%90%EC%84%9C-%EC%B6%94%EA%B0%80%EB%90%9C-%EB%82%B4%EC%9A%A9</guid>
            <pubDate>Sat, 27 Apr 2024 04:48:17 GMT</pubDate>
            <description><![CDATA[<p>JAVA 7에서의 중요한 업데이트와 기능들을 정리하였다.</p>
<ol>
<li>언어 개선 프로젝트(Project Coin)</li>
</ol>
<ul>
<li>이진 리터럴과 숫자 리터럴의 밑줄 사용 : 숫자를 더 쉽게 읽을 수 있도록 밑줄(&quot;_&quot;)을 사용하여 숫자를 구분할 수 있게 되었음</li>
<li>다중 예외 처리 : 아래와 같이 하나의 catch 블록에서 여러 예외를 처리할 수 있게 되었음. 이를 통해 코드의 중복을 줄일 수 있음<pre><code>try {
  // try 구문 안
} catch( ExceptionA | ExceptionB e ) {
  // 예외 처리 로직이 들어갈 곳.
}</code></pre></li>
<li>타입 추론의 개선(diamond 연산자 =&gt; &quot;&lt;&gt;&quot;) : 제너릭 인스턴스 생성 시 컴파일러가 인수의 타입을 추론할 수 있게 하여 코드를 간결하게 할 수 있게 되었음</li>
</ul>
<pre><code>// jdk 7 이전 : 선언시에도 제네릭에 타입을 명시해야함.
List&lt;Integer&gt; list = new ArrayList&lt;Integer&gt;();

Map&lt;String, List&lt;String&gt;&gt; map = new HashMap&lt;String, List&lt;string&gt;&gt;();
// jdk 7 이후(타입추론) : 다이아몬드 연산자 사용으로 컴파일러가 알아서 추론한다. 
List&lt;Intger&gt; list = new ArrayList&lt;&gt;();

Map&lt;String, List&lt;String&gt;&gt; map = new HashMap&lt;&gt;();</code></pre><p>( 소스 출처 : <a href="https://velog.io/@cateto/Java-%EB%8B%A4%EC%9D%B4%EC%95%84%EB%AA%AC%EB%93%9C-%EC%97%B0%EC%82%B0%EC%9E%90Diamond-Operator-Java-1.7%EB%B6%80%ED%84%B0-%EC%B6%94%EA%B0%80">cateto.log</a> )</p>
<ul>
<li>try-with-resource 문 : 자동으로 리소스를 정리할 수 있는 구문이 추가되어 리소스를 효율적으로 관리할 수 있게 되었음<pre><code>// 자원은 try() 괄호 안에 선언되어있어야하고, 해당 자원 클래스가 AutoCloseable 인터페이스를 구현해야함.
try(BufferedReader br = new BufferedReader(new FileReader(&quot;./test.txt&quot;))) {
  // try 내부 로직
} catch( IOException e ) {
  // 예외 처리 로직이 들어갈 곳.
}</code></pre></li>
<li>문자열 switch 문 : switch 문에서 문자열을 직접 사용할 수 있게 되어 프로그래밍이 편리해짐<pre><code>String str = &quot;TEST2&quot;;
switch(str) {
  case &quot;TEST1&quot;: break;
  case &quot;TEST2&quot;: break;
  default: break;
}</code></pre></li>
</ul>
<ol start="2">
<li>JAVA Virtual Machine(JVM) 개선</li>
</ol>
<ul>
<li>Java Virtual Machine 지원: invoke dynamic 명령어가 추가되어 동적 언어의 성능이 개선되었음. 이는 JVM에서 스크립팅 언어의 실행 성능을 향상시키기 위한 변경임.</li>
</ul>
<ol start="3">
<li>병렬 작업에 대한 라이브러리 개선</li>
</ol>
<ul>
<li>Fork/Join Framework : 병렬 작업을 쉽게 작성할 수 있도록 설계된 프레임워크. 이는 대규모 처리를 위한 효율적인 병렬성을 제공함</li>
</ul>
<ol start="4">
<li>입출력 및 네트워킹 개선</li>
</ol>
<ul>
<li>New File System API(NIO.2) : 파일 시스템 관리를 위한 새로운 API가 추가되어, 파일 이벤트를 감지하고, 심볼릭 링크를 처리하며, 파일 시스템의 다양한 속성을 보다 쉽게 접근할 수 있음</li>
</ul>
<ol start="5">
<li>보안 기능 강화</li>
</ol>
<ul>
<li>업그레이드된 암호화 기능 : 새로운 암호화 알고리즘과 기능이 추가되어 JAVA의 보안성이 강화되었음</li>
</ul>
<ol start="6">
<li>국제화 및 지역 설정 개선</li>
</ol>
<ul>
<li>지원 언어 및 스크립트 확장 : 추가적인 유니코드 지원과 함께, 여러 새로운 언어와 스크립트에 대한 지원이 확대되었음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] try-with-resources]]></title>
            <link>https://velog.io/@peten_1105/JAVA-try-with-resources</link>
            <guid>https://velog.io/@peten_1105/JAVA-try-with-resources</guid>
            <pubDate>Sat, 27 Apr 2024 03:26:46 GMT</pubDate>
            <description><![CDATA[<p>JAVA7에서 추가된 try-with-resources 구문은 자원을 효율적으로 관리하기 위한 방법 중 하나이다. 이 구문은 파일, 네트워크 연결 또는 데이터베이스 연결과 같은 자원을 사용한 후 자동으로 해제하도록 설계되었다. 이전에는 &#39;finally&#39;블록에서 자원을 명시적으로 해제했어야 했는데, try-with-resources 구문을 사용하면 이 과정이 자동화되어 개발자의 실수를 줄이고 코드의 가독성을 높일 수 있다.</p>
<h3 id="주요-특징">주요 특징</h3>
<ol>
<li>자동 자원 해제 : try 블록내에 선언된 자원은 블록이 종료될 때 자동으로 해제된다.</li>
<li>가독성 향상 : 코드의 복잡성을 줄이고, 자원 해제를 위한 코드를 작성할 필요가 없어진다.</li>
<li>예외 처리 간소화 : 자원 해제 중 발생할 수 있는 예외를 자동으로 처리할 수 있다.</li>
</ol>
<h3 id="사용-조건">사용 조건</h3>
<p>try-with-resources를 사용하기 위해서는 해당 자원 클래스가 &#39;AutoCloseable&#39;인터페이스를 구현해야 한다. 이 인터페이스는 &#39;close()&#39; 메소드를 포함하고 있으며, 이 메소드가 자원 해제의 핵심이다.</p>
<h3 id="예제-코드">예제 코드</h3>
<p>해당 구문을 사용한 파일을 읽는 간단한 예제다.</p>
<pre><code>import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class TryWithResourcesExample {
    public static void main(String[] args) {
        // 파일 경로 지정
        String path = &quot;example.txt&quot;;

        // try-with-resources 구문을 사용하여 파일을 열고 읽음
        try (BufferedReader br = new BufferedReader(new FileReader(path))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println(&quot;Error reading the file: &quot; + e.getMessage());
        }
    }
}

/*
cat example.txt
test1
test2
test3
test4
*/</code></pre><p>출력 결과</p>
<blockquote>
<p>test1
test2
test3
test4</p>
</blockquote>
<p>이 코드에서 BufferedReader는 AutoCloseable 인터페이스를 구현하고 있으므로 try() 구문 안에 선언될 수 있다. 파일 읽기 작업이 끝나면, BufferedReader의 close() 메소드가 자동으로 호출되어 자원이 해제된다. 이로써 개발자는 자원을 명시적으로 해제하는 코드를 작성할 필요가 없다.</p>
<p>이 구문의 도입으로 자바 개발자들을 자원 관리를 더 간편하고 안전하게 할 수 있게 되었다. 이러한 기능은 코드의 신뢰성을 높이고, 자원 누수 가능성을 줄이는 데 큰 도움이 된다.</p>
<p>위에서 처럼 try-with-resources 구문은 try() 괄호 안에 선언된 모든 자원에 대해 자동 해제를 보장한다. 하지만 여기서 주의할 점은, 자동으로 해제되는 자원은 try() 괄호 안에서 선언된 자원들만 해당된다는 점이 중요하다. 이 자원들은 모두 AutoCloseable 인터페이스를 구현해야하며, 이 인터페이스의 close() 메소드가 블록의 실행이 끝날 때 호출된다.</p>
<h3 id="자동해제가-보장되는-조건">자동해제가 보장되는 조건</h3>
<ol>
<li>해제할 자원은 <strong>AutoCloseable 인터페이스</strong>를 구현해야한다. 이 인터페이스에서 close 메소드가 정의되어있어야 하며, 이 메소드는 자원을 해제하는 데 필요한 모든 코드를 포함한다.</li>
<li>자원은 try() 괄호 안에 선언되어야 한다. 오직 이 위치에 선언된 자원들만이 블록을 벗어날 때 자동으로 해제된다.</li>
</ol>
<p>예를 들어, 다음과 같은 경우는 try-with-resources 자동 해제 대상이 아니다.</p>
<pre><code>BufferedReader br = null;
try {
    br = new BufferedReader(new FileReader(&quot;example.txt&quot;));
    // 여기서 파일을 읽는 작업 수행
} catch (IOException e) {
    e.printStackTrace();
}</code></pre><p>위 코드에서 BufferedReader 인스턴스 try() 구문 밖에서 선언되었기 때문에 자동으로 해제되지 않는다. 이 경우에는 여전히 finally 블록을 사용하여 close 메소드를 명시적으로 호출해야한다.</p>
<h3 id="autocloseable-인터페이스를-구현하는-자원들의-종류">AutoCloseable 인터페이스를 구현하는 자원들의 종류</h3>
<p>AutoCloseable 인터페이스를 구현하는 자원들은 주로 외부 시스템과의 연결이나 파일 시스템 리소스를 관리하는 클래스들이다.</p>
<ol>
<li>파일 I/O 자원 : FileInputStream, FileOutputStream, FileReader, FileWriter, BufferedReader, BufferedWriter, RandomAccessFile</li>
<li>네트워크 I/O 자원 : Socket, ServerSocket, DatagramSocket</li>
<li>데이터베이스 연결 자원 : Connection, PreparedStatement, ResultSet</li>
<li>다른 스트림 및 채널 : InputStream, OutputStream, Reader, Writer, java.nio.channels.Channel의 서버 클래스들(FileChannel)</li>
<li>기타 : ZipFile, Scanner, java.util.Timer(타이머 관리)</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] TCP/UDP]]></title>
            <link>https://velog.io/@peten_1105/JAVA-TCPUDP</link>
            <guid>https://velog.io/@peten_1105/JAVA-TCPUDP</guid>
            <pubDate>Tue, 23 Apr 2024 16:43:20 GMT</pubDate>
            <description><![CDATA[<p>JAVA에서 네트워크 통신을 하기 위해서는 기본으로 제공되는 클래스는 TCP 통신을 위한 Socket 클래스와 UDP 통신을 위한 Datagram 관련 클래스로 나뉜다.
또한 간단하게 웹에 접속하고 데이터를 처리하는 URL 클래스가 있긴 하지만, 섬세한 설정이 불가능하기 때문에 Apache에서 제공하는 HttpClient 클래스를 사용할 것을 권장한다.</p>
<h3 id="tcp-처리를-위한-socket">TCP 처리를 위한 Socket</h3>
<ul>
<li>Socket 클래스는 데이터를 전달하고, 받기 위해서 사용하는 클래스이다.</li>
<li>ServerSocket클래스는 데이터를 수신하기 위해서 사용하는 클래스이다. 클라이언트에서 데이터를 전달하면 Socket 객체로 받아 처리하면된다.</li>
<li>데이터를 주고 받는 것은 Socket 클래스를 통하여 Stream이나 Reader/Writer  객체로 처리하면 된다.</li>
<li>TCP는 연결 지향적 프로토콜으로, 데이터 전송 전에 서버와 클라이언트 간의 연결 설정이 필요하다. 이러한 연결 설정은 3Way Handshake 과정을 통해서 이루어지게 되고, 연결해제시에는 4Way Handshake 과정을 통해서 이루어지게된다.</li>
</ul>
<p>아래는 TCP를 이용한 간단한 Echo Server / Client 소스이다.</p>
<pre><code>import java.io.*;
import java.net.*;

public class EchoServer {
    public static void main(String[] args) throws IOException {
        int port = 3333;
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println(&quot;Server is listening on port &quot; + port);

        while (true) {
            Socket clientSocket = serverSocket.accept();
            System.out.println(&quot;New client connected&quot;);

            BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);

            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                System.out.println(&quot;Received from client: &quot; + inputLine);
                out.println(inputLine); // Echo the same line back to the client
            }

            clientSocket.close();
            System.out.println(&quot;Client connection closed&quot;);
        }
    }
}</code></pre><pre><code>import java.io.*;
import java.net.*;

public class EchoClient {
    public static void main(String[] args) throws IOException {
        String serverAddress = &quot;127.0.0.1&quot;;
        int port = 3333;
        Socket socket = new Socket(serverAddress, port);
        System.out.println(&quot;Connected to server&quot;);

        PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));

        String userInput;
        while ((userInput = stdIn.readLine()) != null) {
            out.println(userInput);
            System.out.println(&quot;Server replies: &quot; + in.readLine());
        }

        socket.close();
        System.out.println(&quot;Socket closed&quot;);
    }
}</code></pre><p>출력 결과(EchoServer)</p>
<blockquote>
<p>Server is listening on port 3333
New client connected
Received from client: hi</p>
</blockquote>
<p>출력 결과(EchoClient)</p>
<blockquote>
<p>Connected to server
hi
Server replies: hi</p>
</blockquote>
<h3 id="udp를-처리하기-위한-datagram">UDP를 처리하기 위한 Datagram</h3>
<ul>
<li>DatagramPacket 클래스는 데이터를 전달하고, 받기 위해서 사용하는 클래스이다.</li>
<li>DatagramSocket는 데이터를 수신하기 위해서 사용하는 클래스이다. 클라이언트에서 데이터를 전달하면 DatagramPacket 객체로 받아 처리하면 된다.</li>
<li>TCP는 연결할 때부터 데이터를 받는 서버가 시작되어 있어야만 데이터를 전송할 수 있지만, UDP는 데이터를 받는 서버가 시작 여부 및 데이터 송수신 가능 여부와 상관 없이 데이터를 전송할 수 있다.</li>
<li>실시간 통신에 유리하나, 신뢰성이 낮고 순서가 보장되지 않는다는 특징이 있다.</li>
</ul>
<p>아래는 UDP를 사용한 간단한 Echo Server / Client 소스이다.</p>
<pre><code>import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class EchoUDPServer {
    public static void main(String[] args) {
        try (DatagramSocket socket = new DatagramSocket(4445)) {
            byte[] buffer = new byte[1024];

            while (true) {
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                socket.receive(packet); // 패킷 수신

                // 수신된 패킷에서 데이터와 클라이언트 주소, 포트 정보 추출
                String received = new String(packet.getData(), 0, packet.getLength());
                System.out.println(&quot;Received: &quot; + received);

                // 동일한 내용으로 클라이언트에게 패킷 전송
                socket.send(packet);
                System.out.println(&quot;Echoed back to client&quot;);
            }
        } catch (SocketException e) {
            System.err.println(&quot;SocketException: &quot; + e.getMessage());
        } catch (IOException e) {
            System.err.println(&quot;IOException: &quot; + e.getMessage());
        }
    }
}</code></pre><pre><code>import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;

public class EchoUDPClient {
    public static void main(String[] args) {
        try (DatagramSocket socket = new DatagramSocket()) {
            InetAddress address = InetAddress.getByName(&quot;localhost&quot;);
            String message = &quot;Hello, UDP Server!&quot;;
            byte[] buffer = message.getBytes();

            // 서버 주소와 포트를 지정하여 패킷 생성
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length, address, 4445);
            socket.send(packet); // 서버로 패킷 전송
            System.out.println(&quot;Message sent to server&quot;);

            // 서버로부터 응답을 받기 위해 패킷을 준비
            packet = new DatagramPacket(buffer, buffer.length);
            socket.receive(packet); // 패킷 수신
            String received = new String(packet.getData(), 0, packet.getLength());

            System.out.println(&quot;Echo from server: &quot; + received);
        } catch (UnknownHostException e) {
            System.err.println(&quot;UnknownHostException: &quot; + e.getMessage());
        } catch (IOException e) {
            System.err.println(&quot;IOException: &quot; + e.getMessage());
        }
    }
}</code></pre><p>출력 결과(EchoUDPServer)</p>
<blockquote>
<p>Received: Hello, UDP Server!
Echoed back to client</p>
</blockquote>
<p>출력 결과(EchoUDPClient)</p>
<blockquote>
<p>Message sent to server
Echo from server: Hello, UDP Server!</p>
</blockquote>
<p>UDP는 TCP처럼 연결지향성이 아니기때문에 EchoClient가 실행되면 미리 정해진 message를 보내고, EchoServer로부터 받아온 메시지를 출력하고 종료하도록 되어있다. 이를 보면서 UDP를 사용하는 경우 연결 설정이나 종료 같은 과정이 필요없고, 각 패킷은 독립적으로 처리된다는 것을 알 수 있다. </p>
<p>추가적으로 네트워크 보안을 강화하기 위해서는 데이터 전송시에 SSL/TLS등을 사용하여 암호화를 적용할 수 있고, 성능 최적화를 위해서 소켓 버퍼를 늘리거나 비동기 I/O를 사용하여 언블로킹 소켓을 사용할 수도 있다. 또한 하나의 프로세스에서 TCP 소켓을 많이 늘려 멀티스레드 환경에서 다수의 클라이언트 요청을 처리하도록 효율적으로 구성할 수도 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] Serializable와 NIO]]></title>
            <link>https://velog.io/@peten_1105/JAVA-Serializable%EC%99%80-NIO</link>
            <guid>https://velog.io/@peten_1105/JAVA-Serializable%EC%99%80-NIO</guid>
            <pubDate>Tue, 23 Apr 2024 15:14:25 GMT</pubDate>
            <description><![CDATA[<p>JAVA 개발을 하다보면 데이터를 파일, 데이터베이스 또는 다른 컴퓨터로 전송할 때 중요한 기술이 있는데, 그 중에 하나가 바로 객체직렬화(Serializable)이다.</p>
<h3 id="객체직렬화란">객체직렬화란?</h3>
<p>객체직렬화는 객체의 메모리 상태를 포함한 모든 정보를 바이트스트림(stream of bytes)형태로 인코딩하는 과정을 말한다. 이과정을 통해 객체는 파일 시스템, 데이터베이스, 네트워크 등을 쉽게 전송하거나 저장할 수 있게된다.
<img src="https://velog.velcdn.com/images/peten_1105/post/bc86dbe1-2e71-44e2-bc0b-54e1c45bd83b/image.png" alt=""></p>
<blockquote>
<p>바이트스트림(stream of bytes)란?
스트림은 클라이언트나 서버 간에 출발지, 목적지로 입출력하기 위한 데이터가 흐르는 통로를 말한다.
자바는 스트림의 기본 단위를 바이트로 두고 있기 때문에, 네트워크, 데이터베이스로 전송하기 위해 최소 단위인 바이트 스트림을 변환하여 처리한다.</p>
</blockquote>
<p>(출처 : <a href="https://velog.io/@jyyoun1022/%EC%A7%81%EB%A0%AC%ED%99%94Serializable">직렬화_CodeJ.log</a> )</p>
<h3 id="구현하기위해서는">구현하기위해서는?</h3>
<p>구현하기위해서는 &#39;java.io.Serializable&#39;인터페이스를 구현해야한다. 이는 메소드를 포함하지 않는 인터페이스로, 클래스의 객체가 직렬화를 지원한다는 것을 JVM에 알리는 역할을 한다.</p>
<h4 id="직렬화-과정">직렬화 과정:</h4>
<p><strong>1. 스트림 생성</strong> : 객체를 직렬화하기 위해 &quot;FileOutputStream&quot; 등의 출력 스트림을 생성한다.
<strong>2. 스트림 연결</strong> : 생성된 출력 스트림을 ObjectOutputStream에 연결한다.
<strong>3. 객체 쓰기</strong> : ObjectOutputStream의 writeObject 메소드를 호출하여 객체를 스트림에 쓰고, 이를 통해 파일이나 네트워크를 통해 전송한다.</p>
<h4 id="역직렬화-과정">역직렬화 과정:</h4>
<p>역직렬화는 직렬화된 데이터 스트림을 다시 JAVA 객체로 변환하는 과정이다. ObjectInputStream을 사용하여 직렬화된 데이터를 읽고, readObject 메소드로 객체를 복원한다.</p>
<pre><code>import java.io.*;

public class Person implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;
    private transient String email;  // transient 키워드로 직렬화에서 제외

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

    public String toString() {
        return &quot;Person [name=&quot; + name + &quot;, age=&quot; + age + &quot;, email=&quot; + email + &quot;]&quot;;
    }

    public static void main(String[] args) {
        Person p = new Person(&quot;John Doe&quot;, 30, &quot;john.doe@example.com&quot;);
        String filename = &quot;person.ser&quot;;

        // 객체 직렬화
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename))) {
            out.writeObject(p);
            System.out.println(&quot;Object has been serialized&quot;);
        } catch (IOException ex) {
            System.out.println(&quot;IOException is caught&quot;);
        }

        // 객체 역직렬화
        Person pDeserialized = null;
        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename))) {
            pDeserialized = (Person) in.readObject();
            System.out.println(&quot;Object has been deserialized&quot;);
            System.out.println(pDeserialized); // email 필드는 null로 출력될 것임
        } catch (IOException ex) {
            System.out.println(&quot;IOException is caught&quot;);
        } catch (ClassNotFoundException ex) {
            System.out.println(&quot;ClassNotFoundException is caught&quot;);
        }
    }
}</code></pre><p>출력 결과</p>
<blockquote>
<p>Object has been serialized
Object has been deserialized
Person [name=John Doe, age=30, email=null]</p>
</blockquote>
<p>transient : Serializable로 선언한 객체 내에 전송하거나 저장하지 않는 변수를 선언할 때 사용한다. 위 예제의 email은 직렬화 대상에서 제외한다.</p>
<p>serialVersionUID : 직렬화된 객체를 역직렬화할 때 클래스 버전의 일치를 확인하는 데 사용되는 고유 식별자이다. 클래스를 수정하고 난 후에도 역직렬화 과정에서 호환성을 유지하기 위해 필요하다. serialVersionUID가 일치하지 않으면 InvalidClassException이 발생할 수 있다.</p>
<h3 id="자바-nio">자바 NIO</h3>
<p>JDK 1.4에서부터 NIO(New IO)라는 것이 추가되었다. 이 것이 생긴이유는 속도 때문이다. NIO는 지금까지 사용한 스트림을 사용하지 않고, 대신 채널(Channel)과 버퍼(Buffer)를 사용한다.</p>
<pre><code>import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class NioSample {
    public static void main(String[] args){
        NioSample sample = new NioSample();
        sample.basicWriteAndRead();
    }

    public void basicWriteAndRead(){
        String fileName = &quot;./nio.txt&quot;;
        try {
            writeFile(fileName, &quot;My first NIO Sample&quot;);
            readFile(fileName);
        } catch(Exception e){
            e.printStackTrace();
        }
    }

    public void writeFile(String fileName, String data) throws Exception {
        FileChannel channel = new FileOutputStream(fileName).getChannel(); // 파일을 쓰기 위한 FileChannel 객체를 만들려면, FileOutputStream 클래스에 선언된 getChannel() 메소르를 호출
        byte[] byteData = data.getBytes(); 
        ByteBuffer buffer = ByteBuffer.wrap(byteData); // static으로 선언된 wrap()이라는 메소드를 호출하면, ByteBuffer 객체가 생성된다. 
        channel.write(buffer);  // FileChannel 클래스에 선언된 write() 메소드에 buffer 객체를 넘겨주면 파일에 쓰게된다.
        channel.close(); 
    }

    public void readFile(String fileName) throws Exception {
        FileChannel channel = new FileInputStream(fileName).getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(1024); // ByteBuffer 클래스에 선언되어 있는 allocate() 메소드를 통해서 buffer라는 객체를 만들었다. 
        channel.read(buffer); // 데이터가 buffer 에 담으라고 알려준다.
        buffer.flip(); // buffer 에 담겨있는 데이터의 가장 앞으로 이동한다.
        while(buffer.hasRemaining()){  // hasRemaining() 메소드를 사용하여 데이터가 더 남아있는지를 확인하면서 반복작업을 수행한다. 
            System.out.println((char)buffer.get()); // get 메소드는 한 바이트씩 데이터를 읽는 작업을 수행한다.
        }
        channel.close();
    }
}</code></pre><p>출력 결과</p>
<blockquote>
<p>My first NIO Sample</p>
</blockquote>
<p>위 예제소스처럼 파일 데이터를 다룰 때는 ByteBuffer라는 버퍼와 FileChannel 이라는 채널을 사용하면 간단하게 처리할 수 있다. Channel의 경우 그냥 간단하게 객체만 생성하여 read()나 write() 메소드만 불러주면 된다고 생각하면 된다.</p>
<p>자바의 Serializable 인터페이스와 NIO 대해서 기초적인 내용을 정리하였다. NIO에 대해서 좀 더 알아볼 필요성이 있을거 같다. </p>
<p>그리고 객체직렬화라고 한다면 통신, 통신이라면 빅엔디안 / 리틀엔디안 변환 과정이 있어야하는데 JAVA에서는 다른 언어들처럼 네트워크 전송을 위해서 리틀 엔디안/빅 엔디안를 구분하지 않고, 대부분의 경우 빅 엔디안(Big-Endian) 방식을 사용한다. JAVA는 JVM 위에서 수행하므로 대부분 빅 엔디안 방식을 사용하여 처리한다. 물론 ByteBuffer 클래스에서 order(ByteOrder.LITTLE_ENDIAN)을 사용하여 리틀 엔디안으로도 데이터 처리를 사용할 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] Thread]]></title>
            <link>https://velog.io/@peten_1105/JAVA-Thread</link>
            <guid>https://velog.io/@peten_1105/JAVA-Thread</guid>
            <pubDate>Mon, 22 Apr 2024 16:44:25 GMT</pubDate>
            <description><![CDATA[<h3 id="스레드">스레드</h3>
<p><img src="https://velog.velcdn.com/images/peten_1105/post/ca672c46-c504-4115-b402-8769e5d8a142/image.png" alt=""></p>
<ul>
<li>어떠한 프로그램 내에서, 특히 프로세스 내에서 실행되는 흐름의 단위를 말함( 위키백과, 스레드 )</li>
<li>일반적으로 하나의 프로그램은 하나의 스레드를 가지고 있지만, 프로그램 환경에 따라서 둘 이상의 스레드를 동시에 실행할 수 도 있다. 이러한 실행 방식을 멀티 스레드라고 함</li>
<li>자바에서는 자바 프로그램을 만든 후 java 명령어를 사용하여 클래스를 실행하게 되면 자바 프로세스가 실행되고, main() 메소드가 수행되면서 하나의 스레드가 시작된다. 다른 스레드가 필요하다면 main() 메소드에서 스레드를 생성해주면 된다. ( 아무런 스레드를 생성하지 않아도 JVM을 관리하기 위한 여러 스레드가 존재한다. 예를 들면 자바의 GC관련 스레드. )</li>
<li>프로세스가 하나 시작하려면 많은 자원이 필요한데, 하나의 작업을 동시에 수행하려고 할 때 여러 개의 프로세스를 띄우는 것보다 하나의 프로세스 내에서 스레드를 여러 개 두는게 메모리를 적게 점유한다. (하나의 프로세스는 대략 32MB~64MB를 점유, 하나의 스레드는 대락 1MB 이내의 메모리를 점유)</li>
<li>자바에서 Thread를 생성하는 방법은 2가지가 있다. Runnable 인터페이스와 Thread 클래스이다.</li>
</ul>
<h3 id="runnable-인터페이스와-thread-클래스">Runnable 인터페이스와 Thread 클래스</h3>
<ul>
<li>둘 다 java.lang 패키지에 있음</li>
<li>Thread 클래스는 Runnable 인터페이스를 구현한 클래스이다.
Runnable 인터페이스에 선언되어 있는 메소드는 스레드가 사작되면 수행되는 메소드인 run() 메소드만 있다. 그에 반해 Thread 클래스는 매우 많은 생성자와 메소드(start, run, join 등등)를 제공한다. Runnable 인터페이스를 사용하면 더 많은 유연성을 얻을 수 있으며, 컴포지션을 통해 다른 목적으로 클래스를 확장하는 것이 가능합니다.</li>
</ul>
<pre><code>class RunnableSample implements Runnable {
    public void run() {
        System.out.println(&quot;This is RunnableSample&#39;s run() method.&quot; );
    }
}

class ThreadSample extends Thread{
    public void run() {
        System.out.println(&quot;This is ThreadSample&#39;s run() method.&quot;);
    }
}

public class RunThreads{
    public static void main(String[] args) {
        RunThreads threads = new RunThreads();
        threads.runBasic();
    }

    public void runBasic(){
        RunnableSample runnable = new RunnableSample();
        new Thread(runnable).start();

        ThreadSample thread = new ThreadSample();
        thread.start();
        System.out.println(&quot;RunThreads.runBasic() method is ended.&quot;);
    }
}</code></pre><p>출력 결과</p>
<blockquote>
<p>This is RunnableSample&#39;s run() method.
RunThreads.runBasic() method is ended.
This is ThreadSample&#39;s run() method.</p>
</blockquote>
<p>위의 프로그램을 실행하면 위와 같은 결과가 나오는데, 중요한 점은 스레드가 수행되는 우리가 구현하는 메소드는 run() 메소드라는 점과 스레드는 start()가 호출되어야만 시작한다는 점이다.</p>
<p>스레드 클래스가 다른 클래스를 확장할 필요가 있을 경우에는 Runnable 인터페이스를 구현하면 되며, 그렇지 않은 경우에는 Thread 클래스를 사용하는 것이 편하다. 
또한 출력결과가 항상 동일하게 나오지 않는데, 그 이유는 멀티 스레딩의 특성과 복잡성에 비롯된다. </p>
<h3 id="멀티-스레드의-동시성">멀티 스레드의 동시성</h3>
<p>자바 프로그램에서 멀티 스레드를 사용하면 각각의 스레드가 CPU 시간을 공유하면서 동시에 실행되는데, 이 과정에서 다음과 같은 요소들이 결과의 일관성에 영향을 줄 수 있다.
(1). <strong>스케줄링의 비결정성(Non-deterministic Scheduling)</strong> : 자바에서 스레드의 실행 순서와 타이밍은 운영체제의 스레드 스케줄러에 의해 결정된다. 스케줄러는 실행 가능한 스레드 중에서 선택을 하는데, 이는 다양한 요인에 의해 영향을 받으므로 매번 실행할 때마다 다른 결과를 낼 수 있다.
(2). <strong>공유 자원의 동시접근(Concurrent Access to Shared Resources)</strong> : 멀티 스레드 프로그램에서 여러 스레드가 동시에 같은 자원에 접근하려 할 때, 적절한 동기화 과정이 없이는 자원의 상태가 예측 불가능하게 변할 수 있다. 이로 인해 데이터 경쟁 조건(Race Condition)이 발생하고, 결과적으로 실행마다 다른 결과가 나올 수 있다.
(3). <strong>동기화 문제(Synchronization Issues)</strong> : 스레드 간의 동기화를 관리하는 것은 매우 중요하다. &#39;synchronized&#39; 블록, 락(lock), 세마포어(semaphore) 등을 사용해 자원에 대한 접근을 제어할 수 있지만, 동기화가 잘못 구현되면 데드락(deadlock)이나 라이브락(live lock) 같은 상황을 초래할 수 있고, 이 역시 실행 결과의 일관성을 해칠 수 있다.
(4). <strong>스레드 간의 상호작용(Inter-thread Interaction)</strong> : 스레드들이 서로를 기다리거나, 특정 스레드의 결과에 기반하여 다음 작업을 수행할 필요가 있는 경우, 이들 스레드의 실행 순서와 시간에 따라 결과가 달라질 수 있다.
(5). <strong>환경적 영향(Environmental Factors)</strong> : 실행 환경의 변화(CPU 사용률, 메모리 상태, 다른 프로세스의 영향.. 등등) 역시 스레드의 실행화 결과에 영향을 줄 수 있다.</p>
<p>이 와 같이 자바의 멀티스레딩 환경은 복잡하고 다양한 요소들에 의해서 영향을 받으므로, 프로그램을 실행할 때마다 결과가 일관되게 나오지 않는 것은 매우 흔한 현상이다. 이를 관리하고 예측 가능하게 만들기 위해 신중한 설계와 충분한 테스트가 요구된다.</p>
<p>스레드를 시작할 때 어떤 값을 전달하고 싶을 때는 아래 예제 소스와 같이 생성자에 값을 전달할 수 있도록 한다.</p>
<pre><code>public class CounterThread extends Thread {
    private static int counter = 0;
    public CounterThread (String name) {
        super(name);
    }

    public void run() {
       synchronized (CounterThread.class) {
            for( int i = 0; i &lt; 1000; i++ ){
                counter++;
            }
        }
    }

    public static void main(String[] args) {
        int number = 1;

        CounterThread[] threads = new CounterThread[10];

        for( int i = 0; i &lt; threads.length; i++ ){
            threads[i] = new CounterThread(&quot;Thread-&quot;+(i+1));
            threads[i].start();
        }

        for(int i = 0; i &lt; threads.length; i++ ){
            try {
                threads[i].join();
            } catch (InterruptedException e){
                e.printStackTrace();
            } 
        }

        System.out.println(&quot;Final counter value : &quot; + counter );
        System.out.println(&quot;CounterThread.main() method is ended.&quot;);
    }
}</code></pre><p>출력 결과</p>
<blockquote>
<p>Final counter value : 10000
CounterThread.main() method is ended.</p>
</blockquote>
<p>위 소스에는 CounterThread의 공유자원으로 counter 변수가 있고 이를 하나씩 증가하는 연산을 하는 스레드이다. 따라서 이 공유자원의 동기화를 위해서 증가연산자가 수행되는 곳을 synchronized 블록으로 감싸두었다.
그래서 마지막 값은 스레드의 개수만큼 증가한 counter가 출력된다. 여기서 synchronized 키워드를 빼고 실행하면, 실행할 때마다 counter value 값이 달라지게 된다. 이는 여러 스레드가 공유 자원인 counter 변수를 동시에 증가시키려고 시도하면서, 데이터 경쟁을 보여준다. 그리고 join 메소드가 있는데 이 메소드는 각각의 스레드가 종료될 때까지 기다리는 메소드이다.</p>
<h3 id="daemon-thread">Daemon Thread</h3>
<p>데몬 스레드는 Thread클래스의 인스턴스에 대해 setDaemon(true)메소드를 호출함으로써 해당 스레드를 데몬 스레드로 설정할 수 있다. 프로그램의 보조적인 역할을 수행하며, 스레드의 작업을 돕는 배경 스레드로 활용된다.</p>
<pre><code>public class DaemonThread extends Thread {
    public void run() {
        while(true){
            for( int i = 0; i &lt; 50; i++) {
                System.out.println(&quot;[Daemon] counter : &quot; + i );
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        DaemonThread thread = new DaemonThread();
        thread.setDaemon(true);
        thread.start();

        DummyThread dummyThread = new DummyThread();
        dummyThread.start();

        try {
            dummyThread.join();
        } catch (InterruptedException e){
            e.printStackTrace();
        }

        System.out.println(&quot;DaemonThread.main() method is ended.&quot;);
    }
}

class DummyThread extends Thread {
    public void run(){
        for( int i = 0; i &lt; 3; i++) {
            System.out.println(&quot;[Dummy] counter : &quot; + i );
            i++;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}</code></pre><p>출력 결과</p>
<blockquote>
<p>[Dummy] counter : 0
[Daemon] counter : 0
[Dummy] counter : 2
[Daemon] counter : 1
[Daemon] counter : 2
DaemonThread.main() method is ended.</p>
</blockquote>
<p>출력 결과를 보면 DummyThread가 0부터 3이될 때까지 1초간격으로 counter를 출력하고 있고, DaemonThread는 무한하게 1초간격으로 counter를 출력하는 스레드이다. 여기서 DaemonThread는 setDaemon이 true로 설정되어있으므로, DummyThread가 종료되게 되면 해당 프로세스가 종료되면서 DaemonThread 또한 종료되게된다.</p>
<p>이러한 데몬 스레드는 주로 프로그램의 보조적인 역할을 수행하며, 주 스레드의 작업을 돕는 배경 스레드로 사용된다. 데몬 스레드의 주요 특징은 프로그램이 종료될 때 데몬 스레드가 실행 중이라도 자바 런타임이 프로그램의 종료를 막지 않는다는 점이다. 즉, 주 스레드(데몬 스레드가 아닌 스레드)가 모두 종료되면 데몬 스레드는 강제로 종료될 수 있다. 이는 데몬 스레드가 주로 프로그램의 생명 주기에 종속적인 보조적인 작업을 수행하기 때문이다.</p>
<p>백그라운드에서 지속적으로 실행되어야 하는 작업에 주로 사용되는데, 가비지 컬렉션, 자동 저장, 세션 모니터링 등의 작업이 데몬 스레드로 실행될 수 있다. 이러한 스레드들은 주요 비즈니스의 로직을 방해하지 않으면서도 필요한 지원 작업을 계속 수행할 수 있다.</p>
<p>데몬스레드를 사용할 때는 스레드가 강제 종료될 수 있다는 점을 명시해야한다. 따라서 중요한 작업을 처리하거나 데이터의 일관성을 유지해야하는 작업에는 사용하지 않는 것이 좋다.</p>
<h3 id="executorservice--volatile">ExecutorService &amp; volatile</h3>
<p>그리고 추가적으로 알아야할 ExecutorService와 volatile 에 대해서 아래에 간단하게 정리한다.</p>
<p>ExecutorService는 스레드를 더 효율적으로 관리할 수 있는 고수준 API를 제공한다. 이 서비스를 사용하면 스레드의 생성과 생명 주기를 수동으로 관리하는 복잡성을 줄일 수 있다. 
ExecutorService는 스레드 풀을 사용하여 스레드를 재 사용함으로써 시스템 리소스의 낭비를 줄이고, 작업 큐를 통해 작업을 효율적으로 관리할 수 있다.</p>
<p>volatile 키워드는 변수를 메인 메모리에 저장하도록 하여, 하나의 스레드에 의해 변경된 값이 다른 스레드에게 바로 보이도록 한다. 이는 메모리 가시성을 보장하며, 스레드 간의 변수 값의 일관성을 유지하는데 사용된다. volatile은 경량 동기화 옵션으로서, 값의 단순한 읽기 및 쓰기 작업에서 사용될 때 적합하다. 하지만 복잡한 상태 또는 여러 변수의 동기화가 필요한 경우에는 synchronized를 사용해야 한다.</p>
<p>이처럼 자바에서 스레드를 이용하기 위한 간단한 예제와 설명들을 알아봤는데, 이 부분에 대한 운영체제 내용도 공부해야겠다. 
회사에서 C로 개발할 때는 Lock과 세마포어를 사용해서 공유자원에 대한 접근을 제한하는 매커니즘을 사용해서 멀티스레딩 환경을 개발하지만, JAVA에서는 synchronized 블럭과 키워드가 있는게 다른 점인거 같다.
물론 기본적으로 깔리는 베이스인 컴퓨터구조와 운영체제와 같은 이론은 그대로겠지만서도..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] Generic]]></title>
            <link>https://velog.io/@peten_1105/JAVA-Generic</link>
            <guid>https://velog.io/@peten_1105/JAVA-Generic</guid>
            <pubDate>Tue, 16 Apr 2024 22:31:40 GMT</pubDate>
            <description><![CDATA[<h2 id="제너릭generic">제너릭(Generic)</h2>
<p>자바에서 제너릭은 코드의 유연성과 타입 안전성을 향상시키는 중요한 기능이다. 제너릭을 사용하면 클래스, 인터페이스, 메소드를 다양한 타입의 객체들과 함께 사용할 수 있다. 이러한 특성은 코드 재사용성을 증가시키고, 컴파일 시간에 타입 체크를 통해 안정성을 높인다.</p>
<p>제너릭은 클래스나 메소드를 정의할 때 타입(Type)을 파라미터로 받을 수 있게 한다. 이를 통해 단 하나의 코드라인으로 다양한 타입의 객체들을 처리할 수 있는 유연성을 제공한다. 자바의 컬렉션 프레임워크에서 제너릭은 특히 유용하게 사용되며, &quot;List&quot;, &quot;Map&quot;, &quot;Set&quot;과 같은 인터페이스에서 제너릭을 통해 다양한 타입을 저장하고 처리할 수 있다.</p>
<h3 id="제너릭을-사용하는-이유">제너릭을 사용하는 이유</h3>
<ol>
<li>타입 안정성 : 제너릭을 사용하면 컴파일 시점에 타입 체크를 수행하여, 잘못된 타입이 사용되는 것을 방지할 수 있다.</li>
<li>타입 캐스팅 제거 : 객체를 추출할 때 타입 캐스팅을 할 필요가 없어 코드가 간결해지고, 실행시간이 단축된다.</li>
<li>재사용성과 추상화 향상 : 하나의 코드로 다양한 타입의 객체들을 처리할 수 있기 때문에 코드의 재사용성이 향상된다.</li>
</ol>
<h3 id="제너릭-사용-예제">제너릭 사용 예제</h3>
<h4 id="1-제너릭을-사용한-제너릭-클래스">1. 제너릭을 사용한 제너릭 클래스</h4>
<pre><code>class Box&lt;T&gt; {
    private T t; // T stands for &quot;Type&quot;

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }

}

public class Main {

    public static void main(String[] args) {
        Box&lt;Integer&gt; integerBox = new Box&lt;&gt;();
        integerBox.set(10);
        System.out.println(&quot;Integer Value: &quot; + integerBox.get());

        Box&lt;String&gt; stringBox = new Box&lt;&gt;();
        stringBox.set(&quot;Hello World&quot;);
        System.out.println(&quot;String Value: &quot; + stringBox.get());
    }
}</code></pre><p>출력 결과
Integer Value: 10
String Value: Hello World</p>
<p>이 예제에서 Box 클래스는 타입 파라미터 T를 사용하여 정의된다. 이 클래스는 정수 또는 문자열 등 어떤 타입의 객체도 저장하고 반환할 수 있다.</p>
<h4 id="2-제너릭-메소드">2. 제너릭 메소드</h4>
<pre><code>public class Util {
    public static &lt;T&gt; void printArray(T[] array) {
        for (T element : array) {
            System.out.println(element);
        }
    }

    public static void main(String[] args) {
        Integer[] intArray = {1, 2, 3, 4, 5};
        String[] stringArray = {&quot;Hello&quot;, &quot;World&quot;, &quot;Java&quot;, &quot;Generic&quot;};

        System.out.println(&quot;Integer Array:&quot;);
        printArray(intArray);

        System.out.println(&quot;String Array:&quot;);
        printArray(stringArray);
    }
}</code></pre><p>출력 결과
Integer Array:
1
2
3
4
5
String Array:
Hello
World
Java
Generic</p>
<p>이 예제에서 printArray 메소드는 제너릭 타입 T를 사용하여 어떤 배열의 요소든 출력할 수 있다. 이는 메소드 하나로 다양한 타입의 배열을 처리할 수 있음을 보여준다.</p>
<p>자바의 제너릭 기능은 프로그램의 안정성을 높이고 코드의 재사용성을 향상시키는 데 도움을 준다. 제너릭을 통해 개발자는 보다 타입 안정하고 유지보수가 용이한 코드를 작성할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] Lombok]]></title>
            <link>https://velog.io/@peten_1105/JAVA-Lombok</link>
            <guid>https://velog.io/@peten_1105/JAVA-Lombok</guid>
            <pubDate>Tue, 16 Apr 2024 15:14:02 GMT</pubDate>
            <description><![CDATA[<h2 id="lombok">Lombok</h2>
<p>getter, setter, 생성자, toString(), equals()와 hashCode() 메소드 같은 표준 자바 코드는 필수적이지만, 매번 작성하기는 번거롭다. 이런 문제를 해결하기 위해, Lombok 라이브러리는 자바 개발을 단순화하고, 보다 깔끔한 코드로 유지할 수 있도록 돕는 다양한 애노테이션을 제공한다.</p>
<p>이 애노테이션은 자바 개발자가 반복적인 코드를 줄이고, 가독성과 유지보수성을 향상시킬 수 있도록 설계된 도구이다. 아래는 Lombok에서 제공하는 몇 가지 중요한 애노테이션이다.</p>
<ol>
<li>@Getter / @Setter</li>
</ol>
<ul>
<li>자동으로 필드에 대한 getter와 setter 메소드를 생성함</li>
<li>클래스 또는 필드 레벨에 적용할 수 있음</li>
</ul>
<pre><code>import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Employee {
    private String name;
    private int age;
}</code></pre><ol start="2">
<li>@ToString</li>
</ol>
<ul>
<li>toString 메소드를 자동으로 생성함</li>
<li>출력형식은 클래스 이름과 각 필드의 이름 및 값이 포함된 문자열임<pre><code>import lombok.ToString;
</code></pre></li>
</ul>
<p>@ToString
public class Employee {
    private String name;
    private int age;
}</p>
<pre><code>
3. @EqualsAndHashCode
- equals()와 hashCode() 메소드를 자동으로 생성함
- 객체의 동등성 비교와 해시 기반의 컬렉션에 객체를 사용하기 위해 필수적임</code></pre><p>import lombok.EqualsAndHashCode;</p>
<p>@EqualsAndHashCode
public class Employee {
    private String name;
    private int age;
}</p>
<pre><code>
4. @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor
- 매개변수가 없는 생성자, 필수 필드(@NonNull필드)만 포함하는 생성자, 모든 필드를 매개변수로 갖는 생성자를 생성함</code></pre><p>import lombok.*;</p>
<p>@NoArgsConstructor
@RequiredArgsConstructor
@AllArgsConstructor
public class Employee {
    @NonNull private String name;
    private int age;
}</p>
<pre><code>
5. @Data
- 이 애노테이션은 @Getter, @Setter, @RequiredArgsConstructor, @ToString, @EqualsAndHashCode를 한 번에 적용하는 애노테이션.
- DTO(Data Transfer Object)와 같은 간단한 모델 객체에 매우 유용</code></pre><p>import lombok.Data;</p>
<p>@Data
public class Employee {
    private String name;
    private int age;
}</p>
<pre><code>

장점
1. 코드 간소화와 가독성 향상
- Lombok은 반복적인 코드 작성을 피하게 함으로써, 클래스의 가독성을 향상시킨다. 예를 들어 getter, setter, toString(), equals(), hashCode() 메소드등을 자동으로 생성하여 코드의 양을 줄일 수 있다.
2. 개발 시간 절약
- 반복적인 메소드를 수동으로 작성하는 데 소요되는 시간을 줄여주고, 이를 통해 개발자는 핵심 비즈니스 로직에 더 많은 시간을 할애할 수 있다.
3. 오류 감소
- 수동으로 코드를 작성할 때 발생할 수 있는 실수나 오류를 줄여준다. 예를 들어 equals()와 hashCode() 메소드를 직접 작성할 때 종종 발생하는 실수를 방지할 수  있다.
4. 유지 보수성 향상
- 클래스의 필드가 변경되거나 추가될 때 자동으로 생성된 메소드들이 업데이트되므로, 유지 보수 시간이 감소한다.

단점
1. 컴파일 의존성
- Lombok은 컴파일 타임에 코드를 조작한다. 이는 런타임 시 예상하지 못한 문제를 발생시킬 수 있으며, 디버깅을 어렵게 만들 수 있음
2. 툴과의 호환성 문제
- 모든 IDE나 빌드 툴에서 Lombok을 지원하는 것이 아니라서 지원하지 않는 경우에는 IDE에 플러그인 설치가 필요하며, 때로는 호환성이 되지 않는 문제가 발생할 수 있음
3. 학습 곡선
- 새로운 개발자나 lombok에 익숙하지 않는 개발자가 프로젝트에 참여할 경우, 코드의 자동 생성된 부분을 이해하고 디버깅하는 데 어려움을 겪을 수 있음
4. API 추상화
- Lombok은 코드 레벨에서 많은 것들을 추상화하고 숨김. 이는 코드의 직접적인 수정없이 자동으로 많은 것들이 처리되는 것을 의미하지만, 내부적으로 무슨 일이 일어나는지 이해하지 못할 수 있음


Lombok 은 자바 프로젝트에서 코드를 간소화하고 개발 효율성을 향상시키는 매우 유용한 도구이다. 이를 도입하기 전에 해당 프로젝트의 요구 사항과 환경을 고려하여 장담점을 충분히 평가해야한다. 팀원 간의 충분한 소통과 교육이 수반되어야 하며, 모든 개발자가 Lombok의 작동 방식과 그로 인한 코드의 변화를 이해할 수 있도록 해야 한다. Lombok의 사용이 적합한지 결정하기 전에 이러한 요소들을 신중하게 고려하는 것이 중요하다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] String에서의 equals(), compareTo() 차이]]></title>
            <link>https://velog.io/@peten_1105/JAVA-String%EC%97%90%EC%84%9C%EC%9D%98-equals-compareTo-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@peten_1105/JAVA-String%EC%97%90%EC%84%9C%EC%9D%98-equals-compareTo-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Tue, 16 Apr 2024 14:52:54 GMT</pubDate>
            <description><![CDATA[<p>String 클래스의 equals()와 compareTo() 메소드의 차이를 알아보자.
이 두 메소드는 비슷한 기능을 수행하는 것 처럼 보일 수 있지만, 사용 목적과 동작 방식에 있어서 중요한 차이점이 있다.</p>
<h3 id="1-equals-메소드">1. equals() 메소드</h3>
<p>&#39;Object&#39; 클래스에서 상속받은 메소드로, 두 객체의 동등성을 비교한다. String 클래스에서 이 메서도는 두 문자열의 내용이 정확히 같은지 비교하여, 같다면 &#39;true&#39;, 다르다면 &#39;false&#39;를 반환한다.
equals()는 주로 두 문자열이 글자와 순서까지 완전히 동일한지 확인할 때 사용된다.</p>
<pre><code>public class EqualsExample {
    public static void main(String[] args) {
        String s1 = &quot;hello&quot;;
        String s2 = &quot;hello&quot;;
        String s3 = &quot;HELLO&quot;;

        System.out.println(s1.equals(s2)); 
        System.out.println(s1.equals(s3));
    }
}</code></pre><p>출력 결과
true
false</p>
<p>위 예제에서 s1과 s2는 내용이 같으므로 true를 반환하고, s1과 s3는 대소문자가 다르므로 false를 반환한다.</p>
<h3 id="2-compareto-메소드">2. compareTo() 메소드</h3>
<p>compareTo() 메소드는 Comparable 인터페이스의 일부로 정의되어 있으며, 두 문자열을 사전순으로 비교한다. 이 메소드는 문자열이 사전순으로 동일한지, 앞서는지, 또는 뒤쳐지는지를 나타내는 정수를 반환한다. 반환 값은 다음과 같다.</p>
<ul>
<li>0 : 두 문자열이 사전순으로 같은 경우</li>
<li>양의 정수 : 호출 객체가 매개변수로 전달된 객체보다 사전 순으로 뒤에 올 경우</li>
<li>음의 정소 : 호출 객체가 매개변수로 전달된 객체보다 사전 순으로 앞에 올 경우</li>
</ul>
<pre><code>public class CompareToExample {
    public static void main(String[] args) {
        String s1 = &quot;apple&quot;;
        String s2 = &quot;banana&quot;;
        String s3 = &quot;apple&quot;;

        System.out.println(s1.compareTo(s2));
        System.out.println(s1.compareTo(s3));
        System.out.println(s2.compareTo(s1));
    }
}</code></pre><p>출력 결과
-1
0
1</p>
<p>compareTo() 메소드는 사적적으로 문자열을 비교할 때 문자간의 차이를 반환한다. 그 결과는 단순히 -1, 0, 1로 제한되지 않고, 실제 유니코드 값 차이를 반영할 수 있다. 예를 들어 문자열 내의 특정 문자가 다른 문자열의 해당 위치에 있는 문자와 유니코드 값에서 차이가 나는 경우, 그 차이는 compareTo() 메소드의 반환 값에 직접적으로 영향을 주게 된다.</p>
<p>아래 예제는 compareTo() 메소드가 -2, 2를 반환하는 경우를 보여준다.</p>
<pre><code>public class CompareToExample {
    public static void main(String[] args) {
        String str1 = &quot;abc&quot;;
        String str2 = &quot;abd&quot;;
        String str3 = &quot;abb&quot;;

        // str1 vs str2: &#39;c&#39; (99 in ASCII) vs &#39;d&#39; (100 in ASCII)
        System.out.println(str1.compareTo(str2));  // Output: -1 (&#39;c&#39;와 &#39;d&#39;의 차이)

        // str2 vs str1: &#39;d&#39; (100 in ASCII) vs &#39;c&#39; (99 in ASCII)
        System.out.println(str2.compareTo(str1));  // Output: 1 (&#39;d&#39;와 &#39;c&#39;의 차이)

        // ASCII 값 차이가 2인 경우의 예제
        String str4 = &quot;axe&quot;;
        String str5 = &quot;aze&quot;;

        // str4 vs str5: &#39;x&#39; (120 in ASCII) vs &#39;z&#39; (122 in ASCII)
        System.out.println(str4.compareTo(str5));  // Output: -2 (&#39;x&#39;와 &#39;z&#39;의 차이)

        // str5 vs str4: &#39;z&#39; (122 in ASCII) vs &#39;x&#39; (120 in ASCII)
        System.out.println(str5.compareTo(str4));  // Output: 2 (&#39;z&#39;와 &#39;x&#39;의 차이)
    }
}</code></pre><p>출력 결과
-1
1
-2
2</p>
<p>이 예제에서는 두 문자열의 각 문자를 비교하여 그 차이를 출력한다. str4와 str5를 비교할 때, 첫 번째 두 문자(&#39;a&#39;와 &#39;a&#39;)는 동일하고, 세번째 문자에서 &#39;x&#39;와 &#39;z&#39;사이에 유니코드 차이가 2만큼 나타낸다. 이 차이는 compareTo() 메소드의 결과로 직접 반영된다.</p>
<p>equals()와 compareTo()는 자바에서 문자열을 비교하는데 사용되지만, 그 목적과 구현이 다르다. equals()는 문자열의 절대적인 동등성을 확인하는데 사용하고, 결과는 Boolean 값이고, compareTo() 는 문자열을 사전순으로 정렬하는데 유용하며, 문자열 간의 상대적 순서를 나타내는 정수 값을 반환한다. 이 두 메소드의 올바른 이해와 사용은 효과적인 문자열 처리와 데이터 구조 운용에 중요하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] 익명 클래스]]></title>
            <link>https://velog.io/@peten_1105/JAVA-%EC%9D%B5%EB%AA%85-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@peten_1105/JAVA-%EC%9D%B5%EB%AA%85-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Tue, 16 Apr 2024 14:33:39 GMT</pubDate>
            <description><![CDATA[<h2 id="익명-클래스">익명 클래스</h2>
<p>자바에서 익명 클래스는 이름없이 선언되고 인스턴스화되는 클래스로, 일반적으로 단일 인스턴스가 필요한 경우에 한정해 사용된다. 이러한 특성 때문에, 익명 클래스는 주로 인터페이스의 구현이나 추상 클래스의 확장에 사용되며, 콜백메서드, 이벤트 리스너 설정, 일회성 작업의 실행 등 다양한 목적으로 활용된다.</p>
<h3 id="1-인터페이스-구현을-위한-익명-클래스">1. 인터페이스 구현을 위한 익명 클래스</h3>
<p>익명 클래스는 인터페이스를 구현하는 데 가장 흔히 사용된다. 이 경우, 클래스 명시 없이 바로 인터페이스 이름을 사용하여 구현할 수 있다. 예를 들어, 자바 GUI 프로그래밍에서 버튼 클릭 이벤트 리스너를 설정할 때 주로 익명 클래스가 사용되고 있다.</p>
<pre><code>import javax.swing.*;
import java.awt.event.*;

public class ButtonExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame(&quot;Button Example&quot;);
        JButton button = new JButton(&quot;Click Me!&quot;);

        // 익명 클래스를 사용하여 ActionListener 인터페이스 구현
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println(&quot;Button was clicked!&quot;);
            }
        });

        frame.add(button);
        frame.setSize(300, 200);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}</code></pre><p>출력 결과
<img src="https://velog.velcdn.com/images/peten_1105/post/36e9efb2-446d-46c9-b79e-f3bdede628ca/image.png" alt=""></p>
<p>위의 예제에서 &#39;ActionListener&#39;는 버튼 클릭과 같은 액션 이벤트를 처리하기 위한 인터페이스이다. 익명 클래스를 사용하여 actionPerformed 메서드를 직접 구현함으로써, 추가적인 외부 클래스 파일 없이 이벤트 처리 로직을 간결하게 유지할 수 있게 되었다.</p>
<h3 id="2-추상-클래스-확장을-위한-익명-클래스">2. 추상 클래스 확장을 위한 익명 클래스</h3>
<p>익명 클래스 또한 추상 클래스를 확장하여 그 추상 메서드들을 구현하는 데 사용될 수 있다. 이를 통해 복잡한 상속 구조 없이도 필요한 메서드를 빠르게 구현하고 인스턴스화할 수 있다. 아래는 추상 클래스 &#39;AbstractButton&#39;의 확장의 예제 소스이다.</p>
<pre><code>abstract class AbstractButton {
    public abstract void click();
}

public class TestButton {
    public static void main(String[] args) {
        AbstractButton btn = new AbstractButton() {
            @Override
            public void click() {
                System.out.println(&quot;Button clicked&quot;);
            }
        };

        btn.click();
    }
}</code></pre><p>출력 결과
Button clicked</p>
<p>이 예제에서는 &#39;AbstractButton&#39;이라는 추상 클래스를 익명으로 확장하여, &#39;click&#39; 메서드를 구현하고 있다. 이 방법을 사용하면, 특정 메서드의 동작만을 빠르게 정의하고 테스트 할 수 있다.</p>
<h3 id="3-익명-클래스를-사용한-즉석에서의-구현">3. 익명 클래스를 사용한 즉석에서의 구현</h3>
<p>익명 클래스는 또한 즉석에서 필요한 기능을 구현하는 데 사용될 수 있으며, 이를 통해 코드를 간소화하고, 로컬 변수와의 상호 작용을 통해 함수적 스타일의 프로그래밍을 할 수 있다. 예를 들어, 정렬 기능을 사용할 때 커스텀 비교 로직을 구현하는 것이 일반적이다.</p>
<pre><code>import java.util.*;

public class SortExample {
    public static void main(String[] args) {
        List&lt;String&gt; names = Arrays.asList(&quot;Steve&quot;, &quot;Jessica&quot;, &quot;Tom&quot;, &quot;Jerry&quot;);

        Collections.sort(names, new Comparator&lt;String&gt;() {
            public int compare(String s1, String s2) {
                return s1.compareTo(s2);
            }
        });

        System.out.println(&quot;Sorted names: &quot; + names);
    }
}</code></pre><p>출력 결과
Sorted names: [Jerry, Jessica, Steve, Tom]</p>
<p>이 예제에서는 &#39;Comparator&#39; 인터페이스를 익명 클래스로 구현하여 문자열 리스트를 알파벳 순으로 정렬한다. 이 방법은 특히 자바에서 람다 표현식이 도입되기 전에 널리 사용되어져 왔다.</p>
<p>익명 클래스는 코드를 더 간결하고 직관적으로 만들고, 특정 인터페이스나 추상 클래스를 즉각적으로 구현하는 방법을 제공하기 때문에 코드의 가독성을 높이고, 유지 보수를 용이하게 하며, 설계상의 유연성을 증가시킬 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] 내부 클래스]]></title>
            <link>https://velog.io/@peten_1105/JAVA-%EB%82%B4%EB%B6%80-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@peten_1105/JAVA-%EB%82%B4%EB%B6%80-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Tue, 16 Apr 2024 14:17:19 GMT</pubDate>
            <description><![CDATA[<h2 id="내부-클래스">내부 클래스</h2>
<p>내부 클래스는 그 이름에서 알 수 있듯이, 하나의 클래스 안에 또 다른 클래스가 정의되어 있는 형태를 말한다. 이 구조는 특정 클래스 내에서만 사용되는 보조 클래스를 그 범위 내에서만 유지하여 외부에는 노출시키지 않는 캡슐화를 강화할 수 있다. 내부 클래스는 주로 외부 클래스와 강하게 연결된 작업을 수행하거나, 외부 클래스의 코드를 간결하게 만들기 위해 사용된다.</p>
<p>이렇게 내부 클래스를 사용함으로써, 개발자는 더욱 체계적이고 구조화된 코드를 작성할 수 있다. 코드의 재사용성과 유지보수성이 향상되며, 복잡한 문제를 좀 더 단순하고 직관적으로 해결할 수 있는 방법을 제공한다. 또한, 이벤트 드리븐 프로그래밍에서는 콜백 함수나 이벤트 핸들러를 내부 클래스를 통해 구현함으로써, 이벤트 처리 로직을 효과적으로 캡슐화할 수 있다.</p>
<h3 id="1-멤버-내부-클래스member-inner-class">1. 멤버 내부 클래스(Member Inner Class)</h3>
<ul>
<li>외부 클래스의 인스턴스 멤버로 선언된 클래스</li>
<li>외부 클래스의 인스턴스 변수에 접근할 수 있음</li>
<li>주로 외부 클래스의 기능을 보완하거나 확장하는 데 사용됨</li>
</ul>
<pre><code>public class OuterClass {
    private int outerField = 10;

    // Member Inner Class
    public class InnerClass {
        public void innerMethod() {
            System.out.println(&quot;Inner method with outerField value: &quot; + outerField);
        }
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        OuterClass.InnerClass inner = outer.new InnerClass();
        inner.innerMethod(); // Output: Inner method with outerField value: 10
    }
}</code></pre><p>출력 결과
Inner method with outerField value: 10</p>
<h3 id="2-정적-내부-클래스static-nested-class">2. 정적 내부 클래스(Static Nested Class)</h3>
<ul>
<li>&#39;static&#39;키워드로 선언된 클래스로, 외부 클래스의 인스턴스에 묶이지 않음</li>
<li>외부 클래스의 정적 멤버에만 접근할 수 있음</li>
<li>주로 외부 클래스와 관련된 보조 기능을 제공하는데 사용됨</li>
</ul>
<pre><code>public class OuterClass {
    private static int outerStaticField = 20;

    // Static Nested Class
    public static class StaticNestedClass {
        public void staticMethod() {
            System.out.println(&quot;Static method of StaticNestedClass with outerStaticField value: &quot; + outerStaticField);
        }
    }

    public static void main(String[] args) {
        OuterClass.StaticNestedClass nested = new OuterClass.StaticNestedClass();
        nested.staticMethod(); // Output: Static method of StaticNestedClass with outerStaticField value: 20
    }
}</code></pre><p>출력 결과
Static method of StaticNestedClass with outerStaticField value: 20</p>
<h3 id="3-지역-내부-클래스local-inner-class">3. 지역 내부 클래스(Local Inner Class)</h3>
<ul>
<li>메서드 내부에 선언된 클래스로, 해당 메서드 내에서만 유효함</li>
<li>주로 메서드 내부의 특정 로직을 캡슐화하고 재사용을 높이는 데 사용됨</li>
</ul>
<pre><code>public class OuterClass {
    public void outerMethod() {
        int localVariable = 30;

        // Method with Local Inner Class
        class LocalInnerClass {
            public void localMethod() {
                System.out.println(&quot;Local method of LocalInnerClass with localVariable value: &quot; + localVariable);
            }
        }

        LocalInnerClass inner = new LocalInnerClass();
        inner.localMethod(); // Output: Local method of LocalInnerClass with localVariable value: 30
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.outerMethod();
    }
}</code></pre><p>출력 결과
Local method of LocalInnerClass with localVariable value: 30</p>
<h3 id="4-익명-내부-클래스anonymous-inner-class">4. 익명 내부 클래스(Anonymous Inner Class)</h3>
<ul>
<li>클래스 이름 없이 정의된 클래스로, 인터페이스나 추상 클래스의 구현을 인라인으로 제공함</li>
<li>주로 이벤트 핸들러나 콜백함수를 구현하는 데 사용됨</li>
</ul>
<pre><code>public class OuterClass {
    public void anonymousMethod() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(&quot;Anonymous inner class&#39;s run method&quot;);
            }
        };
        new Thread(runnable).start();
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.anonymousMethod(); // Output: Anonymous inner class&#39;s run method
    }
}</code></pre><p>출력 결과
Anonymous inner class&#39;s run method</p>
<p>내부 클래스는 주로 다음과 같은 곳에서 사용됨</p>
<ul>
<li>캡슐화(Encapsulation) : 외부 클래스의 복잡성을 줄이고 관련 기능을 하나로 그룹화함</li>
<li>코드 구조화(Code Structuring) : 관련 있는 코드를 논리적으로 그룹화하여 가독성을 향상시킴</li>
<li>콜백 및 이벤트 처리(Callback and Event Handling) : 인터페이스를 구현하거나 추상 클래스를 확장하여 이벤트 처리나 콜백함수를 구현함</li>
<li>테스트용 목 객체(Test Stub Objects) : 테스트 중에 모의 객체를 만들어 외부 의존성을 제거하고 테스트 가능한 코드를 작성함.</li>
</ul>
<p>위 에서 콜백 및 이벤트 처리에서 어떻게 사용되는지 예제 소스를 한번 보자.</p>
<pre><code>// Interface for event listeners
interface OnClickListener {
    void onClick();
}

public class Button {
    private OnClickListener onClickListener;

    // Method to register click event listener
    public void setOnClickListener(OnClickListener onClickListener) {
        this.onClickListener = onClickListener;
    }

    // Inner class representing click event handler
    public class ClickHandler {
        public void handleClick() {
            if (onClickListener != null) {
                onClickListener.onClick();
            }
        }
    }

    public void simulateClick() {
        ClickHandler clickHandler = new ClickHandler();
        clickHandler.handleClick();
    }

    public static void main(String[] args) {
        Button button = new Button();
        button.setOnClickListener(() -&gt; System.out.println(&quot;Button clicked&quot;));
        button.simulateClick(); // Output: Button clicked
    }
}</code></pre><p>출력 결과
Button clicked</p>
<p>이렇게 내부 클래스를 사용하여 ClickHandler 클래스를 구현하여 setOnClickListener를 구현한다.</p>
<p>내부 클래스는 Java 프로그래밍에서 코드의 구조와 디자인을 개선하는 데 중요한 역할을 한다. 각각의 내부 클래스 유형(멤버 내부 클래스, 정적 내부 클래스, 지역 내부 클래스, 그리고 익명 내부 클래스)은 그 특성에 따라 다양한 상황에서 유용하게 사용된다. 이들은 코드의 캡슐화를 강화하고, 관련 기능을 근접하게 위치시켜 프로젝트의 구조를 더욱 명확하게 만든다. 또한, 테스트 가능성을 향상시키고, 코드의 재사용성을 높이며, 복잡한 이벤트 처리나 콜백 구현을 단순화한다.</p>
<p>내부 클래스를 사용할 때는 각 클래스의 범위와 연관성을 명확히 정의하는 것이 중요하다. 외부 클래스의 데이터에 강하게 의존하는 기능이나, 특정 메서드 내에서만 사용되는 클래스는 내부 클래스로 구현하여 외부에서의 불필요한 접근을 제한함으로써 보안성을 높이고, 코드를 깔끔하게 유지할 수 있다. 또한, 익명 내부 클래스를 활용하여 간단한 인터페이스나 추상 클래스의 구현을 인라인으로 제공함으로써 코드의 직관성을 개선할 수 있다.</p>
<p>결국, 내부 클래스는 Java 개발자의 도구 상자에서 매우 강력한 도구라고 할 수 있다. 적절히 활용한다면, 소프트웨어의 설계를 더욱 견고하고 유지보수하기 쉽게 만들어 줄 것 이다. 따라서, 각 프로젝트의 요구 사항과 문제에 맞게 내부 클래스를 전략적으로 사용하여, 보다 효율적인 프로그래밍을 해야한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] Annotaion]]></title>
            <link>https://velog.io/@peten_1105/JAVA-Annotaion</link>
            <guid>https://velog.io/@peten_1105/JAVA-Annotaion</guid>
            <pubDate>Wed, 10 Apr 2024 04:18:14 GMT</pubDate>
            <description><![CDATA[<p>자바 어노테이션은 단순한 코드 보다 훨씬 더 많은 것을 제공한다. 어노테이션은 메타데이터를 통해 코드의 동작을 정의하고, 컴파일러와 개발 도구가 코드를 더 잘 이해할 수 있도록 돕는다. 이로 인해 코드의 가독성이 향상되고, 유지보수가 용이해지며, 반복적인 코드의 양을 줄일 수 있다. 또한, 개발자가 실수로 발생할 수 있는 오류를 미연에 방지할 수 있다.</p>
<h3 id="어노테이션의-기본">어노테이션의 기본</h3>
<p>어노테이션은 &#39;@&#39;심볼로 시작하며, 이를 통해 컴파일러에게 추가적인 정보를 제공하거나, 코드에 메타데이터를 부여한다. 자바에서는 여러 기본 제공 어노테이션이 있으며, 개발자는 사용자 정의 어노테이션도 생성할 수 있다.</p>
<ul>
<li>@Override : 메서드가 상위 클래스를 오버라이드함을 나타낸다.</li>
<li>@Deprecated : 메서드나 클래스가 더 이상 사용되지 않음을 나타내며, 사용하지 않도록 권장한다.</li>
<li>@SuppressWarnings : 특정 경고 메시지(예:deprecation, unchecked)를 억제하도록 컴파일러에 지시한다.</li>
</ul>
<h3 id="메타-어노테이션">메타 어노테이션</h3>
<p>메타 어노테이션은 어노테이션을 정의할 때 사용된다.</p>
<ul>
<li>@Target : 어노테이션이 적용될 수 있는 요소의 종류(예 : 메서드, 필드, 클래스 등)를 지정한다.</li>
<li>@Retention : 어노테이션이 어느 시점까지 유지될 것인지를 지정한다.(소스, 클래스, 런타임)</li>
<li>@Documented : 어노테이션 정보가 Javadoc 문서에 포함될 것인지를 나타낸다.</li>
<li>@Inherited : 어노테이션이 서브클래스에 상속될 것인지를 나타낸다.</li>
</ul>
<h3 id="사용자-정의-어노테이션-만들기">사용자 정의 어노테이션 만들기</h3>
<p>개발자는 특정 목적에 맞는 사용자 정의 어노테이션을 만들 수 있다. 사용자 정의 어노테이션은 &#39;@interface&#39;키워드를 사용하여 정의된다. 예를 들어, 테스트 프레임워크에서 특정 메서드를 테스트 메서드로 지정하려는 경우 사용자 정의 어노테이션을 만들 수 있다.</p>
<pre><code>package c.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)         // (1) 메소드에 사용될 어노테이션
@Retention(RetentionPolicy.RUNTIME) // (2) 런타임에 참조 가능
public @interface TestMethod {        // (3)
    public String description() default &quot;Default test method&quot;; // (4) 기본 설명
}</code></pre><p>(1) : @Target은 해당 어노테이션 사용 대상을 지정한다. 여기서는 ElementType.METHOD를 소괄호 안에 넣어줌으로써 이 어노테이션은 메소드에 사용될 수 있다고 지정한 것이다.
(2) : @Retention은 어노테이션 유지 정보를 지정하는데 사용한다. 소괄호 안에 RetentionPolicy.RUNTIME으로 지정하면 실행시에 이 어노테이션을 참조하게 된다.
(3) : 어노테이션 이름인 TestMethod 앞에는 @interface가 선언되어있다. 처음 보면 익숙하지 않겠지만, 클래스나 인터페이스를 선언할 때 처럼 @interface로 선언하면 @TestMethod 로 어노테이션이 사용가능해진다.
(4) : 어노테이션 선언 안에는 description()이라는 메소드가 있다. description()의 리턴 타입은 String이다. 이렇게 메소드처럼 어노테이션 안에 선언해놓으면, 이 어노테이션을 사용할 때 해당 항목에 대한 타입으로 값을 지정 가능하다. description() 를 보면 default라는 예약어를 쓴 뒤 문자열이 지정되어 있는 것을 볼 수 있다. default 예약어를 사용할 경우에는, default 뒤에 있는 값이 이 어노테이션을 사용할 때의 기본값이 된다.</p>
<p>위의 TestMethod 애노테이션을 사용하는 예는 아래와 같이 사용할 수 있다.</p>
<pre><code>public class ExampleTests {
    @TestMethod(description = &quot;This tests the addition method.&quot;)
    public void testAddition() {
        assert(1 + 1 == 2);
    }
}</code></pre><h3 id="어노테이션-활용">어노테이션 활용</h3>
<p>어노테이션은 리플렉션을 통해 런타임에 조회되며, API 메서드에 대한 문서 생성, 테스트 자동화 등 다양한 분야에서 활용될 수 있다. 예를 들어, 어노테이션을 사용하여 API 메서드의 매개변수와 반환 값에 대한 설명을 자동으로 문서화할 수 있다.</p>
<h3 id="어노테이션-프로세싱">어노테이션 프로세싱</h3>
<p>어노테이션 프로세싱(Annotation Processing)은 컴파일 타임에 어노테이션을 분석하고 처리하는 과정을 말한다. 이를 활용하면 코드 생성, 코드 검증 등 다양한 작업을 자동화 할 수 있다. 아래는 간단한 어노테이션 프로세서를 개발하고, 이를 활용하는 예제를 통해서 어노테이션 프로세싱을 설명한다.</p>
<p>메서드가 실행될 때 시간을 로그로 남기고 싶을 때, 다음과 같이 &quot;LogExecutionTime&quot; 어노테이션을 생성할 수 있다.</p>
<pre><code>import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {}</code></pre><p>어노테이션 프로세서를 생성하기 위해서는 AbstractProcessor 클래스를 상속받아야한다. 이 클래스에서는 process 메서드를 오버라이드하여 어노테이션이 붙은 요소들을 처리한다.</p>
<pre><code>import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.Processor;
import javax.tools.Diagnostic;

@SupportedAnnotationTypes(&quot;LogExecutionTime&quot;)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class TimeLoggingProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set&lt;? extends TypeElement&gt; annotations, RoundEnvironment roundEnv) {
        for (Element elem : roundEnv.getElementsAnnotatedWith(LogExecutionTime.class)) {
            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, &quot;Found method: &quot; + elem.getSimpleName());
        }
        return true; // No further processing of this annotation type
    }
}</code></pre><p>어노테이션 사용은 아래처럼 사용한다.</p>
<pre><code>public class TimeLoggingExample {
    @LogExecutionTime
    public void performTask() {
        // Task implementation
    }
}</code></pre><p>위의 예제를 컴파일할 때는 &quot;TimeLoggingProcessor&quot;를 포함시켜야한다. 대부분의 IDE나 빌드 시스템에서는 어노테이션 프로세서를 자동으로 인식하고 처리한다. 컴파일 중에 performTask 메서드를 찾아 로그 메시지를 출력한다.
이렇게 어노테이션 프로세싱을 통해 코드에 메타데이터를 제공하고, 이를 기반으로 추가적인 코드를 생성하거나 검증 작업을 자동화할 수 있다. 어노테이션 프로세서를 활용하면 코드의 유지보수성을 높이고, 반복 작업을 줄일 수 있는 강력한 도구가 될 수 있다.</p>
]]></description>
        </item>
    </channel>
</rss>