<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Beemo 개발 블로그</title>
    <link>https://devsign-blog.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 27 Jun 2026 22:20:39 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Beemo_</managingEditor>
    <item>
      <title>카카오 sdk v2 굳이 자바로 사용하기 -2 (카카오 링크 메시지)</title>
      <link>https://devsign-blog.tistory.com/entry/%EC%B9%B4%EC%B9%B4%EC%98%A4-sdk-v2-%EA%B5%B3%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%A1%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-2-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EB%A7%81%ED%81%AC-%EB%A9%94%EC%8B%9C%EC%A7%80</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://www.beemo.co.kr/12&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[개발/Android] - 카카오 sdk v2 굳이 자바로 사용하기 -1 (카카오 로그인)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;전 포스팅 로그인에 이어서 카카오 메시지 보내는 방법을 자바 코드로 작성하였습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. kotlin으로 카카오 링크 메시지 보내기&lt;/p&gt;
&lt;pre id=&quot;code_1613796003979&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class KakaoLink {

    companion object {
        @JvmStatic
        val instance by lazy { KakaoUtil() }
    }
    fun kakaoLink(context : Context) {

        val defaultFeed = FeedTemplate(
                content = Content(
                        title = &quot;타이틀&quot;,
                        description = &quot;메시지 내용&quot;,
                        imageUrl = &quot;이미지 경로&quot;,
                        link = Link(
                                webUrl = &quot;웹 링크&quot;,
                                mobileWebUrl = &quot;모바일 링크&quot;
                                androidExecParams = mapOf(&quot;1&quot; to &quot;안드로이드 폰 링크&quot;),
                                iosExecParams = mapOf(&quot;1&quot; to &quot;ios 폰 링크&quot;)
                        )
                )
        )
        LinkClient.instance.defaultTemplate(context, defaultFeed) { linkResult, error -&amp;gt;
            if (error != null) {
                Log.e(&quot;TAG&quot;, &quot;카카오링크 보내기 실패&quot;, error)
            }
            else if (linkResult != null) {
                context.startActivity(linkResult.intent)

                // 카카오링크 보내기에 성공했지만 아래 경고 메시지가 존재할 경우 일부 컨텐츠가 정상 동작하지 않을 수 있습니다.
                Log.w(&quot;TAG&quot;, &quot;Warning Msg: ${linkResult.warningMsg}&quot;)
                Log.w(&quot;TAG&quot;, &quot;Argument Msg: ${linkResult.argumentMsg}&quot;)
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2. Java로 카카오 링크 메시지 보내기&lt;/p&gt;
&lt;pre id=&quot;code_1613796242753&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class TestKakaoMsg {

    public void kakaoLink(Context context) {
        /**
         * new Link() : 파라미터 순서대로 webLink, mobileLink, androidLink, iosLink
         */
        FeedTemplate feedTemplate = new FeedTemplate(new Content(&quot;title&quot;,&quot;imageUrl&quot;,    //메시지 제목, 이미지 url
                new Link(&quot;https://www.naver.com&quot;),&quot;description&quot;,                    //메시지 링크, 메시지 설명
                300,300));                                                     //이미지 사이즈

        LinkClient.getInstance().defaultTemplate(context, feedTemplate,null,new Function2&amp;lt;LinkResult, Throwable,Unit&amp;gt;() {
            @Override
            public Unit invoke(LinkResult linkResult, Throwable throwable) {
                if (throwable != null) {
                    Log.e(&quot;TAG&quot;, &quot;카카오링크 보내기 실패&quot;, throwable);
                }
                else if (linkResult != null) {
                    context.startActivity(linkResult.getIntent());

                    // 카카오링크 보내기에 성공했지만 아래 경고 메시지가 존재할 경우 일부 컨텐츠가 정상 동작하지 않을 수 있습니다.
                    Log.w(&quot;TAG&quot;, &quot;Warning Msg: &quot;+ linkResult.getWarningMsg());
                    Log.w(&quot;TAG&quot;, &quot;Argument Msg: &quot;+ linkResult.getArgumentMsg());
                }
                return null;
            }
        });
    }
    
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/Android</category>
      <author>Beemo_</author>
      <guid isPermaLink="true">https://devsign-blog.tistory.com/13</guid>
      <comments>https://devsign-blog.tistory.com/entry/%EC%B9%B4%EC%B9%B4%EC%98%A4-sdk-v2-%EA%B5%B3%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%A1%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-2-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EB%A7%81%ED%81%AC-%EB%A9%94%EC%8B%9C%EC%A7%80#entry13comment</comments>
      <pubDate>Sat, 20 Feb 2021 13:44:33 +0900</pubDate>
    </item>
    <item>
      <title>카카오 sdk v2 굳이 자바로 사용하기 -1 (카카오 로그인)</title>
      <link>https://devsign-blog.tistory.com/entry/%EC%B9%B4%EC%B9%B4%EC%98%A4-sdk-v2-%EA%B5%B3%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%A1%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-1-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EB%A1%9C%EA%B7%B8%EC%9D%B8</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://www.beemo.co.kr/13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[개발/Android] - 카카오 sdk v2 굳이 자바로 사용하기 -2 (카카오 링크 메시지)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;카카오 sdk v2는 코틀린으로 가이드가 나와있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하지만 굳이, 아니면 어쩔 수 없이 자바로 해야되는 분들을 위해 자바로 사용하는 방법을 공유합니다.&lt;/p&gt;
&lt;p&gt;sdk init, 앱 등록, 키발급 같은 내용은 생략합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. kotlin으로 카카오 로그인하기&lt;/p&gt;
&lt;p&gt;- Login 코드&lt;/p&gt;
&lt;pre id=&quot;code_1613795355428&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class KakaoLogin
{
    interface IKLoginResult
    {
        fun onKakaoLoginResult(user: User?)
    }
    var user:User? = null
    var listener:IKLoginResult? = null

    // 로그인 callback 구성
    val callback: (OAuthToken?, Throwable?) -&amp;gt; Unit = { token, error -&amp;gt;

        if (error != null) {
            Log.e(&quot;TAG&quot;, &quot;로그인 실패&quot;, error)
            if(listener != null)
                listener!!.onKakaoLoginResult(null)
        }
        else if (token != null)
        {
            Log.i(&quot;TAG&quot;, &quot;로그인 성공 ${token.accessToken}&quot;)

            UserApiClient.instance.me { user, error -&amp;gt;

                if (error != null)
                {
                    Log.e(&quot;TAG&quot;, &quot;사용자 정보 요청 실패&quot;, error)
                }
                else if (user != null)
                {
                    Log.i(&quot;TAG&quot;, &quot;사용자 정보 요청 성공&quot; +
                            &quot;\n회원번호: ${user.id}&quot; +
                            &quot;\n이메일: ${user.kakaoAccount?.email}&quot; +
                            &quot;\n닉네임: ${user.kakaoAccount?.profile?.nickname}&quot; +
                            &quot;\n프로필사진: ${user.kakaoAccount?.profile?.thumbnailImageUrl}&quot;)

                    this.user = user

                    if(listener != null)
                        listener!!.onKakaoLoginResult(user)
                }
            }
        }
    }
    fun login(context: Context)
    {
        // 카카오톡이 설치되어 있으면 카카오톡으로 로그인, 아니면 카카오계정으로 로그인
        if (LoginClient.instance.isKakaoTalkLoginAvailable(context))
            LoginClient.instance.loginWithKakaoTalk(context, callback = callback)
        else
            LoginClient.instance.loginWithKakaoAccount(context, callback = callback)
    }
 
	//로그아웃
    fun onLink() {
        UserApiClient.instance.unlink { error -&amp;gt;
            if (error != null) {
                Log.e(&quot;TAG&quot;, &quot;연결 끊기 실패&quot;, error)
            }
            else {
                Log.i(&quot;TAG&quot;, &quot;연결 끊기 성공. SDK에서 토큰 삭제 됨&quot;)

            }
        }
    }

    companion object {
        @JvmStatic
        val instance by lazy { KakaoLogin() }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;- activity 코드&lt;/p&gt;
&lt;pre id=&quot;code_1613795445097&quot; class=&quot;kotlin&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class TestKakaoActivityKotlin : AppCompatActivity(), KakaoLogin.IKLoginResult  {

    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)
        setContentView(R.layout.activity_main)
        kakaoLogin()
    }
    private fun kakaoLogin() {
        KakaoLogin.instance.listener = this
        KakaoLogin.instance.login(this)
    }
    override fun onKakaoLoginResult(user: User?) {
        //콜백메서드
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2. Java로 카카오 로그인하기&lt;/p&gt;
&lt;p&gt;- Login 코드&lt;/p&gt;
&lt;pre id=&quot;code_1613795505219&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class TestKakaoLogin {

    interface IKLoginResult{
        void onKakaoLoginResult(User user);
    }
    private static TestKakaoLogin testKakaoLogin = new TestKakaoLogin();
    IKLoginResult listener;
    public void setListener(IKLoginResult listener){
        this.listener = listener;
    }
    public static TestKakaoLogin getInstance() {
        return testKakaoLogin;
    }
    private TestKakaoLogin() {
        if (testKakaoLogin != null)
            throw new AssertionError();
    }
    private Function2&amp;lt;OAuthToken, Throwable, Unit&amp;gt; callback = new Function2&amp;lt;OAuthToken, Throwable, Unit&amp;gt; () {
        @Override
        public Unit invoke(OAuthToken oAuthToken, Throwable throwable) {

            if (throwable != null) {
                Log.e(&quot;error&quot;,throwable.getLocalizedMessage());
            } else if (oAuthToken != null) {
                Log.i(&quot;success&quot;, &quot;로그인 성공&quot;);
                UserApiClient.getInstance().me(new Function2&amp;lt;User, Throwable, Unit&amp;gt;() {
                    @Override
                    public Unit invoke(User user, Throwable throwable) {
                        if (user != null) {
                            listener.onKakaoLoginResult(user);

                        }
                        return null;
                    }
                });
            }
            return null;
        }
    };
    public void login(Context context) {
        if (LoginClient.getInstance().isKakaoTalkLoginAvailable(context)) {
            LoginClient.getInstance().loginWithKakaoTalk(context, callback);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;- activity 코드&lt;/p&gt;
&lt;pre id=&quot;code_1613795593011&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class TestKakaoActivity extends AppCompatActivity implements TestKakaoLogin.IKLoginResult {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        kakaoLogin();

    }
    private void kakaoLogin() {
        TestKakaoLogin.getInstance().setListener(this);
        TestKakaoLogin.getInstance().login(this);
    }
    @Override
    public void onKakaoLoginResult(User user) {
        //콜백메서드
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Android</category>
      <author>Beemo_</author>
      <guid isPermaLink="true">https://devsign-blog.tistory.com/12</guid>
      <comments>https://devsign-blog.tistory.com/entry/%EC%B9%B4%EC%B9%B4%EC%98%A4-sdk-v2-%EA%B5%B3%EC%9D%B4-%EC%9E%90%EB%B0%94%EB%A1%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-1-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EB%A1%9C%EA%B7%B8%EC%9D%B8#entry12comment</comments>
      <pubDate>Sat, 20 Feb 2021 13:38:03 +0900</pubDate>
    </item>
    <item>
      <title>자바 tcp/ip 소켓통신</title>
      <link>https://devsign-blog.tistory.com/entry/%EC%9E%90%EB%B0%94-tcpip-%EC%86%8C%EC%BC%93%ED%86%B5%EC%8B%A0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;소켓 : 두 프로그램이 네트워크를 통해 서로 통신할 수 있도록 양쪽에 생성되는 링크의 단자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소켓이 연결되면 &lt;b&gt;서로 다른 프로세스&lt;/b&gt;끼리 데이터를 전달할 수 있음&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 45.1163%; height: 263px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;서버&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;클라이언트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;socket()&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;socket()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;bind()&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;listen()&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;connect()&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;accept()&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버, 클라이언트는 각각 socket을 생성하고 서버는 bind에서 포트번호를 할당한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후에 listen()을 호출하여 클라이언트의 접속을 기다린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트는 connect()를 통해 서버에 접속을 시도한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 요청이 오면 accept() 함수를 호출에 연결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소켓이 연결되면 recv() / send() 함수를 통해 데이터를 전달하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막에 close()를 호출하여 소켓을 종료한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C프로그래밍에서는 socket() -&amp;gt; bind() -&amp;gt; listen() 함수를 코드에서 직접 호출해줘야 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서는 socket.accept() 메서드만 호출하면 Socket클래스 내부에서 socket() -&amp;gt; bind() -&amp;gt; listen()을 호출해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 소켓통신 예제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 Class&lt;/p&gt;
&lt;pre id=&quot;code_1612588424261&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SocketServer {

    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(11111);

            Socket socket = serverSocket.accept();
            //socket -&amp;gt; bind -&amp;gt; listen socket 클래스 내부에 구현되어있음

            System.out.println(&quot;connect&quot;);
            OutputStream outputStream = socket.getOutputStream();
            for (int i = 0; i &amp;lt; 10; i++) {
                String sendString = &quot;hello&quot;;
                outputStream.write(sendString.getBytes());
            }
            outputStream.write(&quot;exit&quot;.getBytes());
            serverSocket.close();
            socket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 Class&lt;/p&gt;
&lt;pre id=&quot;code_1612588458019&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SocketClient {

    public static void main(String[] args) {
        try {
            Socket socket = new Socket(&quot;localhost&quot;,11111);
            InputStream inputStream = socket.getInputStream();
            while (true) {
                byte[] bytes = new byte[100];
                inputStream.read(bytes);
                String receive = new String(bytes);
                System.out.println(receive);
                if(receive.equals(&quot;exit&quot;)) {
                    break;
                }

            }
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;br /&gt;&lt;b&gt;소켓통신으로 간단한 채팅만&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;들기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;서버 Class&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1612589393167&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SocketServer2 {

    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(11111);

            while(true) {
                Socket socket = serverSocket.accept();

                ReceiveClass receiveClass = new ReceiveClass();
                receiveClass.setSocket(socket);
                SendClass sendClass = new SendClass();
                sendClass.setSocket(socket);

                receiveClass.start();
                sendClass.start();
            }



        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 ReceiveThread&lt;/p&gt;
&lt;pre id=&quot;code_1612589429261&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ReceiveClass extends Thread {

    private Socket socket;
    @Override
    public void run() {
        super.run();

        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String receiveString;

            while(true) {
                receiveString = bufferedReader.readLine();
                if (receiveString == null) {
                    System.out.println(&quot;disconnect&quot;);
                    socket.close();
                    break;
                } else {
                    System.out.println(&quot;상대방 : &quot; + receiveString);
                }
            }
            SocketServer2.main(null);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void setSocket(Socket socket) {
        this.socket = socket;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 SendThread&lt;/p&gt;
&lt;pre id=&quot;code_1612589458754&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SendClass extends Thread {

    private Socket socket;
    @Override
    public void run() {
        super.run();

        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            PrintWriter printWriter = new PrintWriter(socket.getOutputStream());
            String sendString;
            while (true) {
                sendString = bufferedReader.readLine();
                printWriter.println(sendString);
                printWriter.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void setSocket(Socket socket) {
        this.socket = socket;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 Class&lt;/p&gt;
&lt;pre id=&quot;code_1612589500912&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SocketClient {

    public static void main(String[] args) {
        try {
            Socket socket = new Socket(&quot;localhost&quot;,11111);
            ReceiveClientClass receiveClientClass = new ReceiveClientClass();
            receiveClientClass.setSocket(socket);
            SendClientClass sendClientClass = new SendClientClass();
            sendClientClass.setSocket(socket);

            sendClientClass.start();
            receiveClientClass.start();


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;클라이언트 ReceiveThread&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1612589576935&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ReceiveClientClass extends Thread {

    private Socket socket;
    @Override
    public void run() {
        super.run();

        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String receiveString;

            while(true) {
                receiveString = bufferedReader.readLine();
                System.out.println(&quot;상대방 : &quot; + receiveString);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void setSocket(Socket socket) {
        this.socket = socket;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언드 SendThread&lt;/p&gt;
&lt;pre id=&quot;code_1612589599800&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SendClientClass extends Thread {

    private Socket socket;
    @Override
    public void run() {
        super.run();

        try {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
            PrintWriter printWriter = new PrintWriter(socket.getOutputStream());
            String sendString;
            while (true) {
                sendString = bufferedReader.readLine();
                if(sendString.equals(&quot;exit&quot;)) {
                    break;
                }
                printWriter.println(sendString);
                printWriter.flush();
            }
            bufferedReader.close();
            printWriter.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void setSocket(Socket socket) {
        this.socket = socket;
    }
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/Java</category>
      <author>Beemo_</author>
      <guid isPermaLink="true">https://devsign-blog.tistory.com/11</guid>
      <comments>https://devsign-blog.tistory.com/entry/%EC%9E%90%EB%B0%94-tcpip-%EC%86%8C%EC%BC%93%ED%86%B5%EC%8B%A0#entry11comment</comments>
      <pubDate>Sat, 6 Feb 2021 14:33:54 +0900</pubDate>
    </item>
    <item>
      <title>Effective Java 3/E - 싱글턴을 만드는 방법</title>
      <link>https://devsign-blog.tistory.com/entry/Effective-Java-3E-%EC%8B%B1%EA%B8%80%ED%84%B4%EC%9D%84-%EB%A7%8C%EB%93%9C%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
      <description>&lt;p&gt;싱글턴이란 인스턴스를 오직 하나만 생성할 수 있는 클래스&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;싱글턴을 만드는 3가지 방법&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. public static final 방식&lt;/p&gt;
&lt;pre id=&quot;code_1610770997322&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Singleton {
    public static final Singleton INSTANCE = new Singleton();
    
    private Singleton() {}
    public void singletonMethod() {}
    
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;private 생성자는 public static final 필드의 Singleton.INSTANCE를 초기화 할 때 한 번만 호출&lt;/p&gt;
&lt;p&gt;public이나 protected 생성작 없으므로 클래스가 초기화 될 때 만들어진 인스턴스가 전체 시스템에서 하나뿐임이 보장&lt;/p&gt;
&lt;p&gt;예외적으로 권한이 있는 클라이언트는 AccessibleObject.setAccessible을 이용해 private 생성자를 호출 할 수 있음&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2. 정적 팩터리 방식&lt;/p&gt;
&lt;pre id=&quot;code_1610771288143&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {}
    public static Singleton getInstance() {
        return INSTANCE;
    }
    public void singletonMethod() {}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;api를 변경하지 않고도 싱글턴이 아니게 변경할 수 있다.&lt;/p&gt;
&lt;p&gt;기타 다른 장점은 뒤에서..(아이템 30, 43, 44)&lt;/p&gt;
&lt;p&gt;3. 열거 타입 방식&lt;/p&gt;
&lt;pre id=&quot;code_1610771393435&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public enum Singleton {
    INSTANCE;

    public void singletonMethod() {}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;public 필드 방식과 비슷하지만, 더 간결하고, 추가 노력 없이 직렬화할 수 있다.&lt;/p&gt;
&lt;p&gt;리플렉션 공격에서도 제 2의 인스턴스가 생기는 일을 막아준다.&lt;/p&gt;
&lt;pre id=&quot;code_1610772732815&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Singleton {
    public static final Singleton INSTANCE = new Singleton();

    private Singleton() {

    }
    public static Singleton getInstance() {
        return INSTANCE;
    }
    public void singletonMethod() {
        System.out.println(&quot;singletonMethod&quot;);
    }

    public static void main(String[] args) {
       // Singleton singleton = new Singleton();
        Class&amp;lt;? extends Singleton&amp;gt; cl = null;
        try {
            cl = (Class&amp;lt;? extends Singleton&amp;gt;) Class.forName(&quot;Singleton&quot;);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Constructor&amp;lt;? extends Singleton&amp;gt; constructor = null;
        try {
            constructor = cl.getDeclaredConstructor();
            Singleton singleton = constructor.newInstance();
            singleton.singletonMethod();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;단, 만들려는 싱글턴이 Enum외의 클래스를 상속해야 한다면 이방법은 사용할 수 없다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;+ 클래스안에서 실수로 생성자를 호출하지 안하도록 막기&lt;/p&gt;
&lt;pre id=&quot;code_1610771937083&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Singleton {
    public static final Singleton INSTANCE = new Singleton();

    private Singleton() {
        if (INSTANCE !=null)
            throw new AssertionError();
    }
    public static Singleton getInstance() {
        return INSTANCE;
    }
    public void singletonMethod() {}

    public static void main(String[] args) {
        Singleton singleton = new Singleton();
    }
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/Java</category>
      <author>Beemo_</author>
      <guid isPermaLink="true">https://devsign-blog.tistory.com/10</guid>
      <comments>https://devsign-blog.tistory.com/entry/Effective-Java-3E-%EC%8B%B1%EA%B8%80%ED%84%B4%EC%9D%84-%EB%A7%8C%EB%93%9C%EB%8A%94-%EB%B0%A9%EB%B2%95#entry10comment</comments>
      <pubDate>Sat, 16 Jan 2021 13:42:46 +0900</pubDate>
    </item>
    <item>
      <title>Effective Java 3/E - 정적 팩터리 메서드</title>
      <link>https://devsign-blog.tistory.com/entry/Effective-Java-3E-%EC%A0%95%EC%A0%81-%ED%8C%A9%ED%84%B0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C</link>
      <description>&lt;p&gt;클래스는 생성자와 별도로 정적 팩터리 메서드를 제공할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;생성자보다 정적 팩터리 메서드가 좋은점&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. 이름을 가질 수 있다.&lt;/p&gt;
&lt;p&gt;2. 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다.&lt;/p&gt;
&lt;p&gt;3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.&lt;/p&gt;
&lt;p&gt;4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.&lt;/p&gt;
&lt;p&gt;5. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;단점&lt;/p&gt;
&lt;p&gt;1. 상속을 하려면 public이나 protected생성자가 필요하니 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.&lt;/p&gt;
&lt;p&gt;2. 정척 팩터리 메서드는 프로그래머가 찾기 어렵다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;정적팩터리 메서드 명명방식&lt;/p&gt;
&lt;p&gt;1. from : 매개변수를 하나 받아서 해당 타입의 인스턴스를 반환하는 형변환 메서드&lt;/p&gt;
&lt;p&gt;2. of : 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드&lt;/p&gt;
&lt;p&gt;3. valueOf : from과 of의 더 자세한 버전&lt;/p&gt;
&lt;p&gt;4. instance or getInstance : (매개변수를 받는다면) 매개변수로 명시한 인스턴스를 반환하지만, 같은 인스턴스임을 보장하지는 않는다.&lt;/p&gt;
&lt;p&gt;5. create or newInstance : instance 혹은 getInstance와 같지만, 매번 새로운 인스턴스를 생성해 반홤함을 보장한다.&lt;/p&gt;
&lt;p&gt;6. getType : getInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 쓴다.&lt;/p&gt;
&lt;p&gt;7. newType : newInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 쓴다.&lt;/p&gt;
&lt;p&gt;8. type : getType과 newType의 간결한 버전&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Java</category>
      <author>Beemo_</author>
      <guid isPermaLink="true">https://devsign-blog.tistory.com/9</guid>
      <comments>https://devsign-blog.tistory.com/entry/Effective-Java-3E-%EC%A0%95%EC%A0%81-%ED%8C%A9%ED%84%B0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C#entry9comment</comments>
      <pubDate>Thu, 14 Jan 2021 16:48:17 +0900</pubDate>
    </item>
    <item>
      <title>자바 스트림 -2</title>
      <link>https://devsign-blog.tistory.com/entry/%EC%9E%90%EB%B0%94-%EC%8A%A4%ED%8A%B8%EB%A6%BC-2</link>
      <description>&lt;p&gt;&lt;b&gt;스트림 최종연산 collect&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;collect() : 스트림의 최종연산, 매개변수로 컬렉터를 필요&lt;/p&gt;
&lt;p&gt;Collector : 인터페이스, 컬렉터는 이 인터페이스를 구현&lt;/p&gt;
&lt;p&gt;Collectors : 클래스, static메서드로 미리 작성된 컬렉터를 제공&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;스트림을 컬렉션과 배열로 변환 : toList(), toSet(), toMap(), toCollection(), to Array()&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;통계 : Counting(), summingInt(), averagingInt(), maxBy(), minBy()&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;리듀싱 : reducing()&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;문자열 결합 : joining(), joining(&quot;,&quot;), joining(&quot;,&quot; , &quot;{&quot; , &quot;}&quot;);&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그룹화와 분할 : groupingBy(), partitioningBy()&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Collector 구현하기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1609502944273&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface Collector&amp;lt;T, A, R&amp;gt; {
    Supplier&amp;lt;A&amp;gt; supplier();
    BiConsumer&amp;lt;A, T&amp;gt; accumulator();
    BinaryOperator&amp;lt;A&amp;gt; combiner();
    Function&amp;lt;A, R&amp;gt; finisher();
    Set&amp;lt;Characteristics&amp;gt; characteristics();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;supplier() : 작업 결과를 저장할 공간을 제공&lt;/p&gt;
&lt;p&gt;accumulator() : 스트림의 요소를 수집(collect)할 방법을 제공&lt;/p&gt;
&lt;p&gt;combiner() : 두 저장공간을 병합할 방법을 제공&lt;/p&gt;
&lt;p&gt;finisher() : 결과를 최종적으로 변환할 방법을 제공&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;characteristics() : 컬렉터가 수행하는 작업의 속성에 대한 정보를 제공&lt;/p&gt;
&lt;p&gt;C&lt;span style=&quot;color: #333333;&quot;&gt;haracteristics.CONCURRENT : 병렬로 처리할 수 있는 작업&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;C&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;haracteristics.UNORDERED : 스트림의 요소의 순서가 유지될 필요가 없는 작업&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;C&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;haracteristics.IDENTITY_FINISH : finisher()가 항등 함수인 작업&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Java</category>
      <author>Beemo_</author>
      <guid isPermaLink="true">https://devsign-blog.tistory.com/8</guid>
      <comments>https://devsign-blog.tistory.com/entry/%EC%9E%90%EB%B0%94-%EC%8A%A4%ED%8A%B8%EB%A6%BC-2#entry8comment</comments>
      <pubDate>Fri, 1 Jan 2021 23:59:57 +0900</pubDate>
    </item>
    <item>
      <title>자바 스트림 -1</title>
      <link>https://devsign-blog.tistory.com/entry/%EC%9E%90%EB%B0%94-%EC%8A%A4%ED%8A%B8%EB%A6%BC-1</link>
      <description>&lt;p&gt;&lt;b&gt;스트림?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 데이터 소스를 추상화하고, 데이터를 다루는데 자주 사용되는 메서드들을 정의해 놓은 것&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 데이터 소스가 무엇이던 간에 같은 방식으로 다를 수 있게 해줌&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 코드의 재사용성이 높아짐&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;문자열 &lt;span style=&quot;color: #333333;&quot;&gt;정렬, 출력&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1608951694587&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;        String[] strings = {&quot;data1&quot;, &quot;data3&quot;, &quot;data2&quot;};
        List&amp;lt;String&amp;gt; stringList = Arrays.asList(strings);

        Arrays.sort(strings);
        Collections.sort(stringList);
        for(String string : strings) {
            System.out.println(string);
        }
        for(String string : stringList) {
            System.out.println(string);
        }
        
        Stream&amp;lt;String&amp;gt; stringStream = stringList.stream();
        Stream&amp;lt;String&amp;gt; stringStream2 = Arrays.stream(strings);

        stringStream.sorted().forEach(System.out::println);
        stringStream2.sorted().forEach(System.out::println);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;스트림 특징&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 데이터 소스를 변경하지 않음&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 일회용&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 내부 반복으로 처리&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;스트림 연산&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 중간 연산 : 연산 결과(반환값)이 스트림인 연산&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 최종 연산 : 스트림의 요소를 소모하는 연산&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;stringStream.sorted().forEach(System.&lt;span&gt;out&lt;/span&gt;::println)&lt;span&gt;;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;에서 sorted()는 중간 연산, forEach는 최종 연산에 해당&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;- 중간 연산 종류&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;distinct() - 중복을 제거&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;filter() - 조건에 안 맞는 요소 제외&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;limit() - 스트림의 일부를 잘라냄&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;skip() - 스트림의 일부를 건너뜀&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;peek() - 스트림의 요소에 작업수행 (스트림의 중간 값을 확인하기에 좋음)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;sorted() - 스트림의 요소를 정렬&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;map, &lt;/span&gt;&lt;span&gt;flatMap - 스트림의 요소를 변환&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 최종 연산 종류&lt;/p&gt;
&lt;p&gt;forEach(), forEachOrdered() - 각 요소에 지정된 작업 수행&lt;/p&gt;
&lt;p&gt;count() - 스트림의 요소의 갯수 반환&lt;/p&gt;
&lt;p&gt;max(), min() - 스트림의 최대, 최소 값을 반환&lt;/p&gt;
&lt;p&gt;findAny(), findFirst() - 스트림의 요소 하나를 반환(any : 아무거나 1개, first : 첫 번째 요소)&lt;/p&gt;
&lt;p&gt;allMatch(), anyMatch(), noneMatch() - 주어진 조건을 모든 요소가 만족시키는지, 만족시키지 않는지 확인&lt;/p&gt;
&lt;p&gt;toArray() - 스트림의 모든 요소를 배열로 반환&lt;/p&gt;
&lt;p&gt;reduce() - 스트림의 요소를 하나씩 줄여가면서 계산&lt;/p&gt;
&lt;p&gt;collect() - 스트림 요소를 수집, 결과를 컬렉션에 담아 반환하는데 사용&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&amp;nbsp;- 스트림 연산은 최종 연산이 수행되기 전까지는 중간 연산을 수행하지 않는다(지연된 연산)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;- 중간 연산을 호출 해도 어떤 작업이 수행되어야 하는지를 지정할 뿐 연산을 수행하진 않는다.&lt;/p&gt;</description>
      <category>개발/Java</category>
      <author>Beemo_</author>
      <guid isPermaLink="true">https://devsign-blog.tistory.com/7</guid>
      <comments>https://devsign-blog.tistory.com/entry/%EC%9E%90%EB%B0%94-%EC%8A%A4%ED%8A%B8%EB%A6%BC-1#entry7comment</comments>
      <pubDate>Sat, 26 Dec 2020 14:19:38 +0900</pubDate>
    </item>
    <item>
      <title>자바 람다식</title>
      <link>https://devsign-blog.tistory.com/entry/%EC%9E%90%EB%B0%94-%EB%9E%8C%EB%8B%A4%EC%8B%9D</link>
      <description>&lt;p&gt;&lt;b&gt;람다식?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 메서드를 하나의 식으로 표현한 것&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 메서드의 이름과 반환값이 없어지므로, 익명함수라고도 함&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;람다식 작성법&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;반환타입 메서드이름 (매개변수) {&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; //내용&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;(매개변수) -&amp;gt; {&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; //내용&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;int add(int a, int b) {&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; return a + b;&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;(int a, int b) -&amp;gt; {&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; return a + b;&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;(a, b) -&amp;gt; a + b&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;함수형 인터페이스&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Type t = (int a, int b) -&amp;gt; a + b;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1608345436675&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Function {
    int add(int a, int b);
}

Function function = new Function() {
      @Override
      public int add(int a, int b) {
          return a + b;
      }
};
function.add(1,3);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1608345519921&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface LambdaInterface {
    int add(int a, int b);
}

LambdaInterface lambdaInterface = (int a, int b) -&amp;gt; {return a + b;};
lambdaInterface.add(1,3);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;- 인터페이스를 통해 람다식을 다룸&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 람다식을 다루기 위한 인터페이스를 함수형 인터페이스 라고 함&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 함수형 인터페이스는 오직 하나의 추상 메서드만 정의 되어야 한다는 제약이 있음&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1608345732120&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@FunctionalInterface
interface LambdaInterface {
    int add(int a, int b);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;- @FunctionalInterface 어노테이션을 선언하면 함수형 인터페이스의 제약에 맞게 정의하였는지 확인해줌&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/owQ3A/btqQIXeIT3a/aRIAFk5SK7leZkfwJq2Pnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/owQ3A/btqQIXeIT3a/aRIAFk5SK7leZkfwJq2Pnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/owQ3A/btqQIXeIT3a/aRIAFk5SK7leZkfwJq2Pnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FowQ3A%2FbtqQIXeIT3a%2FaRIAFk5SK7leZkfwJq2Pnk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;람다식의 외부 변수 참조&lt;/p&gt;
&lt;pre id=&quot;code_1608346680313&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@FunctionalInterface
interface LambdaInterface {
    void method();
}

class Outer {
    int val = 10;

    class Inner {
        int val = 20;

        void method(int i) { //final
            int val = 30; //final
            Outer.this.val = 40;
            this.val = 30;
            //val = 20; - 에러
            //i = 40; - 에러
            LambdaInterface lambdaInterface = () -&amp;gt; {
                System.out.println(&quot;i : &quot; + i);
                System.out.println(&quot;val : &quot; + val);
                System.out.println(&quot;this.val : &quot; + this.val);
                System.out.println(&quot;Outer.this.val : &quot; + Outer.this.val);
            };
            lambdaInterface.method();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;- 람다식내에서 참조하는 지역변수는 상수로 간주&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 외부변수들은 상수로 간주되지 않으므로 값의 변경이 가능&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1608346816350&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; void method(int i) { //final
            int val = 30; //final
            Outer.this.val = 40;
            this.val = 30;
            //val = 20; - 에러
            //i = 40; - 에러
            LambdaInterface lambdaInterface = (i) -&amp;gt; { //에러
                System.out.println(&quot;i : &quot; + i);
                System.out.println(&quot;val : &quot; + val);
                System.out.println(&quot;this.val : &quot; + this.val);
                System.out.println(&quot;Outer.this.val : &quot; + Outer.this.val);
            };
            lambdaInterface.method();
        }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;- 외부 지역변수와 같은 이름의 람다식 매개변수는 허용되지 않음&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;java.util.function&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1608347392846&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Runnable runnable = () -&amp;gt; {}; // void run();
Supplier&amp;lt;String&amp;gt; supplier = () -&amp;gt; {return &quot;string&quot;;}; //T get();
Consumer&amp;lt;String&amp;gt; consumer = (String t) -&amp;gt; {}; // void accept(T t);
Function&amp;lt;String, Integer&amp;gt; function = (String t) -&amp;gt; {return 5;}; // R apply(T t) : R은 반환 타입
Predicate&amp;lt;String&amp;gt; predicate = (String t) -&amp;gt; {return false;}; // boolean test(T t);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;- java.util.function 패키지안에 미리 정의 된 함수형 인터페이스&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;- 매번 새로운 인터페이스를 정의 할 필요없이 해당 패키지의 인터페이스를 활용하는 게 좋음&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp; &amp;nbsp;- 메서드 이름의 통일&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp; &amp;nbsp;- 재사용성, 유지보수 측면에서 효율&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1608347641534&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;BiPredicate&amp;lt;String, String&amp;gt; biPredicate = (String t, String u) -&amp;gt; {return false;}; 
//매개변수가 2개면 앞에 Bi가 붙은 interface사용&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;합성과 결합&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;합성&lt;/p&gt;
&lt;p&gt;andThen, compose&lt;/p&gt;
&lt;pre id=&quot;code_1608356901611&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; Function &amp;lt;String, Integer&amp;gt; f = (s) -&amp;gt; Integer.parseInt(s);
 Function &amp;lt;Integer, String&amp;gt; g = (i) -&amp;gt; Integer.toBinaryString(i);
 Function &amp;lt;String, String&amp;gt; h = f.andThen(g); //f 수행 후 g를 수행
 Function &amp;lt;Integer, Integer&amp;gt; h2 = g.andThen(f); //g 수행 후 f를 수행
        
 h = g.compose(f); //f 수행 후 g를 수행
 h2 = f.compose(g);//g 수행 후 f를 수행&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결합&lt;/p&gt;
&lt;p&gt;and, or, negate&lt;/p&gt;
&lt;pre id=&quot;code_1608357174234&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Predicate&amp;lt;Integer&amp;gt; p = i-&amp;gt; i &amp;lt; 100;
Predicate&amp;lt;Integer&amp;gt; q = i-&amp;gt; i &amp;lt; 200;
Predicate&amp;lt;Integer&amp;gt; r = i-&amp;gt; i % 2 == 0;
Predicate&amp;lt;Integer&amp;gt; notP = p.negate(); // i &amp;gt;= 100
        
// 100 &amp;lt;= i &amp;amp;&amp;amp; (i &amp;lt; 200 || i % 2 == 0) 
Predicate&amp;lt;Integer&amp;gt; result = notP.and(q.or(r));
System.out.println(result.test(150)); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Java</category>
      <author>Beemo_</author>
      <guid isPermaLink="true">https://devsign-blog.tistory.com/6</guid>
      <comments>https://devsign-blog.tistory.com/entry/%EC%9E%90%EB%B0%94-%EB%9E%8C%EB%8B%A4%EC%8B%9D#entry6comment</comments>
      <pubDate>Sat, 19 Dec 2020 14:57:26 +0900</pubDate>
    </item>
    <item>
      <title>프로그래머스 해시 - 베스트앨범</title>
      <link>https://devsign-blog.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%95%B4%EC%8B%9C-%EB%B2%A0%EC%8A%A4%ED%8A%B8%EC%95%A8%EB%B2%94</link>
      <description>&lt;p&gt;해시문제 베스트 앨범&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDab5Z/btqPQtftOsz/JBcVkonMSpBjvbXZaKo7oK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDab5Z/btqPQtftOsz/JBcVkonMSpBjvbXZaKo7oK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDab5Z/btqPQtftOsz/JBcVkonMSpBjvbXZaKo7oK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDab5Z%2FbtqPQtftOsz%2FJBcVkonMSpBjvbXZaKo7oK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;코드&lt;/p&gt;
&lt;pre id=&quot;code_1607745363895&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public int[] solution(String[] genres, int[] plays) {
        int[] answer = {};
        HashMap&amp;lt;String,PlayData&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
        for (int i = 0; i &amp;lt; genres.length; i++) {
            PlayData playData;
            playData = new PlayData(i);
            playData.put(i, plays[i]);
            map.merge(genres[i], playData, PlayData::merge);
        }
        Iterator iterator = PlayData.sortByTotalValue(map).iterator();
        ArrayList&amp;lt;Integer&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();

        while(iterator.hasNext()) {
            String temp = (String) iterator.next();
            HashMap&amp;lt;Integer, Integer&amp;gt; result = map.get(temp).getPlayList();
            Iterator playIterator = sortByValue(result).iterator();
            int i = 0;
            while(playIterator.hasNext() &amp;amp;&amp;amp; i &amp;lt; 2) {
                i++;
                list.add((int)playIterator.next());
            }

        }
        answer = list.stream().mapToInt(i-&amp;gt;i).toArray();

        return answer;
    }

    public static List sortByValue(HashMap allList) {

        List&amp;lt;Integer&amp;gt; list = new ArrayList();
        list.addAll(allList.keySet());
        Collections.sort(list,new Comparator() {
            public int compare(Object o1,Object o2) {
                Object v1 = allList.get(o1);
                Object v2 = allList.get(o2);
                return ((Comparable) v2).compareTo(v1);
            }

        });
        return list;

    }
}

class PlayData {
    private HashMap&amp;lt;Integer, Integer&amp;gt; allList = new HashMap&amp;lt;&amp;gt;();

    private int total = 0;
    int index;
    int plays;
    public PlayData(int index) {
        this.index = index;
    }
    public HashMap&amp;lt;Integer, Integer&amp;gt; getPlayList() {
        return allList;
    }
    public int getTotal() {
        return total;
    }
    public int[] getPlayInfo() {
        return new int[]{index, plays};
    }
    public void put(int index, int plays) {
        this.plays = plays;
        this.total += plays;
        allList.put(index, plays);
    }

    public static PlayData merge(PlayData playData, PlayData playData1) {

        int[] value = playData1.getPlayInfo();
        playData.put(value[0], value[1]);
        return playData;
    }
    public static List sortByTotalValue(HashMap allList) {

        List&amp;lt;Integer&amp;gt; list = new ArrayList();
        list.addAll(allList.keySet());
        Collections.sort(list,new Comparator() {
            public int compare(Object o1,Object o2) {
                Object v1 = ((PlayData)allList.get(o1)).getTotal();
                Object v2 = ((PlayData)allList.get(o2)).getTotal();
                return ((Comparable) v2).compareTo(v1);
            }
        });
        return list;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;코드 내용 요약&lt;/p&gt;
&lt;p&gt;&lt;span&gt;for &lt;/span&gt;(&lt;span&gt;int &lt;/span&gt;i = &lt;span&gt;0&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;i &amp;lt; genres.&lt;span&gt;length&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;i++) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; PlayData playData&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; playData = &lt;span&gt;new &lt;/span&gt;PlayData(i)&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; playData.put(i&lt;span&gt;, &lt;/span&gt;plays[i])&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; map.merge(genres[i]&lt;span&gt;, &lt;/span&gt;playData&lt;span&gt;, &lt;/span&gt;PlayData::&lt;span&gt;merge&lt;/span&gt;)&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;}&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;한 장르의 데이터를 맵에 넣기위해 PlayData 클래스를 만들어서 같은 장르를 인덱스별로 보관하기 위해 PlayData 클래스 내부에 allList라는 맵을 만들어주고 인덱스와 플레이 횟수를 저장해줌&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;public static &lt;/span&gt;PlayData &lt;span&gt;merge&lt;/span&gt;(PlayData playData&lt;span&gt;, &lt;/span&gt;PlayData playData1) {&lt;br /&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; int&lt;/span&gt;[] value = playData1.getPlayInfo()&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; playData.put(value[&lt;span&gt;0&lt;/span&gt;]&lt;span&gt;, &lt;/span&gt;value[&lt;span&gt;1&lt;/span&gt;])&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return &lt;/span&gt;playData&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;map.merge를 사용해서 같은 장르의 앨범을 PlayData 안의 allList에 넣도록 해줌&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;public static &lt;/span&gt;List &lt;span&gt;sortByTotalValue&lt;/span&gt;(HashMap allList) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; List&amp;lt;Integer&amp;gt; list = &lt;span&gt;new &lt;/span&gt;ArrayList()&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; list.addAll(allList.keySet())&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Collections.&lt;span&gt;sort&lt;/span&gt;(list&lt;span&gt;,new &lt;/span&gt;Comparator() {&lt;br /&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; public int &lt;/span&gt;&lt;span&gt;compare&lt;/span&gt;(Object o1&lt;span&gt;,&lt;/span&gt;Object o2) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Object v1 = ((PlayData)&lt;span&gt;allList&lt;/span&gt;.get(o1)).getTotal()&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Object v2 = ((PlayData)&lt;span&gt;allList&lt;/span&gt;.get(o2)).getTotal()&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return &lt;/span&gt;((Comparable) v2).compareTo(v1)&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; })&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return &lt;/span&gt;list&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;}&lt;/p&gt;
&lt;p&gt;총 플레이 횟수를 기준으로 정렬시키기 위한 코드&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;list.addAll(allList.keySet())&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;; 로 키값의 list를 리턴할 수 있도록 처리&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;public static &lt;/span&gt;List &lt;span&gt;sortByValue&lt;/span&gt;(HashMap allList) {&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; List&amp;lt;Integer&amp;gt; list = &lt;span&gt;new &lt;/span&gt;ArrayList()&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; list.addAll(allList.keySet())&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Collections.&lt;span&gt;sort&lt;/span&gt;(list&lt;span&gt;,new &lt;/span&gt;Comparator() {&lt;br /&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; public int &lt;/span&gt;&lt;span&gt;compare&lt;/span&gt;(Object o1&lt;span&gt;,&lt;/span&gt;Object o2) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Object v1 = &lt;span&gt;allList&lt;/span&gt;.get(o1)&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Object v2 = &lt;span&gt;allList&lt;/span&gt;.get(o2)&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return &lt;/span&gt;((Comparable) v2).compareTo(v1)&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; })&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return &lt;/span&gt;list&lt;span&gt;;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;같은 장르의 노래들을 플레이 수 순으로 정렬 후&lt;br /&gt;&lt;span&gt;while&lt;/span&gt;(playIterator.hasNext() &amp;amp;&amp;amp; i &amp;lt; &lt;span&gt;2&lt;/span&gt;) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; i++&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; list.add((&lt;span&gt;int&lt;/span&gt;)playIterator.next())&lt;span&gt;;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;최상위 곡 2개를 뽑아서 저장&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;answer = list.stream().mapToInt(i-&amp;gt;i).toArray()&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;문제의 리턴형은 int형 배열이기 때문에 list를 int형 array로 바꾸는 mapToInt를 사용하여 변환&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Algorithm</category>
      <author>Beemo_</author>
      <guid isPermaLink="true">https://devsign-blog.tistory.com/5</guid>
      <comments>https://devsign-blog.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%95%B4%EC%8B%9C-%EB%B2%A0%EC%8A%A4%ED%8A%B8%EC%95%A8%EB%B2%94#entry5comment</comments>
      <pubDate>Sat, 12 Dec 2020 13:55:27 +0900</pubDate>
    </item>
    <item>
      <title>프로그래머스 DP - 등굣길</title>
      <link>https://devsign-blog.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-DP-%EB%93%B1%EA%B5%A3%EA%B8%B8</link>
      <description>&lt;p&gt;&lt;span style=&quot;color: #666666;&quot;&gt;동적계획법 등굣길 문제&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uShI4/btqPuUcLi3U/XrsYlhBRIqFKqP1u5kBOsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uShI4/btqPuUcLi3U/XrsYlhBRIqFKqP1u5kBOsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uShI4/btqPuUcLi3U/XrsYlhBRIqFKqP1u5kBOsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuShI4%2FbtqPuUcLi3U%2FXrsYlhBRIqFKqP1u5kBOsk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1607408529307&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public int solution(int m, int n, int[][] puddles) {
        int answer = 0;
        int[][] dp = new int[m+1][n+1];
        for (int[] puddle : puddles) {
            dp[puddle[0]][puddle[1]] = -1;
        }


        dp[1][0] = 1;
        for (int i = 1; i &amp;lt;= m; i++) {

            for (int j = 1; j &amp;lt;= n; j++) {
                if (dp[i][j] == -1) {
                    dp[i][j] = 0;
                } else {
                    dp[i][j] = (dp[i][j-1]+dp[i-1][j]) % 1000000007;
                }
            }
        }
        answer = dp[m][n];
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;코드 내용 요약&lt;/p&gt;
&lt;p&gt;&amp;nbsp;int[][]&amp;nbsp;dp&amp;nbsp;=&amp;nbsp;new&amp;nbsp;int[m+1][n+1]; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;(int[]&amp;nbsp;puddle&amp;nbsp;:&amp;nbsp;puddles)&amp;nbsp;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dp[puddle[0]][puddle[1]]&amp;nbsp;=&amp;nbsp;-1; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;/p&gt;
&lt;p&gt;물웅덩이의 위치를 -1로 셋팅 그 외에는 0으로 셋팅(자바에서는 초기화와 동시에 배열값이 0으로 셋팅 된다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;dp[1][0]&lt;/p&gt;
&lt;p&gt;집의 시작지점은 1가지 길이기 때문에 1로 셋팅&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;for (int i = 1; i &amp;lt;= m; i++) { &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for (int j = 1; j &amp;lt;= n; j++) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(dp[i][j]&amp;nbsp;==&amp;nbsp;-1)&amp;nbsp;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dp[i][j]&amp;nbsp;=&amp;nbsp;0; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;else&amp;nbsp;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dp[i][j]&amp;nbsp;=&amp;nbsp;(dp[i][j-1]+dp[i-1][j])&amp;nbsp;%&amp;nbsp;1000000007; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;br /&gt;}&lt;/p&gt;
&lt;p&gt;물웅덩이로 가는길 (&lt;span style=&quot;color: #333333;&quot;&gt;dp[i][j] == -1) 은 갈 수 있는 길이 0가지 이므로 0으로 재 셋팅&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그 외에는 해당 위치의 위와 왼쪽의 갈 수 있는 길의 갯 수 합이 해당 지점으로 가는 길의 갯수가 되므로 더함&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;문제에서 1000000007로 나눈 나머지 값을 저장 하라고 했으니 % 1000000007로 계산&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;dp[m][n]이 최종 목적지 까지 가는 길의 갯 수가 됨.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Algorithm</category>
      <author>Beemo_</author>
      <guid isPermaLink="true">https://devsign-blog.tistory.com/4</guid>
      <comments>https://devsign-blog.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-DP-%EB%93%B1%EA%B5%A3%EA%B8%B8#entry4comment</comments>
      <pubDate>Tue, 8 Dec 2020 15:29:41 +0900</pubDate>
    </item>
  </channel>
</rss>