<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yonnyLog</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sun, 20 Nov 2022 14:55:15 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yonnyLog</title>
            <url>https://velog.velcdn.com/images/yonny_k/profile/29653cd1-a7d4-4caf-861d-f23bee06423b/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yonnyLog. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yonny_k" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Java] File I/O close() and flush()]]></title>
            <link>https://velog.io/@yonny_k/javacloseandflush</link>
            <guid>https://velog.io/@yonny_k/javacloseandflush</guid>
            <pubDate>Sun, 20 Nov 2022 14:55:15 GMT</pubDate>
            <description><![CDATA[<h1 id="✅-스트림-닫기를-잊지-마세요">✅ 스트림 닫기를 잊지 마세요!</h1>
<h2 id="close">close()</h2>
<p><code>close()</code>는 스트림을 닫는 메소드다. 스트림의 사용이 끝났다면 <code>반</code> <code>드</code> <code>시</code> 호출해야 한다. </p>
<p>앞에서 자바는 프로그램 종료 시 사용한 파일 스트림을 알아서 닫긴 한다고 적었지만...
절대 GC에 의존하지 말고 철저히 스트림을 닫는 것을 확실하게 수행해야 한다. 무엇보다도 자원의 누수를 방지하는 것은 프로그래머로써 당연히 고려해야 하는 사항이지만, 예기치 못한 에러를 마주할 수 있으므로 사전에 마음에 새겨 두자.</p>
<p>우선 <code>파일을 작성하는 경우</code>에는 반드시 스트림을 닫아 주어야 한다. 파일에 확실한 끝을 전달하지 않으면 에러가 발생할 수 있다. <code>파일을 읽어들이는 경우</code>에도 네트워크 메세지를 받는 등의 경우 문제가 발생할 수 있기 때문에 반드시 <code>close()</code>를 수행해 주도록 하자.
실제 서버에서 돌아가는 프로그램의 경우, 파일을 올린 후 바로 웹에서 확인하는 작업 등을 수행할 때 파일을 제대로 닫지 않으면 파일을 열 수 없어 문제가 발생한다... 이 때문에 폐를 끼친 경험이 있다. C부터 공부해 온 프로그래머라면 자존심을 걸고서라도 꼭 이런 사소한 실수는 방지할 수 있도록 하자...</p>
<blockquote>
<p>언제나 <code>close()</code>를 통해 스트림을 닫는 것을 반드시 습관화하도록 하자.</p>
</blockquote>
<p>&nbsp;</p>
<h2 id="flush">flush()</h2>
<blockquote>
<p>한 마디로 말하자면, close()만 잘 한다면 쓸 필요 없다.</p>
</blockquote>
<p>파일 출력을 수행할 때, 프로그램은 데이터를 버퍼에 우선 채운 다음 버퍼가 다 차면 파일에 작성하게 되어 있다.
flush()는 버퍼가 다 차지 않았더라도 파일에 데이터의 작성을 강제한다. 버퍼에 남은 데이터가 작성되지 않고 파일 작성이 종료되는 경우를 방지하기 위해 작성하는 메소드다.
하지만 close()를 호출하면 내부에서 버퍼에 남은 데이터를 flush한 다음 스트림을 닫게 된다. 때문에 close()를 잘 호출하고 있다면 굳이 스트림을 닫을 때 flush()와 close()를 같이 호출하지 않아도 된다.
또한 flush()에는 스트림을 닫는 기능은 없기 때문에 flush()를 close() 대신 호출하는 실수도 하지 않도록 유의하자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Repository]]></title>
            <link>https://velog.io/@yonny_k/springrepository</link>
            <guid>https://velog.io/@yonny_k/springrepository</guid>
            <pubDate>Sun, 30 Oct 2022 07:19:27 GMT</pubDate>
            <description><![CDATA[<h1 id="repository">Repository</h1>
<hr>
<p>데이터 처리를 위해 실제 DB와 연동되는 JPA Repository이다.
이는 Entity에 의해 생성된 DB의 table에 접근하는 메소드를 사용하기 위한 인터페이스이다.
아래 설명할 방법을 활용해 작성하면 Mybatis와 같은 별도의 SQL Mapper 없이도 CRUD를 수행할 수 있다.</p>
<pre><code class="language-java">// Repository 생성
public interface ExampleRepository extends JpaRepository&lt;Question, Integer&gt; {
    Example 
}

// 사용

    @Autowired
    private ExampleRepository exampleRepository;

    @Test
    void testJpa() {
        List&lt;Example&gt; all = this.exampleRepository.findAll();
        assertEquals(2, all.size());

        Example e = all.get(0);
        assertEquals(&quot;searchKeyword&quot;, e.getSubject());
    }</code></pre>
<p>Repository가 제공하는 메서드들을 이용하면 데이터 조회, 생성, 삭제 등의 CRUD 처리가 가능하다. 제공되는 메서드로는 findById, findBySubjectAndContent, findBySubjectLike 등 다양한 서치 메서드가 있으며 setSubject(), save(), delete() 등으로 등록, 수정, 삭제 처리가 가능하다. &gt;&gt;&gt; <em>Repository의 메소드명과 쿼리 생성 규칙에 대한 더 자세한 정보는 <a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation">Repository 쿼리 생성 공식 문서</a>를 참고하세요!</em></p>
<p>직접 쿼리를 추가하는 방법도 있다.</p>
<pre><code class="language-java">@Query(&quot;select &quot;
        + &quot;distinct q &quot;
        + &quot;from Question q &quot;
        ...
        + &quot;where &quot;
        + &quot;        q.subject like %:kw% &quot;
        ... )
Page&lt;Question&gt; findAllByKeyword(@Param(&quot;kw&quot;) String kw, Pageable pageable);</code></pre>
<h3 id="transactional">Transactional</h3>
<p><em><a href="https://velog.io/@yonny_k/Java-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC">지난 글</a>에서 트랜잭션과 예외처리에 대해 적어두었다!</em></p>
<hr>
<p>트랜잭션은 업무 처리의 최소 단위이다. 어떠한 트랜잭션의 수행 중 에러가 발생하면 거기서 변경 중 에러가 발생하면 냅다 거기서 멈추면 안 되고, 아예 처리 전의 상태로 돌아올 수 있도록 처리해야 한다.
한편 테스트 코드로 DB에 액세스하는 경우에 모든 쿼리를 수행하지 않았음에도 DB 세션이 종료되어 버리는 경우도 발생할 수 있다.
이런 경우 <code>@Transactional</code> 어노테이션을 사용하면 해당 메소드를 트랜잭션으로 인식하여 DB 처리를 비교적 안전하고 수월하게 진행할 수 있다.</p>
<p>&nbsp;</p>
<hr>
<p><em>이 글은 <a href="https://wikidocs.net/book/7601">점프 투 스프링부트</a>를 스터디한 기록입니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Service]]></title>
            <link>https://velog.io/@yonny_k/springservice</link>
            <guid>https://velog.io/@yonny_k/springservice</guid>
            <pubDate>Sun, 30 Oct 2022 07:19:20 GMT</pubDate>
            <description><![CDATA[<h1 id="service">Service</h1>
<hr>
<p>Service는 컨트롤러에서 리퀘스트를 받아 처리하기 위해 호출한다. 서비스 단에서는 받은 리퀘스트대로 DAO를 이용해 데이터를 적절히 가공하여 컨트롤러에게 다시 넘겨준다.</p>
<p>Service의 간단한 작성 예제를 살펴보자.</p>
<pre><code class="language-java">@RequiredArgsConstructor
@Service
public class QuestionService {

    private final ARepository aRepository;

    public List&lt;Question&gt; getList() {
        return this.questionRepository.findAll();
    }

    ...
}</code></pre>
<p>@Service 어노테이션 역시 @Controller 어노테이션과 같이 @Component 어노테이션의 연장으로 Bean에 별도로 등록하지 않아도 알아서 스캔하여 등록된다.</p>
<p>서비스는 비즈니스 로직들의 모듈화를 위해 필요하다. 서비스 대신 컨트롤러 단에 모든 비즈니스 로직을 작성할 경우, 중복되는 로직들을 전부 다시 작성해야 하는 문제가 발생할 수도 있으며 컨트롤러로부터 Repository에 직접 접근하여 데이터를 건드릴 수 있게 된다면 보안상 취약점이 발생하므로 바람직하지 않다. 또한 서비스는 DB에 Entity로 직접 접근하지 않고 DTO로 변환하여 접근하도록 함으로써 안전한 데이터 관리를 가능하게 한다.</p>
<p>&nbsp;</p>
<hr>
<p><em>이 글은 <a href="https://wikidocs.net/book/7601">점프 투 스프링부트</a>를 스터디한 기록입니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DI, IoC container]]></title>
            <link>https://velog.io/@yonny_k/DIIOC</link>
            <guid>https://velog.io/@yonny_k/DIIOC</guid>
            <pubDate>Thu, 20 Oct 2022 01:09:39 GMT</pubDate>
            <description><![CDATA[<h1 id="의존성-defendency">의존성 (Defendency)</h1>
<hr>
<p>의존성이란, 한 요소가 다른 요소에 의존해 작동하는 관계를 가리킨다. 여기서 요소는 클래스, 모듈 패키지, 라이브러리 등이 될 수 있다.</p>
<p>쉽게 말해, A 클래스가 B 클래스를 사용하고 있으면 의존성이 있다고 볼 수 있다.</p>
<p>아래와 같은 코드를 상정해 보자.</p>
<pre><code class="language-java">class A {
    new b = new B();
    ...
}

class B {
    ...
}</code></pre>
<p>클래스 B의 내용이 바뀐다면 클래스 A의 내용 역시 필연적으로 바뀌어야 한다. 즉, B를 수정하면 A 역시 수정해야 한다. 변경사항이 전파되어 의존하는 다른 요소들에 영향을 끼칠 수 있다는 것이다.</p>
<p>&amp;nbsp</p>
<h1 id="의존성-주입-di-defendency-injection">의존성 주입 (DI, Defendency Injection)</h1>
<hr>
<p>그렇다면 의존성 주입이란 무엇일까?
의존성 주입, DI는 <code>의존성이 있는 객체를 넣어준다</code>라는 뜻이다.
즉, A가 B를 쓰고 있을 때, <em>의존하고 있을 때</em>, A에서 B를 직접 생성해서 쓰는게 아니라 _외부에서 B의 인스턴스를 생성해서 주입_한다는 뜻이다.</p>
<p>&nbsp;</p>
<p>기존에는,
<code>[class A] -&gt; [class B]</code>
이런 형태로 직접적으로 의존했다면,</p>
<p><code>[class A] -&gt; [매개체] &lt;- [class B]</code>
와 같은 형태로 매개체를 통하도록 한다.</p>
<p>&nbsp;</p>
<p>이 매개체는 <code>IoC Container</code>라고 불린다. IoC란, <code>Inversion of Control</code>, 즉 제어의 역전을 가리킨다.</p>
<p>제어의 역전이란 무엇일까? 그리고 이 IoC 컨테이너는 어떻게 의존성을 주입해주는 걸까?</p>
<h2 id="ioc">IoC</h2>
<p>제어가 역전되다. 제어권이 역전되다. 즉, <code>내가 제어하던 의존성</code>에 대한 권한이 <code>역전</code>된다는 것이다.
기존에는 의존성을 모두 제어했다면 IoC의 발생으로 제어권이 역전되어 직접 제어하지 않게 된다.
개발자가 제어하는 것이 아니라, 제어권을 빼앗기는 것이다.</p>
<p>위에서 말한 <code>[매개체]</code>는 이 IoC를 일으켜 제어권을 빼앗고 대신 의존성을 관리하고 인스턴스를 생성하여 주입해주고, 메모리를 해제해주는 IoC 컨테이너를 의미한다.</p>
<p>즉 DI, 의존성 주입이란,
IoC 컨테이너에 필요한 모든 모듈들을 넣고 필요할 때 IoC 컨테이너가 의존성을 주입할 수 있도록 하는 것이다.</p>
<hr>
<p>&nbsp;</p>
<h2 id="왜">왜?</h2>
<p>IoC 컨테이너를 두어 DI를 하는 이유는 무엇일까?</p>
<p>우선, <code>의존성이 줄어든다</code>. 상기했듯 의존성이 있다면 하나의 코드를 수정했을 때 그 영향이 전파되어 다른 코드들을 수정해야 하는 문제가 발생한다. 어떠한 모듈을 사용처에서 직접 생성하지 않고 IoC 컨테이너를 통하게 되면 이러한 의존성이 줄어들게 되고 코드 간 결합이 느슨해진다.</p>
<p>의존성이 줄어든다는 것은 곧 <code>변화에 강해진다</code>는 것이다. 의존하고 있는 모듈의 라이프사이클에 관계가 없어지니까.</p>
<p>따라서 코드의 <code>재사용성이 좋아지고</code>, <code>유지보수가 용이해진다</code>는 장점까지 따라오게 된다.</p>
<p>모듈의 생성, 삭제를 직접 하지 않으니까 코드 양도 감소하고, 원하는 객체의 상태를 직접 세팅해서 주입할 수 있게 되므로 <code>테스트도 용이해진다</code>.</p>
<p>&nbsp;</p>
<p>사실, 말로 하니까 난해하게 들릴 수 있지만, 초급 단계의 과제를 하면서 프레임워크 없이 뒤죽박죽 코드를 작성해 본 경험이 있다면 프레임워크를 통해 DI를 수행하며 느끼는 것이 있을 것이다.
하나를 수정하면 다른 것도 수정해야 하고, 이것과 저것이 다 연결되어 있고, 사용을 위해 갖다 붙이며 누덕누덕 만들어야 하고... 코드 간의 결합도 굉장히 강해진다.
이렇게 강한 의존성을 갖고 작성된 코드들은 변화에 취약하며 유지보수가 어렵고 재사용성 역시 떨어진다.</p>
<p>&nbsp;</p>
<hr>
<p>&nbsp;</p>
<h2 id="어떻게-쓸까">어떻게 쓸까?</h2>
<p>스프링 프레임워크에서 제공하는 IoC 컨테이너를 활용해 DI를 수행하고 싶다면 어떻게 해야 할까?</p>
<p>스프링에서는 IoC 컨테이너로 ApplicationContext 인터페이스를 제공한다. 일반적으로 IoC 컨테이너는 XML, 어노테이션 또는 자바 설정 파일을 통해 설정되고 구성된다. 여기에는 빈의 정의, DI, 빈의 라이프사이클 관리 등이 포함된다.</p>
<p>applicationContext.xml에서 스프링 IoC 컨테이너를 설정하는 예시를 살펴보자.</p>
<pre><code class="language-xml">&lt;!-- applicationContext.xml --&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd&quot;&gt;

    &lt;!-- 빈(Bean) 정의 --&gt;
    &lt;bean id=&quot;exampleService&quot; class=&quot;com.example.ExampleService&quot;&gt;
        &lt;!-- 의존성 주입 --&gt;
        &lt;property name=&quot;exampleRepository&quot; ref=&quot;exampleRepository&quot;/&gt;
    &lt;/bean&gt;

    &lt;bean id=&quot;exmapleRepository&quot; class=&quot;com.example.ExampleRepository&quot;/&gt;

&lt;/beans&gt;</code></pre>
<p>ExampleService와 ExampleRepository라는 두 개의 빈을 정의하고 의존성을 주입한다.
ExampleService는 ExampleRepository에 의존하며 이 의존성은 IoC 컨테이너에서 DI가 수행된다.</p>
<p>위의 내용을 가지고 ApplicationContext를 생성하고 빈을 가져오려면 어떻게 작성해야 할까?</p>
<pre><code class="language-java">import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        // XML 설정 파일을 사용하여 ApplicationContext 생성
        ApplicationContext context = new ClassPathXmlApplicationContext(&quot;applicationContext.xml&quot;);

        // ExampleService 빈을 가져옴
        ExampleService exampleService = (ExampleService) context.getBean(&quot;exampleService&quot;);

        // ExampleService 사용
        exampleService.someFunction();
        }
}
</code></pre>
<p>위의 코드는 applicationContext.xml을 사용하여 ApplicationContext를 생성하고 그 안에 정의된 ExampleService 빈을 가져오는 코드다.</p>
<p>위와 같은 방식으로 IoC 컨테이너를 통해 DI를 수행할 수 있다.</p>
<p>&nbsp;</p>
<hr>
<p>&nbsp;</p>
<p>_<a href='https://youtu.be/1vdeIL2iCcM?si=duBNQluEmotmYnRJ'>5분개발지식 님의 설명</a>_을 보고 이해하게 된 부분을 정리해 보았다.
스프링을 쓰면 바로 마주하게 되는 기본적인 코드고 내용이지만 막상 설명하기 어렵고 조금 난해하게 느껴지는 부분이었는데 큰 도움을 받았다. 감사합니당...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Controller]]></title>
            <link>https://velog.io/@yonny_k/springcontraller</link>
            <guid>https://velog.io/@yonny_k/springcontraller</guid>
            <pubDate>Wed, 19 Oct 2022 01:23:43 GMT</pubDate>
            <description><![CDATA[<h1 id="mvc">MVC</h1>
<hr>
<p>Model - View - Controller 구성을 갖는 디자인 패턴으로, 많은 웹 어플리케이션에 사용되고 있는 디자인 패턴이다.</p>
<h5 id="mvc-패턴은-어떻게-수행될까">MVC 패턴은 어떻게 수행될까?</h5>
<p>웹에서 특정 URL로 접속하여 리퀘스트가 들어오면 우선 컨트롤러 단에서 처리를 시작한다.
컨트롤러는 리퀘스트에 따라 Model을 업데이트하는 등의 처리를 한 뒤, 매핑된 View를 로드한다.
뷰 단에서는 업데이트된 모델을 처리하여 사용자에게 나타내게 된다.</p>
<p>이런 MVC 패턴의 웹 어플리케이션 프로그램 작성에서 컨트롤러는 어떻게 작성되고, 어떤 식으로 프로세스가 진행되는지 살펴보자.</p>
<h1 id="controller">Controller</h1>
<hr>
<p>컨트롤러는 브라우저에서 URL로 페이지를 요청할 때 URL을 매핑하고, 메소드를 연결해 주는 역할을 한다. 모델을 통해 받는 데이터 처리를 수행하고, 결과 값을 뷰에 반환하여 모델과 뷰 사이를 연결하는 다리 역할이 된다.</p>
<p>간단한 컨트롤러의 작성법을 살펴보자.</p>
<pre><code class="language-java">@RestController
public class YeonContoller {
    @RequestMapping(&quot;/yeon&quot;)
    public void requiredMethod() {
        ...
    }
}</code></pre>
<p>RestController 어노테이션을 이용해 컨트롤러를 설정할 수 있다.
어노테이션은 Controller를 사용할 수도 있으나, 그렇게 작성할 경우 메서드에 RequestMapping과 함께 ResponceBody 어노테이션을 추가해 주어야 한다.</p>
<p>컨트롤러는 URL 매핑 시 요구되는 데이터를 URL 혹은 뷰 단에서 가져와 Service 단에서 지정된 데이터 처리를 수행한다. Model로 데이터를 받아온 뒤 다시 뷰 단으로 보내어 사용자에게 UI 화면을 출력해 보여주게 된다.</p>
<p>컨트롤러는 URL 리퀘스트와 메소드를 매핑하는 것을 목적으로 한다. 컨트롤러에 비즈니스 로직까지 전부 구현할 수는 있으나, 유지보수와 가독성을 위해 컨트롤러 단에는 비즈니스 로직을 구성하는 것을 피하고, Service 단으로 넘겨 작성하는 것이 좋다.</p>
<hr>
<p><em>이 글은 <a href="https://wikidocs.net/book/7601">점프 투 스프링부트</a>를 스터디한 기록입니다.</em></p>
<p>참고한 페이지
<a href="https://hackmd.io/@NItj2RZUR_6qs26fqgepdg/rJ9EnWKJs">MVC, MVP, MVVM 등 아키텍쳐에 대하여...</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] Select]]></title>
            <link>https://velog.io/@yonny_k/vue-select</link>
            <guid>https://velog.io/@yonny_k/vue-select</guid>
            <pubDate>Tue, 18 Oct 2022 21:53:54 GMT</pubDate>
            <description><![CDATA[<h2 id="select">Select</h2>
<hr>
<p>기존에 세팅된 값들 중에서 하나를 고를 수 있도록 하는 컴포넌트다.
v-model로 바인딩하여 선택한 값을 저장해 보내거나 불러와 표시할 수 있다.
Search를 위한 분류 선택이나 글의 카테고리 지정 등으로 활용할 수 있다.</p>
<p>&nbsp;
기본적인 구성은 다음과 같다.
아래 구성은 아무것도 골라지지 않은 상태로 로드된다.</p>
<pre><code class="language-vue.js">&lt;templete&gt;
...
&lt;select v-model=&quot;dataId&quot; class=&quot;지정 스타일&quot;&gt;
    &lt;option value=&quot;0&quot;&gt;Black&lt;/option&gt;
    &lt;option value=&quot;1&quot;&gt;White&lt;/option&gt;
&lt;/select&gt;
...
&lt;/templete&gt;

&lt;script&gt;
export default {
    data() {
        return {
            dataId = &#39;&#39;,
            ...
           };
     };
},
...
&lt;script&gt;</code></pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<hr>
<h3 id="✔-보이는-초기값-설정하기">✔ 보이는 초기값 설정하기</h3>
<p>select에 초기값을 설정하고 싶다면 어떻게 해야 할까?
아래 코드를 활용하면 간단하게 설정할 수 있다.</p>
<pre><code class="language-vue.js">&lt;select v-model=&quot;dataId&quot; class=&quot;지정 스타일&quot;&gt;
    &lt;option value=&quot;&quot;&gt;All&lt;/option&gt;
    &lt;option value=&quot;0&quot;&gt;Black&lt;/option&gt;
    &lt;option value=&quot;1&quot;&gt;White&lt;/option&gt;
&lt;/select&gt;</code></pre>
<p>코드를 보면 알 수 있겠지만, v-model로 바인딩한 데이터에 저장된 값이 없는 상태라면 &quot;null&quot;의 값을 갖게 된다. 그래서 그냥 null로 설정해 주면 디폴트 값을 노출시킬 수 있다.
이 방법을 이용해서 초기값을 &#39;전체&#39;로 설정하여 검색을 수행시킬 수도 있고,
페이지 레이아웃에 따라 select에 &quot;~~을 선택하세요.&quot; 라는 문구를 노출시키는 등으로 활용할 수 있다.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<hr>
<p><em><a href="https://v3.ko.vuejs.org/guide/forms.html#%E1%84%8B%E1%85%A7%E1%84%85%E1%85%A5-%E1%84%8C%E1%85%AE%E1%86%AF%E1%84%8B%E1%85%B3%E1%86%AF-%E1%84%80%E1%85%A1%E1%84%8C%E1%85%B5%E1%86%AB-%E1%84%86%E1%85%AE%E1%86%AB%E1%84%8C%E1%85%A1%E1%86%BC">공식 가이드</a>를 읽어보는 걸 잊지 마세요!</em> 👩‍🏫</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MyBatis] mapper xml 작성하기]]></title>
            <link>https://velog.io/@yonny_k/mybatismysqlquerymapping</link>
            <guid>https://velog.io/@yonny_k/mybatismysqlquerymapping</guid>
            <pubDate>Tue, 18 Oct 2022 03:54:15 GMT</pubDate>
            <description><![CDATA[<h2 id="매퍼-초기-설정">매퍼 초기 설정</h2>
<hr>
<h3 id="mybatis-mapper로-세팅">mybatis mapper로 세팅</h3>
<pre><code>&lt;!DOCTYPE mapper
    PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
    &quot;https://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;

&lt;mapper namespace=&quot;example&quot;&gt;
...
&lt;/mapper&gt;</code></pre><h3 id="가져올-db-설정하기">가져올 DB 설정하기</h3>
<pre><code class="language-xml">&lt;sql id=&quot;tableMyData&quot;&gt;MY_DB_NAME&lt;/sql&gt;</code></pre>
<h3 id="column-정의">column 정의</h3>
<pre><code>&lt;sql id=&quot;columnsMyData&quot;&gt;
    EXAMPLE_ID, EXAMPLE_NAME, EXAMPLE_DATE,
    EXAMPLE_CODE, SELECT_YN
&lt;/sql&gt;</code></pre><p>&nbsp;</p>
<h2 id="resultmap">resultMap</h2>
<hr>
<p>resultMap은 데이터베이스 결과 데이터를 객체에 로드하는 방법을 정의하는 엘리먼트이다. 복잡한 구문에서 관계 서술을 위해 사용될 수 있는 강력한 엘리먼트지만, 여기서는 resultMap을 활용한 구문 매핑 대신 간단한 명칭 매핑만을 알아본다.
column과 property의 이름이 다른 경우, 데이터베이스 별칭을 사용하는 대신 명시적으로 resultMap을 선언하여 사용할 수 있다.</p>
<pre><code class="language-xml">&lt;resultMap id=&quot;exampleResult&quot; type=&quot;example&quot;&gt;
      &lt;id property=&quot;exampleId&quot; column=&quot;EXAMPLE_ID&quot; /&gt;
      &lt;result property=&quot;name&quot; column=&quot;EXAMPLE_NAME&quot; /&gt;
    &lt;result property=&quot;date&quot; column=&quot;EXAMPLE_DATE&quot; /&gt;
    &lt;result property=&quot;code&quot; column=&quot;EXAMPLE_CODE&quot; /&gt;
&lt;/resultMap&gt;</code></pre>
<p>위와 같이 프로퍼티명과 DB의 칼럼명을 지정해 준다.</p>
<p>&nbsp;</p>
<h2 id="select">select</h2>
<hr>
<pre><code>&lt;select id=&quot;selectName&quot; parameterType=&quot;string&quot; resultType=&quot;string&quot;&gt;
    SELECT &lt;include refid=&quot;columnsMyData&quot; /&gt;
    FROM &lt;include refid=&quot;tableMyData&quot; /&gt;
    WHERE EXAMPLE_ID = #{exmapleId}
    AND SELECT_YN = TRUE
&lt;/select&gt;</code></pre><pre><code class="language-xml">&lt;select id=&quot;selectASet&quot; parameterType=&quot;java.util.HashMap&quot; resultMap=&quot;exampleResult&quot;&gt;
    SELECT * FROM EXAMPLE_NAME
     WHERE EXAMPLE_ID = #{exmapleId}
&lt;/select&gt;</code></pre>
<p>returnType의 경우에는 다양한 타입이 올 수 있다.
이때 primitive type의 경우에는 _int 와 같이 적어야 int형으로 받을 수 있다.
적지 않을 경우, Wrapper class인 Integer 타입이 반환된다.</p>
<p>&nbsp;</p>
<h2 id="insert">insert</h2>
<hr>
<pre><code>&lt;insert id=&quot;insertData&quot; parameterType=&quot;exampleData&quot;&gt;
    INSERT INTO &lt;include refid=&quot;tableMyData&quot;/&gt;
    (&lt;include refid=&quot;columnsMyData&quot; /&gt;)
    VALUES
    (#{exampleId}, #{name}, NOW(), #{code}, FALSE)
&lt;/insert&gt;</code></pre><p>&nbsp;</p>
<h2 id="update">update</h2>
<hr>
<pre><code>&lt;update id=&quot;updateData&quot; parameterType=&quot;exampleData&quot;&gt;
    UNDATE &lt;include refid=&quot;tableMyData&quot;/&gt;
    SET EXAMPLE_NAME = #{name},
    EXAMPLE_DATE = NOW(),
    EXAMPLE_CODE = #{code}
    WHERE EXAMPLE_ID = #{exampleId}
&lt;/update&gt;</code></pre><p>&nbsp;</p>
<h2 id="delete">delete</h2>
<hr>
<pre><code>&lt;delete id=&quot;deleteData&quot; parameterType=&quot;exampleData&quot;&gt;
    DELETE FROM &lt;include refid=&quot;tableMyData&quot;/&gt;
    WHERE EXAMPLE_ID = #{exampleId}
&lt;/delete&gt;</code></pre><p>&nbsp;</p>
<p>&nbsp;</p>
<hr>
<p>_<a href="https://mybatis.org/mybatis-3/ko/index.html">MyBatis 공식 문서(ko)</a>_도 확인해 보세요🤷‍♀️</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] DAO, DTO, Entity]]></title>
            <link>https://velog.io/@yonny_k/dao-dto-entity</link>
            <guid>https://velog.io/@yonny_k/dao-dto-entity</guid>
            <pubDate>Mon, 17 Oct 2022 09:20:29 GMT</pubDate>
            <description><![CDATA[<hr>
<h2 id="dao">DAO</h2>
<p>DAO는 Data Access Object의 약자로, 데이터에 접근하는 객체다.
Service에서 DB의 데이터를 다루기 위한 툴과 같은 역할을 한다.</p>
<p>아래 예시를 통해 살펴보자.</p>
<pre><code class="language-java">// 템플릿 설정 등을 완료했음을 상정한 예시 코드

@Repository
public class ExDao {

    @Inject
    SqlSession sqlSession;

    public ExEntity getEx(String exId) {
        return sqlSession.selectOne(&quot;...ExMapper.selectEx&quot;, exId);
        // 개발된 상황에 따라 매핑된 sql문 호출은 달라질 수 있음
    }
}</code></pre>
<p>DB의 CRUD를 수행하기 위한 메서드를 위처럼 정의한다.
SqlSession을 이용해 MyBatis로 매핑된 쿼리를 날리는 직접적인 역할을 하는 것이다.
이를 Service에서 가져가서 사용하는 것으로 DB의 데이터를 관리할 수 있게 된다.</p>
<p>&nbsp;</p>
<hr>
<h2 id="dto">DTO</h2>
<p>DTO는 Data Transfer Object의 약자로, 데이터 교환을 위한 객체다.</p>
<pre><code class="language-java">@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnorProperties(ignoreUnknown = true)
public class ExDto {
    private String orderBy;
    private String exId;
    private String exName;
    private int exAge;
}</code></pre>
<p>DTO는 Layer간 데이터 교환이 이루어지도록 하는 객체로, Entity와 유사하지만 Entity와는 달리 각 레이어에서 주고받을 수 있는, 그저 데이터들을 담아둔 박스와 같은 객체다. 목적 자체가 데이터를 전달하는 것에 있기 때문에 읽고 쓰는 것이 모두 가능해서 getter, setter을 모두 설정할 수 있으며 일회성으로 데이터를 주고받는 것으로만 사용되는 성격이 강하다.
예를 들어, 가져온 데이터를 페이징한 결과를 view에서 요청할 때 DTO를 활용해 paging된 result를 보내는 데 사용할 수 있다. 이런 경우 Presentaion 로직이 추가로 요구되는데, 그러한 처리를 DTO에서 담당해 처리 후 데이터를 보내는 것이다. 이렇게 view에서 요청하는 정보와 테이블에 매핑된 정보가 다를 경우 그 데이터 변환 과정 로직을 담기 위해, 또는 불필요한 데이터의 노출을 막기 위해 사용될 수 있다.
DTO가 사용되는 방식은 프로젝트마다 성격이 다를 수 있으므로 맞춰서 작성하도록 하자.
한편 읽기 전용으로만 사용되는 DTO는 <strong>VO</strong>_(Value Object)_로 작성되기도 한다. 둘은 완벽히 같은 것이 아니고, VO는 setter 메서드를 가질 수 없으며 객체들의 주소 값이 다르더라도 데이터의 value가 같으면 동일한 것으로 처리하는 등의 차이점이 있다.</p>
<p>&nbsp;</p>
<hr>
<h2 id="entity">Entity</h2>
<p>실제 DB의 테이블과 매칭시켜 링크하는 클래스다.</p>
<pre><code class="language-java">@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnorProperties(ignoreUnknown = true)
public class ExEntity implements Serializable {
    private String exId;
    private String exName;
    private int exAge;
}</code></pre>
<p>위처럼 DB의 테이블에 존재하는 column들을 매핑하여 1:1 필드로 가지며 실제 DB에 존재하지 않는 칼럼은 가지지 않는다. 테이블과 링크되어 데이터들을 나타내는 코어한 클래스이기 때문에 Entity를 기준으로 많은 로직들이 설정되게 되므로 Entity의 내용이 변경되면 큰 영향을 보일 수 있다. DB의 영속성을 목적으로 사용되기 때문에 setter을 작성할 수는 있으나 지양하는 것이 좋으며 필요한 경우 생성자나 Builder를 사용한다.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<hr>
<p><em>참고한 페이지</em>
<a href="https://wildeveloperetrain.tistory.com/101">https://wildeveloperetrain.tistory.com/101</a>
<a href="https://gmlwjd9405.github.io/2018/12/25/difference-dao-dto-entity.html">https://gmlwjd9405.github.io/2018/12/25/difference-dao-dto-entity.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] Splash]]></title>
            <link>https://velog.io/@yonny_k/kotlinsplash</link>
            <guid>https://velog.io/@yonny_k/kotlinsplash</guid>
            <pubDate>Mon, 17 Oct 2022 09:20:15 GMT</pubDate>
            <description><![CDATA[<h2 id="🌊-splash">🌊 Splash</h2>
<p>어플리케이션 실행 시 가장 먼저 나타나는 화면을 뜻한다.
실행 후 2초간 나타나는 Splash 화면을 설정해 보자.</p>
<ul>
<li>AndroidManifest.xml</li>
</ul>
<pre><code class="language-kotlin">&lt;activity
    android:name=&quot;.Splash&quot;
    android:exported=&quot;true&quot;&gt;
        &lt;intent-filter&gt;
            &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;
            &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;
        &lt;/intent-filter&gt;
&lt;/activity&gt;</code></pre>
<p>app 모듈의 AndroidManifest.xml을 수정하여 실행 시 MainActivity를 로드하는 대신 Splash 액티비티를 로드하도록 설정한다.</p>
<p>&nbsp;</p>
<ul>
<li><p>Splash.kt</p>
<pre><code class="language-kotlin">class Splash : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.splash_screen)
      loadSplash()
  }

  private fun loadSplash(){
      Handler().postDelayed({
          val intent = Intent(this, MainActivity::class.java)
          startActivity(intent)
          finish()
      }, 2000)
  }
}</code></pre>
<p>Splash는 가장 먼저 실행되어야 하는 Activity이므로 onCreate를 바로 호출한다.
setContentView로 Splash 화면의 레이아웃을 설정하고, loadSplash로 딜레이 후 화면 전환을 진행한다. 딜레이 후 intent로 가져온 MainActivity로 넘기도록 핸들러를 사용해 준다.
초기에 한 번만 사용하는 Activity이기 때문에 finish()로 Destroy하도록 한다.</p>
</li>
</ul>
<p>handler use warning ignore을 위해서는 <code>@Suppress(&quot;DEPRECATION&quot;)</code> 어노테이션을 상단에 추가한다.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<hr>
<p><em>Android Studio Chipmunk | 2021.2.1 Patch 2</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Lambda]]></title>
            <link>https://velog.io/@yonny_k/Java-Lambda</link>
            <guid>https://velog.io/@yonny_k/Java-Lambda</guid>
            <pubDate>Sun, 16 Oct 2022 23:41:37 GMT</pubDate>
            <description><![CDATA[<h1 id="함수형-프로그래밍">함수형 프로그래밍</h1>
<p>Java 8부터 람다(Lambda)가 도입되었다. 이를 활용하면 함수형 프로그래밍 스타일로 자바 코드를 작성할 수 있다. 이를 이용해 코드를 작성하면 코드의 양이 줄어들고, 가독성을 높이는 데 유리하다.</p>
<p>&nbsp;</p>
<h2 id="람다lambda">람다(Lambda)</h2>
<hr>
<p>람다를 사용하면 인터페이스 내부 메서드를 별도의 구현 클래스 없이 사용하거나, 인터페이스도 구현하지 않고 익명의 함수를 만들어 바로 사용할 수 있다.</p>
<p>먼저 구현 없이 인터페이스 내부 메서드를 사용해 보자.</p>
<pre><code class="language-java">@FuntionalInterface // 람다 함수로 쓸 인터페이스는 어노테이션을 사용하는 것이 좋다.
interface AddTwoInt {
    int sum(int a, int b);
}

public class Example {
    public static void main(String[] args) {
        AddTwoInt ati= (a, b) -&gt; a + b; // 람다로 바로 구현해서 쓴다.
        int result = ati.sum(3, 4);
        System.out.println(result);  // 7 출력
    }
}</code></pre>
<p>람다함수로 사용하기 위해서는 해당 인터페이스에 메서드가 하나만 있어야 한다.
@FuntionalInterface 어노테이션을 사용하면 인터페이스에 메서드를 하나만 작성할 수 있도록 강제해 람다 함수로 안정적으로 쓸 수 있다.
<code>(a, b) -&gt; a + b;</code> 는 <code>(int a, int b) -&gt; a + b;</code> 로도 쓸 수 있으나 자료형은 인터페이스에 선언되어 있으므로 생략가능하다.
또한 두 int의 합을 구하는 것은 Integer.sum(int a, int b)와 동일하기 때문에, 이미 존재하는 어떤 클래스의 메서드를 가져와 사용한다면 <code>AddTwoInt ati = Integer::sum;</code> 즉, 클래스명::메서드명 으로도 작성할 수 있다.</p>
<p>&nbsp;</p>
<p>굳이 인터페이스를 따로 작성하지 않고 더 쉽게 익명 함수를 만들 방법은 없을까?
Java에서 제공되는 BiFunction 인터페이스를 사용하면 아래처럼 더 쉽게 작성할 수 있다.</p>
<pre><code class="language-java">    BiFunction&lt;Integer, Integer, Integer&gt; ati = (a, b) -&gt; a + b;
    BiFunction&lt;입력, 입력, 출력&gt; 이름 = 람다식;

    // BiFunction은 입출력 타입을 다양하게 설정할 수 있지만,
    // 위처럼 모두 같다면 BinaryOperator을 사용하면 더 간단하다.

    BinaryOperator&lt;Integer&gt; ati = (a, b) -&gt; a + b;

    int result = ati.apply(3, 4); // apply로 호출한다.</code></pre>
<p>이처럼 람다식을 사용하면 조금 더 간결한 코드 작성이 가능하다.
Java에서는 위에서 소개한 것보다 더 다양한 람다 인터페이스를 제공하고 있어, 필요에 맞게 사용할 수 있다.</p>
<h2 id="스트림stream">스트림(Stream)</h2>
<hr>
<p>스트림은 데이터의 흐름을 의미한다. 배열, 리스트와 같은 데이터셋을 필터링하고 가공할 때 물 흐르듯 제어할 수 있도록 해 준다.</p>
<p>주어진 정수 배열에서 짝수만 찾아 중복을 제거한 다음 역순으로 정렬해야 하는 문제가 있다고 가정해 보자.</p>
<pre><code class="language-java">import java.util.*;

public class Sample {
    public static void main(String[] args) {
        int[] data = {5, 6, 4, 2, 3, 1, 1, 2, 2, 4, 8};

        // 짝수만 포함하는 ArrayList 생성
        ArrayList&lt;Integer&gt; dataList = new ArrayList&lt;&gt;();
        for(int i=0; i&lt;data.length; i++) {
            if(data[i] % 2 == 0) {
                dataList.add(data[i]);
            }
        }

        // Set을 사용하여 중복을 제거
        HashSet&lt;Integer&gt; dataSet = new HashSet&lt;&gt;(dataList);

        // Set을 다시 List로 변경
        ArrayList&lt;Integer&gt; distinctList = new ArrayList&lt;&gt;(dataSet);

        // 역순으로 정렬
        distinctList.sort(Comparator.reverseOrder());

        // Integer 리스트를 정수 배열로 변환
        int[] result = new int[distinctList.size()];
        for(int i=0; i&lt; distinctList.size(); i++) {
            result[i] = distinctList.get(i);
        }
    }
}</code></pre>
<p>스트림을 활용하지 않으면 위처럼 기나긴 과정을 거쳐 결과를 얻어야 한다.
하지만 스트림을 사용하면 아래처럼 간단하게 표현할 수 있다.</p>
<pre><code class="language-java">import java.util.Arrays;
import java.util.Comparator;

public class Sample {
    public static void main(String[] args) {
        int[] data = {5, 6, 4, 2, 3, 1, 1, 2, 2, 4, 8};
        int[] result = Arrays.stream(data)  // IntStream을 생성한다.
                .boxed()  // IntStream을 Stream&lt;Integer&gt;로 변경한다.
                .filter((a) -&gt; a % 2 == 0)  //  짝수만 걸러낸다.
                .distinct()  // 중복을 제거한다.
                .sorted(Comparator.reverseOrder())  // 역순으로 정렬한다.
                .mapToInt(Integer::intValue)  // Stream&lt;Integer&gt;를 IntStream으로 변경한다.
                .toArray()  // int[] 배열로 반환한다.
                ;
    }
}</code></pre>
<p>스트림은 적힌 순서대로 데이터를 처리한다. 가독성이 훨씬 뛰어난 것을 확인할 수 있다.
스트림은 위처럼 기존 데이터를 통해 만들 수도 있지만 빌더를 이용해 원하는 값을 넣어 만들 수도 있고, 빈 스트림을 만들 수도 있다. 스트림에서 제공되는 작업 역시 매우 다양하므로 필요에 맞게 찾아 사용하면 데이터 처리를 한결 수월하게 진행할 수 있다.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<hr>
<p><em>이 글은 <a href="https://wikidocs.net/book/31">점프 투 자바</a>를 읽고 스터디한 글입니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Thread]]></title>
            <link>https://velog.io/@yonny_k/Java-Thread</link>
            <guid>https://velog.io/@yonny_k/Java-Thread</guid>
            <pubDate>Sun, 16 Oct 2022 23:40:56 GMT</pubDate>
            <description><![CDATA[<h2 id="thread">Thread</h2>
<hr>
<p>한 프로세스 내에서 여러 쓰레드를 이용하면 여러 가지 일을 동시에 수행할 수 있다.</p>
<pre><code class="language-java">public class Exmple extends Thread {
    public void run() {
        System.out.println(&quot;thread run.&quot;);
    }

    public static void main(String[] args) {
        Example example = new Example();
        example.start();  // start()로 쓰레드를 실행한다.
    }
}</code></pre>
<p>Thread 클래스를 상속받고, thread 클래스의 run 메소드를 구현하면 해당 thread를 start할 때 run 메소드가 수행된다.</p>
<pre><code class="language-java">import java.util.ArrayList;

public class Sample extends Thread {
    int seq;
    public Sample(int seq) {
        this.seq = seq;
    }

    public void run() {
        System.out.println(this.seq+&quot; thread start.&quot;);
        try {
            Thread.sleep(1000);
        }catch(Exception e) {
        }
        System.out.println(this.seq+&quot; thread end.&quot;);
    }

    public static void main(String[] args) {
        ArrayList&lt;Thread&gt; threads = new ArrayList&lt;&gt;();
        for(int i=0; i&lt;10; i++) {
            Thread t = new Sample(i);
            t.start();
            threads.add(t);
        }

        for(int i=0; i&lt;threads.size(); i++) {
            Thread t = threads.get(i);
            try {
                t.join(); // t 쓰레드가 종료할 때까지 기다린다.
            }catch(Exception e) {
            }
        }
        System.out.println(&quot;main end.&quot;);
    }
}</code></pre>
<p>thread는 동시에 실행하면 순서와 상관없이 실행되고, 별도의 처리 없이는 스레드를 실행한 main 메소드가 먼저 종료되어버릴 수 있다. 따라서 위와 같이 join 메서드를 활용해 모든 스레드 종료 후 main 메소드를 종료시키도록 할 수 있다. join 메서드는 스레드가 종료될 때까지 기다리게 하는 메서드이다.</p>
<h2 id="runnable">Runnable</h2>
<hr>
<p>스레드를 만들 때 위처럼 Thread를 상속받아 만들기도 하지만, 주로 Runnable 인터페이스를 구현하는 방법을 주로 사용한다. Thread 상속 시 다중 상속이 불가능하므로 다른 클래스를 상속받으면서 쓰레드를 구현하기 위해서이다.
위에서 작성한 예제를 아래와 같이 바꿀 수 있다.</p>
<pre><code class="language-java">import java.util.ArrayList;

public class Sample implements Runnable {
    int seq;
    public Sample(int seq) {
        this.seq = seq;
    }

    public void run() {
        System.out.println(this.seq+&quot; thread start.&quot;);
        try {
            Thread.sleep(1000);
        }catch(Exception e) {
        }
        System.out.println(this.seq+&quot; thread end.&quot;);
    }

    public static void main(String[] args) {
        ArrayList&lt;Thread&gt; threads = new ArrayList&lt;&gt;();
        for(int i=0; i&lt;10; i++) {
            Thread t = new Thread(new Sample(i));
            t.start();
            threads.add(t);
        }

        for(int i=0; i&lt;threads.size(); i++) {
            Thread t = threads.get(i);
            try {
                t.join();
            }catch(Exception e) {
            }
        }
        System.out.println(&quot;main end.&quot;);
    }
}</code></pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<hr>
<p><em>이 글은 <a href="https://wikidocs.net/book/31">점프 투 자바</a>를 읽고 스터디한 글입니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 예외처리]]></title>
            <link>https://velog.io/@yonny_k/Java-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@yonny_k/Java-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Sun, 16 Oct 2022 23:40:35 GMT</pubDate>
            <description><![CDATA[<h4 id="java의-예외처리">Java의 예외처리</h4>
<p>존재하지 않은 파일을 열려고 한다거나, 숫자를 0으로 나눈다거나... 앞에서 입출력을 수행할 때 IOException을 throw했듯, Java는 이런 예외가 발생할 수 있다고 판단되는 구문들을 모두 잡아두고 예외처리를 수행하도록 강제하고 있다.
이는 작성이 번거롭다는 단점이 될 수도 있지만 동시에 빠른 디버깅과 유지보수를 가능하게 한다.</p>
<p>&nbsp;</p>
<h2 id="try--catch-finally">try ... catch, finally</h2>
<hr>
<pre><code class="language-java">try {
    ...
} catch (예외1) {
    ...
} catch (예외2) {
    ...
} finally {
    ...
}</code></pre>
<p>try 문을 수행하면서 예외가 발생하는지 체크하고, 예외가 발생한다면 예외 상황에 맞는 catch문을 수행한다.
한편 예외가 발생했건 아니건 간에 finally 구문이 존재한다면, try 문과 (예외 발생 시) catch 문을 모두 수행한 뒤 마지막에 finally의 내용을 수행한다.</p>
<p>&nbsp;</p>
<h2 id="예외-만들기">예외 만들기</h2>
<hr>
<p>매우 다양한 Exception들이 이미 존재하지만, 우리는 그 예외들을 상속해서 필요 시 우리만의 예외를 만들 수도 있다.</p>
<pre><code class="language-java">class MyException extends Exception {}
class MyRuntimeException extends RuntimeExceptions {}</code></pre>
<p>Exception은 컴파일시 발생하는 예외이고 RuntimeException은 실행 중 발생하는 예외이다. 작성 중 예측 가능한 경우 Exception, 런타임 에러가 예상되는 경우 RuntimeException을 이용하자.
이렇게 직접 작성한 에러는 본인의 코드 내에서 특정 조건이 성립할 때 <code>throw new MyException;</code> 처럼 던지도록 해 사용할 수 있다.</p>
<p>&nbsp;</p>
<h2 id="throws">throws</h2>
<hr>
<p>try ... catch 구문 대신, 메서드에 throws XXXException 을 추가해서 호출한 곳에서 예외를 처리할 수 있도록 위로 던지는 방법이 있다.</p>
<pre><code class="language-java">public void exMethod(String str) throws IOException {
    ...
}</code></pre>
<p>이 방법을 사용하게 되면 예외처리를 뒤로 미루듯, 해당 메서드를 호출한 메서드에서 해결하도록 할 수 있다. 해당 메서드 호출 후 예외 발생 시 처리방법이 다르게 적용되어야 하는 경우 유용하게 사용될 수 있다.
예외를 처리하는 위치는 프로그램의 수행여부를 결정하기도 하고 트랜잭션 처리와도 밀접한 관계가 있어서 이를 잘 컨트롤하는 것은 대단히 중요하다.
하지만 그냥 throws만을 남발하게 되면 최상위단에서 수많은 예외를 혼자 처리해야 할 수 있으므로 필요시에 사용하도록 하자.</p>
<p>&nbsp;</p>
<h3 id="트랜잭션">트랜잭션</h3>
<hr>
<p>예외 처리 위치가 트랜잭션 처리와 왜 관계가 있는지 알아보자.
트랜잭션이란 쪼갤 수 없는 업무의 최소 단위를 뜻한다. 어떠한 트랜잭션의 수행 중 에러가 발생하면 거기서 멈추는 것이 아니라 트랜잭션이 시작되기 전의 상태로 돌아와야 한다. DB 처리를 수행할 때 트랜잭션이라는 단어를 들어보게 될 것이다. DB 상태 변경 중 에러가 발생하면 냅다 거기서 멈추면 안 되고, 아예 처리 전의 상태로 돌아올 수 있도록 처리해야 한다.
따라서 아래와 같이 예외처리의 위치를 설정해 트랜잭션을 관리해야 한다.</p>
<pre><code class="language-java">A 트랜잭션() {
    try {
        업무 1();
        업무 2();
        업무 3();
    } catch(예외) {
        진행사항 모두 취소();
    }
}

업무 1() throws 예외 { ... }
업무 2() throws 예외 { ... }
업무 3() throws 예외 { ... }</code></pre>
<p>&nbsp;</p>
<hr>
<p><em>이 글은 <a href="https://wikidocs.net/book/31">점프 투 자바</a>를 읽고 스터디한 글입니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 콘솔 & 파일 입출력]]></title>
            <link>https://velog.io/@yonny_k/Java-Package</link>
            <guid>https://velog.io/@yonny_k/Java-Package</guid>
            <pubDate>Sun, 16 Oct 2022 23:38:33 GMT</pubDate>
            <description><![CDATA[<h1 id="콘솔-입출력">콘솔 입출력</h1>
<hr>
<pre><code class="language-java">System.out.println(&quot;내용&quot;);</code></pre>
<p>콘솔 출력을 위해 사용해 온 위 메서드는 PrintStream 클래스의 메서드다.
println은 콘솔에 문자열을 출력하고 ln, 즉 줄바꿈을 수행해 준다.
한편 System.out.printf를 사용하면 C에서 사용했던 printf처럼, %d, %s 등을 사용한 서식과 변수를 따로 전달해 출력할 수 있다.
System.err.println을 사용하면 오류 메세지 출력이 가능하다.</p>
<p>&nbsp;</p>
<p>그렇다면 콘솔에서의 입력은 어떻게 받을 수 있을까?</p>
<h4 id="inputstream">InputStream</h4>
<pre><code class="language-java">import java.io.IOException;
import java.io.InputStream;

public class Example {
    public static void main(String[] args) throws IOException {
        InputStream is = System.in;
        int a;
        a = is.read();
        System.out.println(a);
    }
}</code></pre>
<p>InputStream의 read 메서드는 1 byte의 입력을 받아들인다. 한편 사용자의 입력은 우선 문자로 처리되기 때문에 0을 입력해도 숫자 0이 아닌 0의 아스키코드값(48)이 int a에 저장된다.
1 byte씩만 read되므로 그 이상을 저장하고 싶을 경우 여러 개의 변수에 나눠 저장하거나 byte 배열을 이용해야 한다.</p>
<h4 id="inputstreamreader">InputStreamReader</h4>
<pre><code class="language-java">import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Example {
    public static void main(String[] args) throws IOException {
        InputStream is = System.in;
        InputStreamReader inputStreamReader = new InputStreamReader(is);
        char[] a = new char[3];
        inputStreamReader.read(a);
        System.out.println(a);
    }
}</code></pre>
<p>InputStreamReader를 이용하면 byte 단위로 아스키 코드값을 읽어오는 대신, char로 읽어와 바로 문자로 저장하고 출력할 수 있게 된다.</p>
<h4 id="bufferedreader">BufferedReader</h4>
<pre><code class="language-java">import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Example {
    public static void main(String[] args) throws IOException {
        InputStream is = System.in;
        InputStreamReader inputStreamReader = new InputStreamReader(is);
        BufferedReader buffReader = new BufferedReader(inputStreamReader);

        String a = buffReader.readLine();
        System.out.println(a);
    }
}</code></pre>
<p>BufferedReader를 이용하면 이제 배열 대신 바로 문자열로 저장할 수 있게 된다.
readLine 메서드는 사용자가 엔터키를 입력할 때까지 입력을 받다가, 엔터가 입력되면 스트림을 닫고 문자열을 저장한다.</p>
<h4 id="scanner">Scanner</h4>
<p>하지만 여러분은 아마도 그간 콘솔 입력을 받을 때 Scanner을 이용해 왔을 것이다.
위에서 살펴본 메서드들은 불편한 점이 남아있을 뿐더러 객체를 만들고 감싸고 감싸니 불편하게 느껴진다.
J2SE 5.0부터 추가된 Scanner 클래스를 이용해 편하게 입력을 받아보자.</p>
<pre><code class="language-java">import java.util.Scanner;

public class Example {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println(scanner.next());
    }
}</code></pre>
<p>Scanner 역시 콘솔입력 InputStream을 System.in으로 받아 생성되는 것이 이제는 눈에 보인다.
Scanner 객체의 next() 메서드는 단어 하나를 받아들인다. nextLine은 한 줄을, nextInt는 정수를 받아들이는 등 여러 간편한 메서드들이 있어 필요에 따라 사용할 수 있다.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h1 id="파일-입출력">파일 입출력</h1>
<hr>
<p>파일 출력은 즉 파일의 작성이다. Java에서 파일 출력을 수행해 보자.</p>
<h2 id="파일-출력">파일 출력</h2>
<h3 id="파일-작성">파일 작성</h3>
<pre><code class="language-java">import java.io.FileOutputStream;
import java.io.IOException;

public class Example {
    public static void main(String[] args) throws IOException {
        FileOutputStream output = new FileOutputStream(&quot;c:/out.txt&quot;);
        String data = &quot;Hello java!\r\nWe made a file!\r\n&quot;;
        output.write(data.getBytes());
        output.close();
    }
}</code></pre>
<p>c:/out.txt 파일이 생성된 것을 볼 수 있다. 지정된 경로에 아웃풋 스트림을 열고 데이터를 작성한다.
FileOutputStream도 byte 단위로 데이터를 처리하기 때문에 String을 getBytes()로 byte 배열로 바꿔 전달한다.
하지만 FileWriter 클래스를 이용해 <code>FileWriter fileWriter = new FileWriter(&quot;c:/out.txt&quot;);</code> 파일을 열고, <code>fileWriter.write(data);</code>로 사용하면 byte 대신 문자열을 바로 출력할 수 있다.
하지만 줄바꿈을 위해 \r\n을 덧붙여야 한다니, 명색이 java인데 너무 귀찮게 느껴지지 않는가?
PrintWriter 클래스를 이용하면 println을 파일에서도 이용할 수 있다.</p>
<pre><code class="language-java">import java.io.IOException;
import java.io.PrintWriter;

public class Example {
    public static void main(String[] args) throws IOException {
        PrintWriter pw = new PrintWriter(&quot;c:/out.txt&quot;);
        String str1 = &quot;Hello java!&quot;;
        String str2 = &quot;We made a file!&quot;;
        pw.println(str1);
        pw.println(str2);
        pw.close();
    }
}</code></pre>
<h3 id="파일-내용-추가-작성">파일 내용 추가 작성</h3>
<p>매번 파일을 생성하거나 완전히 덮어써버릴 순 없다. 파일에 내용을 추가하기 위해선 어떻게 해야 할까?</p>
<pre><code class="language-java">import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class Example {
    public static void main(String[] args) throws IOException {
        PrintWriter pw = new PrintWriter(&quot;c:/out.txt&quot;);
        String str2 = &quot;Hello java!&quot;;
        pw.println(str1);
        pw.close();


        PrintWriter pw2 = new PrintWriter(new FileWriter(&quot;c:/out.txt&quot;, true));
        String str2 = &quot;We made a file!&quot;;
        pw2.println(str2);
        pw2.close();
    }
}</code></pre>
<p>파일의 아웃풋스트림을 열 때 true를 같이 전달하는 것을 볼 수 있다. 이는 추가모드로 열 것인지에 대한 boolean 파라미터를 전달하는 것으로, true로 넣을 경우 추가모드로 파일을 수정할 수 있게 된다.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2 id="파일-읽기">파일 읽기</h2>
<p>콘솔 때와 유사하게 FileInputStream을 사용하면 바이트 단위로 파일을 읽어올 수 있지만, 대신 라인 단위로 읽어올 수 있는 BufferedReader을 사용해 보자.</p>
<pre><code class="language-java">import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Example {
    public static void main(String[] args) throws IOException {
        BufferedReader buffReader = new BufferedReader(new FileReader(&quot;c:/out.txt&quot;));
        while(true) {
            String line = buffReader.readLine();
            if (line==null) break;
            System.out.println(line);
        }
        buffReader.close();
    }
}</code></pre>
<p>라인 단위로 파일을 읽을 수 있고 더 이상 라인이 없을 경우(null) 종료한다.</p>
<p>&nbsp;</p>
<blockquote>
<p>Java는 프로그램 종료 시 사용한 파일 스트림을 알아서 닫지만 사용했던 파일을 닫지 않고 다시 사용하려고 하면 에러가 발생하므로 반! 드! 시! 닫도록 한다.</p>
</blockquote>
<p> &nbsp;</p>
<p>&nbsp;</p>
<hr>
<p><em>이 글은 <a href="https://wikidocs.net/book/31">점프 투 자바</a>를 읽고 스터디한 글입니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 객체 지향, 클래스]]></title>
            <link>https://velog.io/@yonny_k/Java-OOP-class</link>
            <guid>https://velog.io/@yonny_k/Java-OOP-class</guid>
            <pubDate>Sun, 16 Oct 2022 23:36:14 GMT</pubDate>
            <description><![CDATA[<h1 id="객체-지향-프로그래밍">객체 지향 프로그래밍</h1>
<hr>
<p>Java는 객체 지향 언어이다. 객체 지향 프로그래밍은,</p>
<blockquote>
<ul>
<li>코드의 재사용성이 높고<em>(상속, 캡슐화, 다형성)</em>,</li>
</ul>
</blockquote>
<ul>
<li>코드의 관리_(유지보수, 업그레이드, 디버깅)_가 용이하며,</li>
<li>보안성을 향상할 수 있으며 신뢰성 높은 프로그래밍을 가능하게 한다.</li>
</ul>
<p>모든 것을 객체와 그 객체들 간의 상호작용으로 보는 것이 객체지향이론의 기본이다. 객체 지향 프로그래밍은 이 이론을 기반으로, 각 속성과 기능을 담은 객체들과 객체들 간의 상호작용의 서술으로 어플리케이션을 작성하는 방식이다. Java를 들여다 보면 모든 것이 클래스에서 시작해서 클래스로 끝난다. 각 클래스에서 각자의 역할을 맡아 세부적인 사항들을 기술하고 있고, 그걸 사용하는 방식-관계-을 잘 서술해내는 것으로 프로그래밍이 이루어진다. 해야할 일을 순차적으로 기술하고 그대로 수행하는 절차 지향 프로그래밍과는 큰 차이가 있다.
대규모의 프로그램은 많은 기능을 포함하기 때문에 객체 지향으로 작성하는 것이 적합하다. 성능(실행 속도) 측면에서는 절차적 프로그램보다 느리다는 단점이 있으나 눈부신 기술의 발전이 있었기에 빠른 속도가 요구되는 분야가 아닌 이상 실생활 어플리케이션 작성에는 아무 문제없이 사용할 수 있다.</p>
<p>&nbsp;</p>
<h1 id="class">class</h1>
<hr>
<p>클래스는 객체를 생성하기 위한 템플릿이며 속성과 기능으로 정의되어 있다. 이 클래스라는 틀을 이용해서 객체라는 것들을 찍어낸다.
클래스는 객체 내의 변수와 메서드를 정의해 준다. 객체는 이를 그대로 이어받아 만들어지고, 각자 다른 데이터를 담거나 어떠한 처리를 하는 등으로 사용된다.</p>
<pre><code class="language-java">class ExClass {
    객체변수;
    메서드() { ... };
    ...
}

...

ExClass ex1 = new ExClass();
// ex1은 객체이자 ExClass의 인스턴스이다.</code></pre>
<p>객체 변수에는 객체명.변수명 으로 접근할 수 있으며,
메서드 역시 객체명.메서드() 으로 접근할 수 있다.
또한 같은 클래스의 객체라도 서로의 값이 <em>(static이 아니라면)</em> <strong>절대</strong> 공유되지 않는다. 때문에 객체 지향 프로그래밍이 가능한 것이다.</p>
<p>&nbsp;</p>
<p>한편 메서드로 하여금 해당 인스턴스의 객체 변수에 접근하기 위해서는</p>
<pre><code class="language-java">exMethod(String data) {
    this.str = data; // &quot;this.&quot;
}</code></pre>
<p>this.변수명 으로 접근할 수 있다.</p>
<p>&nbsp;</p>
<hr>
<h4 id="call-by-value-reference">Call by Value? Reference?</h4>
<blockquote>
<p>메서드에서 <strong>&#39;값&#39;</strong>으로 받았으면 <strong>Value</strong>
 메서드에서 _<strong>&#39;객체&#39;</strong>_로 받아서 _<strong>&#39;객체 변수&#39;</strong>_를 건드렸으면 <strong>Reference</strong></p>
</blockquote>
<p> &nbsp;</p>
<hr>
<h4 id="메서드-오버로딩">메서드 오버로딩</h4>
<p>메서드를 작성하다 보면, 같은 이름의 메서드를 호출하는데 서로 다른 개수나 타입의 매개변수를 전달해야 하는 경우가 발생할 수 있다. 이런 경우에는 그저 각 경우의 수를 모두 기술하면 메서드를 호출할 때 호출한 매개변수의 종류에 맞는 메서드를 알아서 불러오게 된다.</p>
<pre><code class="language-java">class Eat(){
    void eat(String a) {
        System.out.println(&quot;I ate &quot; + a + &quot; and still hungry.&quot;);
    }

    void eat(String a, String b) {
        System.out.println(&quot;I ate &quot; + a + &quot; and &quot; + b + &quot; but still hungry.&quot;);
    }

    void eat(String a, String b, String c) {
        System.out.println(&quot;I ate &quot; + a + &quot;, &quot; + b + &quot; and &quot; + c &quot;, I&#39;m full!&quot;);
    }
}</code></pre>
<p>이렇게 입력항목이 다른 동일한 이름의 메서드를 만들 수 있는데 이를 메서드 오버로딩이라고 한다.</p>
<p>&nbsp;</p>
<h2 id="상속-inheritance">상속 (Inheritance)</h2>
<hr>
<p>A 클래스의 기능을 이어받으면서 확장하는 B 클래스를 만들고 싶다면 어떻게 해야 할까?
A 클래스를 복사, 붙여넣기한 뒤 코드를 잇는 대신, <strong>&#39;상속&#39;</strong> 기능을 쓰면 된다.
extends 키워드를 이용해 클래스를 상속받으면 부모 클래스의 템플릿을 그대로 가져오면서, 추가로 작성한 변수나 메서드를 추가로 갖게 된다.</p>
<pre><code class="language-java">class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

class Dog extends Animal { // Animal 상속.
    void bark() {
        System.out.println(this.name + &quot;barked!&quot;);
    }
}</code></pre>
<p>Dog 클래스는 Animal 클래스를 상속하므로 &quot;<code>Dog</code> is a(n) <code>Animal</code>&quot; 이라고 할 수 있다. 이런 관계를 Java에서는 IS-A 관계라고 하며,</p>
<pre><code class="language-java">Animal dog = new Dog();</code></pre>
<p>와 같이 작성할 수 있다. 하지만 이 경우 객체 <code>dog</code>는 <code>Animal의 객체</code>이기 때문에 bark 메서드를 호출할 수 없다.</p>
<pre><code class="language-java">Dog dog = new Animal(); // 이렇게는 할 수 없다!</code></pre>
<p>한편 자식 클래스에서 부모 클래스에 있는 메서드와 같은 이름과 매개변수의 메서드를 작성하는 것을 메서드 오버라이딩이라고 한다. 자식 클래스의 객체는 오버라이딩된 메서드를 실행한다.</p>
<pre><code class="language-java">class HouseDog extends Animal { // Dog 상속.
    void bark() { // 메서드 오버라이딩
        System.out.println(this.name + &quot;barked in house!&quot;);
        // HouseDog의 객체에서 bark 메서드를 부르면 이 메서드를 실행한다.
    }
}
</code></pre>
<h4 id="--다중-상속">- 다중 상속</h4>
<p>Java에서는 다중 상속을 지원하지 않는다. 여러 부모 클래스들 중에 같은 이름과 매개변수를 가진 메서드가 있을 경우의 불명확함을 제거하기 위해서이다. (다른 언어의 경우에는 우선순위 적용 등의 방법을 사용한다.)</p>
<p>&nbsp;</p>
<h2 id="생성자-constructor">생성자 (Constructor)</h2>
<hr>
<p>생성자는 객체가 생성될 때 호출되는 메서드로, 메서드명이 클래스명과 동일하고 리턴 자료형을 정의하지 않는다.
생성자 역시 메서드처럼 오버로딩이 가능하다. 아래와 같이 작성할 수 있다.</p>
<pre><code class="language-java">class Animal {
    String name;
    int age;


    Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
     //생성자 내부에서도 생성자 호출이 가능하다. this로 호출한다.
    Animal(String name) { this(name, 10); }
    Animal(int age) { this(&quot;dog&quot;, age); }

}</code></pre>
<p>생성자가 없을 경우에는 아무것도 받지 않고 아무것도 수행하지 않는 디폴트 생성자를 컴파일러가 자동으로 추가한다. 하지만 위와 같이 작성된 경우 디폴트 생성자는 만들어지지 않는다. 따라서 Animal의 객체를 만들 때에는 반드시 name이나 age 혹은 둘 모두를 전달해야만 한다. <code>Animal dog = new Animal();</code> 처럼은 작성할 수 없다.</p>
<p>&nbsp;</p>
<h2 id="추상클래스와-인터페이스">추상클래스와 인터페이스</h2>
<hr>
<p>위에서 우리는 같은 틀을 가지지만 다른 정보를 담는 객체들을 찍어내기 위해 클래스라는 템플릿을 만들어서 사용했다. 하지만 만약 틀 자체도 약간씩 다른 객체들을 찍어내야 한다면 어떻게 해야 할까?
키보드를 만들어야 한다고 가정해 보자. 납품해야 하는 키보드들은 굉장히 비슷하지만 구조나 기능이 약간씩 다르다. 설계도가 90% 정도는 동일하지만, 10% 정도의 바리에이션이 존재하는 경우이다. 그렇다면 90% 정도의 미완성 설계도를 공유하고, 나머지만 다르게 만들면 되지 않겠는가? 이런 프로그래밍이 필요할 때 우리는 <strong>추상클래스</strong> 혹은 <strong>인터페이스</strong>를 사용하게 된다.</p>
<h3 id="추상클래스-abstract-class">추상클래스 (Abstract Class)</h3>
<hr>
<p>추상클래스는 키워드 abstract를 붙여서 만들 수 있고, 객체 생성이 불가능하다. 객체를 생성하려면 반드시 상속을 통해 구현한 클래스부터 생성해야 한다. 추상클래스는 일반 클래스를 상속받아 작성될 수 있다.</p>
<pre><code class="language-java">abstract class AbsClass {
    abstract String getHello();
    void sayHi() {
        System.out.println(&quot;Hi!&quot;);
    }
}</code></pre>
<p>추상클래스는 완성된 부분도 있지만 아무튼 미완성인 설계도와 같다.
클래스의 기능도 갖고 있으면서 아래 기술할 인터페이스의 역할도 갖고 있는 클래스이다.</p>
<p>&nbsp;</p>
<h3 id="인터페이스-interface">인터페이스 (Interface)</h3>
<hr>
<p>인터페이스를 사용하면 개발시간을 단축할 수 있고, 표준화가 가능하며, 서로 관계없는 클래스들에게 관계를 설정해줄 수 있으며 독립적인 프로그래밍이 가능해진다.
인터페이스는 추상클래스보다 조금 인터페이스의 모든 멤버변수는 public static final이고 생략가능하다.
또한 모든 메서드는 public abstract이고 생략가능하다.
JDK 1.8 (Java 8) 부터는 static 메서드와 default 메서드를 예외로 작성할 수 있다.
디폴트 메서드를 사용하면 구현된 메서드를 작성해둘 수 있고, 스태틱 메서드를 사용하면 일반 클래스의 스태틱 메서드를 사용하는 것과 동일하게 사용할 수 있다.</p>
<pre><code class="language-java">interface AInterface {
    void aMethod(int a);
}

interface BInterface {
    void bMethod(String str);
}</code></pre>
<p>인터페이스는 인터페이스를 상속받을 수 있고 다중상속이 가능하다.</p>
<pre><code class="language-java">interface ABInterface extends AInterface, BInterface { }</code></pre>
<p>인터페이스를 구현할 때에는 인터페이스에 정의된 모든 추상 메서드를 구현해야 하고, 일부만 구현할 경우에는 추상 클래스로 선언해야 한다.
또한 상속과 구현을 동시에 할 수도 있다.</p>
<pre><code class="language-java">class ExClass extends ParentClass implements AVInterface {
    public void aMethod(int a) { 구현; }
    public void bMethod(String str) { 구현; }
}</code></pre>
<p>&nbsp;</p>
<blockquote>
<p>인터페이스에 디폴트 메서드가 추가되면서 추상 클래스와의 차이점이 살짝 모호해졌지만, 추상 클래스는 인터페이스와 달리 객체변수, 생성자, private 메서드를 가질 수 있다.</p>
</blockquote>
<p>&nbsp;</p>
<p>인터페이스는 그 인터페이스를 구현한 클래스가 존재할 때, 매개변수의 타입으로 사용될 수 있다.</p>
<pre><code class="language-java">    void callInterface(AInterface a) { ...</code></pre>
<p>매개변수의 타입으로 사용된 인터페이스는 <strong>해당 인터페이스가 구현된 클래스의 인스턴스를 넘겨준다.</strong>
또한 메서드의 리턴타입으로 인터페이스를 지정할 수도 있다. <strong>리턴타입이 인터페이스라는 것은, 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미</strong>한다.</p>
<p>&nbsp;</p>
<h2 id="다형성-polymorphism">다형성 (Polymorphism)</h2>
<hr>
<p>하나의 객체가 여러 자료형 타입을 가질 수 있는 것을 다형성이라고 한다. 물론, 이는 상속 관계가 존재하기에 가능한 특징이다. 그렇다면 다형성은 어떤 의미를 가질까?
이는 메서드가 실행 시점에 성격이 결정되는 동적 바인딩을 이용해, 상속 관계에 있는 클래스에서 &quot;부모 클래스가 오버라이딩을 통해 자식 클래스의 메서드를 호출할 수 있음&quot;을 의미한다.</p>
<blockquote>
<p>부모 클래스는 자식 클래스가 뭘 하는지 알 수 없다. 그럼에도 자식 클래스의 메서드를 가져다 쓸 수 있다!</p>
</blockquote>
<p>프로그램의 컴파일 시점에는 부모 클래스는 자신의 멤버 메서드에밖에 접근할 수 없다. 하지만 실행 시점에는 자식 클래스의 메서드를 실행시킬 수 있게 되는 것이다.
다형성은 <code>메소드 오버라이딩이 이루어진 상속 관계</code>에서, 자식 클래스의 객체를 부모 클래스로 <code>업캐스팅</code>했을 때 성립한다. 여러 객체를 하나의 타입으로 관리할 수 있어 코드의 유지보수가 용이해지고, 재사용성이 좋아지며 클래스 간 의존성이 줄어들어 안전성이 높아진다.</p>
<pre><code class="language-java">// 상속 관계 클래스
class Food {
    public String name;
    Food(String name) { this.name = name; }
    void eat(){
        System.out.println(name + &quot; 냠냠&quot;);
    }
}

class Cookie extends Food {
    public String name;
    Cookie(String name) { this.name = name; }
        void eat(){ // 오버라이드
        System.out.println(name + &quot; 바삭바삭&quot;);
    }
}

...

Food a = new Cookie(&quot;빠다코코넛&quot;);
a.eat(); // 빠다코코넛 바삭바삭 출력됨</code></pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>여러분은 아마도 오늘 읽은 내용으로부터 곧 아래 코드를 보게 될 것이다.</p>
<blockquote>
<pre><code class="language-java">Map&lt;String, String&gt; map = new HashMap&lt;&gt;();</code></pre>
</blockquote>
<p>```</p>
<p>&nbsp;</p>
<hr>
<p><em>이 글은 <a href="https://wikidocs.net/book/31">점프 투 자바</a>와 <a href="http://www.yes24.com/Product/Goods/24259565">자바의 정석</a>을 읽고 스터디한 글입니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 제어문]]></title>
            <link>https://velog.io/@yonny_k/Java-%EC%A0%9C%EC%96%B4%EB%AC%B8</link>
            <guid>https://velog.io/@yonny_k/Java-%EC%A0%9C%EC%96%B4%EB%AC%B8</guid>
            <pubDate>Sun, 16 Oct 2022 23:35:41 GMT</pubDate>
            <description><![CDATA[<h2 id="if">IF</h2>
<p>여러분 모두가 이미 알고 있듯.</p>
<pre><code class="language-java">if (cond1) {
// cond = true, exec this
} else (cond2) {
// cond1 = false and cond2 = true, exec this
} else {
// nothing&#39;s true!
}</code></pre>
<p>조건의 경우에는 당연히 비교연산자를 쓸 수 있으며 boolean 타입 변수나 메소드가 될 수도 있고, &amp;&amp;(and), ||(or) 과 같은 연산자를 붙이며 무한으로 길어질 수도 있다.</p>
<p>&nbsp;</p>
<hr>
<h2 id="switchcase">switch/case</h2>
<p>선택지가 정형화되고 여러개인 케이스에서 유리하다. if와 else if...로 잔뜩 길어진 코드보다 가독성이 뛰어나지만, 모든 if else 구조의 조건문을 switch/case 문으로 바꿀 수는 없다. break를 잊지 말자 - break하지 않으면 성립된 조건으로부터 break를 만날 때까지 모두 실행해 버린다.</p>
<pre><code class="language-java">int a = 3;
int b = 2;
String operator = &quot;+&quot;;
int ans = 0;

switch (operator) {
    case &quot;+&quot;:    ans = a+b;
                 break;
    case &quot;-&quot;:    ans = a-b;
                 break;
    case &quot;*&quot;:    ans = a*b;
                 break;
    case &quot;/&quot;:    ans = a/b;
                 break;
    case &quot;%&quot;:    ans = a%b;
                 break;
    default:    ans = 0;
                System.out.println(&quot;Wrong Operator!&quot;);
                 break;</code></pre>
<p>&nbsp;</p>
<hr>
<h2 id="while">while</h2>
<p>조건문이 참인 동안 반복해서 수행한다.
while (true) 를 설정하면 무한반복해서 수행하게 된다. break가 없는 이상 어플리케이션 강제 종료 커맨드 (Ctrl+C, IDE별 종료버튼 등...)를 입력하지 않는 한 멈추지 않는다.
while문 내부에 break; 를 설정하면, while문을 강제종료할 수 있다.</p>
<pre><code class="language-java">int hair = 20;
while (true) {
    System.out.println(&quot;머리가 &quot; + hair-- + &quot; 가닥 남았네요.&quot;);
    if (hair == 0) {
        System.out.println(&quot;당신은 이제 대머리입니다.&quot;);
        break;
    }
}</code></pre>
<p>또, while문 내부에서 continue;를 만나면 그 아래를 수행하지 않고 while문 가장 위로 돌아가 다시 수행한다.</p>
<p>한 번은 무조건 실행한 다음 조건을 체크하는 do while문도 존재하지만, 잘 사용되지 않는다.</p>
<pre><code class="language-java">do {
    실행할 문장;
} while (조건); // 세미콜론이 붙는다.</code></pre>
<p>&nbsp;</p>
<hr>
<h2 id="for">for</h2>
<p>가장 많이 사용되는 반복문이다.</p>
<pre><code class="language-java">for (초기치; 조건문; 증가치){ ... }</code></pre>
<p>조건문이 true일 경우 계속해서 수행한다.
첫 수행에는 초기치 그대로 수행한 다음, 매 수행 시마다 &#39;증가치&#39;를 수행한 다음 수행한다.
<em>(for 문에서 뭔가 걸려 문제가 된다면 꼭 for 내의 세미콜론을 잘 적었는지 확인해 보자... 잘 안 보인다...)</em></p>
<p>for문에서 역시 continue; 를 쓸 수 있다. continue;를 만나면 아래를 수행하지 않고 다음으로 넘어간다. break; 역시 마찬가지로 만나면 멈춘다.</p>
<h3 id="for-each">for each</h3>
<p>배열이나 리스트와 같은 여러 개의 값을 가진 자료형을 이용해, 그 요소 하나하나에 대해 전부 루프를 수행하도록 할 수 있는 아주 편리한 방법이다. 기존 for에서 조건문을 조금 다르게 설정하면 된다.</p>
<pre><code class="language-java">String[] names = {&quot;Mina&quot;, &quot;Sana&quot;, &quot;Momo&quot;};
for(String name : names) {
    System.out.println(name);
}</code></pre>
<p>&nbsp;
&nbsp;</p>
<hr>
<p><em>이 글은 <a href="https://wikidocs.net/book/31">점프 투 자바</a>를 읽고 스터디한 글입니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Data types 2]]></title>
            <link>https://velog.io/@yonny_k/Java-Data-types-2</link>
            <guid>https://velog.io/@yonny_k/Java-Data-types-2</guid>
            <pubDate>Sun, 16 Oct 2022 23:34:46 GMT</pubDate>
            <description><![CDATA[<h3 id="array">Array</h3>
<p>배열은 길이를 변경할 수 없으므로 고려해서 작성한다.</p>
<pre><code class="language-java">int[] odds = {1, 3, 5, 7, 9};
String[] names = new String[5];
// 초기값 없는 배열 선언 시에는 길이를 반드시 설정
String[] weeks = {&quot;월&quot;, &quot;화&quot;, &quot;수&quot;, &quot;목&quot;, &quot;금&quot;, &quot;토&quot;, &quot;일&quot;};
String monday = String[0]; // 배열 접근
int week = weeks.length; // week = 7</code></pre>
<p>&nbsp;</p>
<hr>
<h3 id="list">List</h3>
<p>List는 인터페이스로, 이를 구현한 자료형으로 ArrayList, Vector, LinkedList 등이 있다.
배열과 유사하지만, 크기가 동적으로 변한다.</p>
<h4 id="arraylist">ArrayList</h4>
<pre><code class="language-java">import java.util.ArrayList;</code></pre>
<p>ArrayList 사용을 위해서는 import가 필요하다.</p>
<pre><code class="language-java">ArrayList&lt;String&gt; names = new ArrayList&lt;&gt;();
names.add(&quot;Mina&quot;);        // Mina
names.add(&quot;Jisu&quot;);        // Mina, Jisu
names.add(0, &quot;Yeon&quot;);    // Yeon, Mina, Jisu

String thirdName = names.get(2); // Jisu</code></pre>
<p>이 외에도 size, contains, remove 등의 메소드가 있다.
또한 이미 존재하는 배열을 ArrayList로 변환할 수도 있다.</p>
<p>Arrays의 메소드를 사용하기 위해서는
&nbsp;</p>
<pre><code class="language-java">import.java.util.Arrays;</code></pre>
<pre><code class="language-java">String[] data = {&quot;Mina&quot;, &quot;Jisu&quot;, &quot;Yeon&quot;};
ArrayList&lt;String&gt; names = new ArrayList&lt;&gt;(Arrays.asList(data));</code></pre>
<p>String.join을 이용해 각 요소 사이 원하는 구분자를 추가해 하나의 문자열로 만들 수 있다.</p>
<pre><code class="language-java">ArrayList&lt;String&gt; heights = new ArrayList&lt;&gt;(Arrays.asList(&quot;155&quot;, &quot;170&quot;, &quot;192&quot;));
String result = String.join(&quot;,&quot;, heights); // 155,170,192</code></pre>
<p>리스트의 sort 메소드를 사용하면 각 요소를 순서대로 정렬하는 것도 가능하다.</p>
<pre><code class="language-java">import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;

public class Example {
    public static void main(String[] args) {
        ArrayList&lt;String&gt; heights = new ArrayList&lt;&gt;(Arrays.asList(&quot;155&quot;, &quot;170&quot;, &quot;192&quot;);
        heights.sort(Comparator.naturalOrder()); // 오름차순 정렬
        heights.sort(Comparator.reverseOrder()); // 내림차순 정렬
    }
}</code></pre>
<p>&nbsp;</p>
<hr>
<h3 id="map">Map</h3>
<p>데이터셋을 전달할 때, Key : Value 형식이 요구되는 경우가 종종 발생한다.
Map 구조는 이러한 대응관계를 쉽게 표현할 수 있도록 한다.
리스트나 배열처럼 순서에 따라 요소의 값을 가져오지 않고, key를 이용하게 된다.
Map 역시 인터페이스로 HashMap, LinkedHashMap_(Sequential)<em>, TreeMap</em>(저장과 동시에 오름차순 정렬)_ 등으로 구현되어 있다.</p>
<h4 id="hashmap">HashMap</h4>
<pre><code class="language-java">import java.util.HashMap;

public class Example {
    public static void main(String[] args) {
        HashMap&lt;String, String&gt; map = new HashMap&lt;&gt;();
        map.put(&quot;name&quot;, &quot;YEON&quot;);
        map.put(&quot;height&quot;, &quot;200&quot;);
        System.out.println(map.get(&quot;name&quot;));
        System.out.println(&quot;wrong height value : &quot; + map.remove(&quot;height&quot;));
    }
}    </code></pre>
<p>&nbsp;</p>
<hr>
<h3 id="set">Set</h3>
<p>집합을 표현하는 자료형으로 Set이 존재한다. 역시 인터페이스로, HashSet, LinkedHashSet, TreeSet 등이 존재한다.
Set 자료형은 집합을 표현하는 것, 즉 값의 중복을 허용하지 않는다. 따라서 필터로도 사용될 수 있다.</p>
<pre><code class="language-java">import java.util.Arrays;
import java.util.HashSet;

public class Example {
    public static void main(String[] args) {
        HashSet&lt;String&gt; set1 = new HashSet&lt;&gt;(Arrays.asList(&quot;A&quot;, &quot;b&quot;, &quot;c&quot;, &quot;c&quot;)); // A, b, c
        set1.add(&quot;x&quot;); // x 추가
        HashSet&lt;String&gt; set2 = new HashSet&lt;&gt;(Arrays.asList(&quot;A&quot;, &quot;B&quot;, &quot;C));
        HashSet&lt;String&gt; intersection = new HashSet&lt;&gt;(set1);
        intersection.retainAll(set2); // 교집합 -&gt; &quot;A&quot;
    }
}    </code></pre>
<p>이 외에도 addAll(합집합 또는 여러 값 추가), remove, removeAll(차집합) 등의 메소드가 있다.</p>
<p>&nbsp;</p>
<hr>
<h3 id="enum">Enum</h3>
<p>Enum은 상수 집합으로, 관련이 있는 상수들의 집합을 저장한다.</p>
<pre><code class="language-java">public class Pay {
    public final static Pay CARD = new Pay();
    public final static Pay MONEY = new Pay();
    public final static Pay SMARTPAY = new Pay();
}
// ------------------- //
public enum Pay {
    CARD, MONEY, SMARTPAY;
}</code></pre>
<p>위와 같이 코드를 간결하게 하면서 가독성을 좋게 하고, 인스턴스 생성과 상속을 방지할 수 있다. 또한 enum임을 명시하여 구현의 의도를 바로 파악할 수 있다. 이를 활용하여 특정 상황에서 데이터 관리를 DB 대신 코드 내에서 수행하게 하는 등의 활용이 가능하다. 기본적으로 직렬화가 가능한 타입이기 때문에 싱글톤을 구현하는 데 있어 좋은 방법으로 사용될 수 있다.</p>
<p>&nbsp;
&nbsp;</p>
<hr>
<h3 id="형변환과-final">형변환과 final</h3>
<pre><code class="language-java">String aStr = &quot;123&quot;;
int aInt = Interger.parseInt(aStr);

int bInt = 123;
String bStr1 = &quot;&quot; + bInt;
String bStr2 = String.valueOf(bInt);
String bStr3 = Integer.toString(bInt);

String cStr = &quot;12.34&quot;;
double cDouble = Double.parseDouble(cStr);
int cInt = (int) cDouble; //타입캐스팅 필요
double d = cInt; // 정수-&gt;실수에는 타입캐스팅 요구되지 않음</code></pre>
<p>final 키워드를 설정하면 자료형에 값을 단 한 번만 설정할 수 있도록 해 수정이 불가능하도록 만든다.</p>
<p>&nbsp;
&nbsp;</p>
<hr>
<p><em>이 글은 <a href="https://wikidocs.net/book/31">점프 투 자바</a>를 읽고 스터디한 글입니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Data types 1]]></title>
            <link>https://velog.io/@yonny_k/Java-Data-types</link>
            <guid>https://velog.io/@yonny_k/Java-Data-types</guid>
            <pubDate>Sun, 16 Oct 2022 22:57:52 GMT</pubDate>
            <description><![CDATA[<p>&nbsp;</p>
<h2 id="자료형">자료형</h2>
<hr>
<h3 id="숫자">숫자</h3>
<blockquote>
<h4 id="정수">정수</h4>
<p> int (-2147483648 ~ 2147483647)
long (-9223372036854775808 ~ 9223372036854775807)</p>
</blockquote>
<pre><code class="language-java">int intData = 10;
long longData = 2147483648L;</code></pre>
<blockquote>
<h4 id="실수">실수</h4>
<p>float (-3.4x10^38 ~ 3.4x10^38)
double (-1.7x10^308 ~ 1.7x10^308)</p>
</blockquote>
<pre><code class="language-java">float pi = 3.14F;
double longPi = 3.1415926535897932384616;
double d1 = 123.4;
double d2 = 1.234e2;</code></pre>
<blockquote>
<h4 id="진수">진수</h4>
</blockquote>
<pre><code class="language-java">int octal = 023; // 19
int hex = 0xC;  // 12</code></pre>
<blockquote>
<h4 id="연산">연산</h4>
<p>더하기 +, 빼기 -, 곱하기 *, 나누기 /, 나머지 %
증감연산 i++ / ++i</p>
</blockquote>
<p>&nbsp;</p>
<hr>
<h3 id="boolean">boolean</h3>
<h4 id="불-자료형">불 자료형</h4>
<p>true or false</p>
<pre><code class="language-java">boolean isTrue = true;
boolean isTall = height &gt; base;
System.out.println(isTall);  // true or false 출력됨</code></pre>
<p>&nbsp;</p>
<hr>
<h3 id="문자">문자</h3>
<h4 id="char">char</h4>
<pre><code class="language-java">char a1 = &#39;a&#39;;
char a2 = 97; // 아스키코드
char a3 = &#39;\u0061&#39;; // 유니코드</code></pre>
<p>&nbsp;</p>
<hr>
<h3 id="문자열">문자열</h3>
<h4 id="string">String</h4>
<pre><code class="language-java">String a = &quot;Hello java&quot;;</code></pre>
<p>String 자료형은 또한 다양한 내장 메소드를 갖는다.
equals, indexOf, contains, chatAt, replaceAll...
한편, 내장 메소드에 따라 프로그램 실행 중 NullPointerException의 발생 우려와 같은 고려사항이 존재하므로 별도의 유틸 함수 사용 등이 요구될 수 있다.</p>
<h4 id="문자열-포매팅">문자열 포매팅</h4>
<p>C와 같은 다른 언어에서도 그렇듯, System.out.println등을 사용할 때 다른 문자열, 정수를 가져오거나 하는 등의 표현을 위해서는 포매팅이 요구되며 아래와 같이 사용한다.</p>
<blockquote>
</blockquote>
<p>%s : 문자열
%c : 문자
%d : 정수
%f : 부동소수
%o, %x : 8진수, 16진수
%% : %</p>
<p>%.4f로 소수점 아래 네 자리까지만 표현하는 등의 표현도 가능하다.
또한 String.format 메소드를 이용해 포매팅된 문자열을 리턴받을 수도 있다.</p>
<h4 id="stringbuffer">StringBuffer</h4>
<p>문자열을 추가하거나 변경할 때 사용하는 자료형이다.</p>
<pre><code class="language-java">StringBuffer sb = new StringBuffer();
sb.append(&quot;hello&quot;);
sb.append(&quot; java&quot;);
sb.insert(0, &quot;yeon: &quot;);
System.out.println(sb.toString()); // yeon: hello java 출력
System.out.println(sb.subString(0, 4)); // yeon 출력</code></pre>
<p>한편 String에도 + 연산으로 문자열을 추가할 수 있는데, 그 경우에는 + 연산이 있을 때마다 새로운 String 객체가 생성된다. String 자료형은 immutable하여 다양한 메소드를 통해 내용을 바꿀 때마다 전부 새로운 String이 생성되는 것이지 값이 변경되는 것이 아니기 때문이다.
StringBuffer 자료형은 mutable하다는 특징을 갖지만, 그냥 String보다 무거운 편이기 때문에 문자열 추가/변경의 작업이 많은 경우에 사용하는 것이 유리하다.
유사한 자료형으로 StringBuilderㅏ가 존재하는데 StringBuffer는 멀티 스레드 환경에서 유리하고 StringBuilder는 보다 성능이 낫다는 장점이 있어 동기화를 고려하지 않을 때는 StringBuilder를 사용하는 것이 좋다.</p>
<hr>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2 id="primitive-자료형">primitive 자료형</h2>
<hr>
<p>앞서 살펴본 int, char 등의 자료형은 원시 자료형으로 구분된다.
이런 자료형들은 아래와 같이 리터럴로만 값 세팅이 가능하며, new 키워드로 생성할 수 없다.</p>
<pre><code class="language-java">int a = 1;</code></pre>
<p>한편 String의 경우에는 아래와 같은 표현이 가능하다.</p>
<pre><code class="language-java">String str1 = &quot;literal&quot;;
String str2 = new String(&quot;non-literal!&quot;);</code></pre>
<p>String은 리터럴 표현식을 사용할 수 있도록 자바에서 특별히 제공되는 자료형이기에 위와 같은 표현이 가능하지만, 그 외의 원시 자료형들은 new로 생성할 수 없다.
int, long과 같은 원시 자료형들은 아래와 같이 각각 별도의 Wrapper 클래스를 가진다.</p>
<blockquote>
<p>int - Integer
long - Long
double - Double
...</p>
</blockquote>
<p>ArrayList, HashMap과 같은 형식으로 데이터를 저장하는 경우 원시 자료형 대신 Wrapper 클래스를 사용해야 한다. Wrapper 클래스를 사용하면 값 대신 객체를 주고 받을 수 있어 OOP에 유리하다. 또한 멀티스레딩 환경의 동기화 지원을 위해서는 반드시 Wrapper 클래스를 사용해야 한다.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<hr>
<p><em>이 글은 <a href="https://wikidocs.net/book/31">점프 투 자바</a>를 읽고 스터디한 글입니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] about java]]></title>
            <link>https://velog.io/@yonny_k/Java-about-java</link>
            <guid>https://velog.io/@yonny_k/Java-about-java</guid>
            <pubDate>Sun, 16 Oct 2022 22:39:40 GMT</pubDate>
            <description><![CDATA[<h1 id="java의-특징">Java의 특징</h1>
<p>&nbsp;</p>
<h3 id="객체-지향적">객체 지향적</h3>
<hr>
<p>Java는 객체 지향 프로그래밍_(OOP, Object Oriented Programming)_을 가능하게 하는 객체 지향 언어이다. 숫자나 논리값을 제외한 거의 모든 것들이 <strong>객체</strong>로 구성되어 있으며, 실제로 Object 클래스로부터 모든 클래스를 파생한다. 또 캡슐화, 상속, 다형성의 구현을 지원하고 있다. 때문에 코드 재사용 및 유지보수, 업그레이드, 디버깅을 비교적 쉽게 할 수 있으며 생산성이 높아 많은 곳에서 Java를 사용하고 있다.</p>
<p>&nbsp;</p>
<h3 id="인터프리터-언어">인터프리터 언어</h3>
<hr>
<p>Java는 컴파일 언어인 동시에 인터프리터 언어로, 텍스트 소스를 컴파일<em>(javac.exe)_하여 이진 클래스 파일로 만든 다음 자바 런타임이 클래스 파일을 인터프리트하며 실행</em>(java.exe)<em>하게 된다. 따라서 JRE</em>(Java Runtime Environment)<em>만 설치되어 있다면 OS에 관계없이 어디서든 실행할 수 있어 플랫폼에 대해 독립적인 특징</em>(Platform independent)_을 갖는다.</p>
<p>&nbsp;</p>
<h3 id="안전하다">안전하다</h3>
<hr>
<p>Java는 포인터 연산을 지원하지 않아 모든 메모리 접근을 자바 시스템이 관리하고 제한한다. 또한 예외 핸들링을 하여 시스템 붕괴의 위험이 없다. 객체 생성 시 Java는 자동적으로 메모리 영역을 찾아 할당하고, 사용이 종료되면 GC_(Garbage Collector)_를 실행시켜 자동적으로 메모리를 관리한다. 또한 유형의 정의가 강고하여 실행 전에 클래스 파일을 이용한 프로그램의 검사가 가능하다. Java는 프로그램 작성 시 자료형 타입에 굉장히 민감하여 일단 컴파일만 성공한다면 실행 시 오류가 발생하는 경우가 비교적 적다. 이런 제약은 코드를 명확하게 작성할 수 있도록 만들어 준다.</p>
<p>&nbsp;</p>
<h3 id="멀티-쓰레딩-지원">멀티 쓰레딩 지원</h3>
<hr>
<p>멀티쓰레드를 이용하면 하나의 프로그램 단위로 동일한 쓰레드를 동시에 수행할 수 있게 된다. Java는 멀티 프로세서 하드웨어를 지원하도록 설계되어 있으며, 스레드 생성 및 제어와 관련된 라이브러리 API를 제공하여 멀티스레드를 쉽게 구현할 수 있다.</p>
<p>&nbsp;</p>
<h3 id="동적-로딩">동적 로딩</h3>
<hr>
<p>Java 인터페이스는 모든 인스턴스 변수와 툴의 실행문을 배제한 채 객체 간의 상호작용을 정의하고 있어 하나의 모듈을 갱신할 때 다른 모듈을 모두 갱신할 필요가 없다. 즉, 어플리케이션을 실행할 때 모든 객체를 즉시 생성하지 않고 필요할 때 동적으로 로드하여 생성하기 때문에 유지보수 및 디버깅 시 전체 프로그램을 다시 컴파일하는 대신 해당 클래스만 수정하면 된다는 장점을 갖는다.</p>
<p>&nbsp;</p>
<h3 id="함수적-프로그래밍-지원">함수적 프로그래밍 지원</h3>
<hr>
<p>대용량 데이터 병렬 처리와 이벤트 지향 프로그래밍에는 함수적 프로그래밍이 적합한데, Java 8부터 함수적 프로그래밍을 위한 람다식을 지원하고 있다. 람다식을 사용하면 컬렉션 요소 필터링, 매핑, 집계가 쉬워지며 코드가 간결해진다.</p>
<p>&nbsp;</p>
<h3 id="다양한-오픈소스-라이브러리">다양한 오픈소스 라이브러리</h3>
<hr>
<p>Java는 매우 광범위하게 사용되고 있으며, 그 자체가 오픈소스 언어이기도 하다. 때문에 apache와 같은 다양한 오픈소스 라이브러리가 제공되고 있어 프로그램 개발 시간을 단축하면서 높은 안정성을 가진 프로그램 개발이 가능하다.</p>
<p>&nbsp;</p>
<h3 id="비교적-느린-속도">비교적 느린 속도</h3>
<hr>
<p>Java는 JVM에 의해 이진 파일로 번역된 후에 실행하는 과정을 거쳐야 하므로 C, C++에 비해서는 속도가 느리다. 하지만 전반적 하드웨어 기술 발전 및 JIT 컴파일러와 같은 기술 적용으로 JVM의 성능이 향상되어 큰 격차가 나진 않는다.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<hr>
<p><em>이 글은 <a href="https://wikidocs.net/book/31">점프 투 자바</a>를 읽고 스터디한 글입니다.</em></p>
]]></description>
        </item>
    </channel>
</rss>