<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>bangrr</title>
        <link>https://velog.io/</link>
        <description>나만의 텃밭을 가꾸어보자</description>
        <lastBuildDate>Thu, 23 Jan 2025 07:09:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. bangrr. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/bang_rr" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[CRA to Vite Migration]]></title>
            <link>https://velog.io/@bang_rr/CRA-to-Vite-Migration</link>
            <guid>https://velog.io/@bang_rr/CRA-to-Vite-Migration</guid>
            <pubDate>Thu, 23 Jan 2025 07:09:32 GMT</pubDate>
            <description><![CDATA[<p>기존에 CRA + React + JS 로 만들었던 프로젝트를 Vite + React + JS + SWC 로 마이그레이션 했다.</p>
<h2 id="vite-react-swc-플러그인-설치">Vite, React-swc 플러그인 설치</h2>
<pre><code class="language-bash">npm install vite @vitejs/plugin-react-swc --save-dev</code></pre>
<h2 id="cra-의존성-제거">CRA 의존성 제거</h2>
<pre><code class="language-bash">npm uninstall react-scripts</code></pre>
<h2 id="packagejson-파일-수정">package.json 파일 수정</h2>
<pre><code class="language-json">&quot;scripts&quot;: {
  &quot;dev&quot;: &quot;vite&quot;,
  &quot;build&quot;: &quot;vite build&quot;,
  &quot;preview&quot;: &quot;vite preview&quot;
},</code></pre>
<h2 id="viteconfigjs-파일-추가-및-작성">vite.config.js 파일 추가 및 작성</h2>
<p>vite.config.js 파일을 루트 디렉토리에 생성하고 작성한다.</p>
<pre><code class="language-jsx">import { defineConfig } from &#39;vite&#39;
import react from &#39;@vitejs/plugin-react-swc&#39;

// https://vite.dev/config/
export default defineConfig({
  plugins: [react()],
})</code></pre>
<h2 id="indexhtml-파일-이동-및-수정">index.html 파일 이동 및 수정</h2>
<p>기존 프로젝트에서는 index.html 파일이 /public 경로에 있었는데</p>
<p>Vite 에서는 루트(/) 경로에 있어야 한다.</p>
<p>html파일을 옮기면 <code>HTTP ERROR 404</code> 가 아니고 <strong><code>URI malformed</code></strong> 라고 에러가 바뀔 것이다.</p>
<p>또한, index.html 파일 내에 <code>%PUBLIC_URL%</code> 경로를 참조하는 코드들은 과감히 지워준다.</p>
<p>ex) <code>&lt;link rel=&quot;icon&quot; href=&quot;%PUBLIC_URL%/favicon.ico&quot; /&gt;</code></p>
<p>그리고 <body> 내에 index.jsx 파일을 연결해준다.</p>
<pre><code class="language-jsx">&lt;body&gt;
  &lt;noscript&gt;You need to enable JavaScript to run this app.&lt;/noscript&gt;
  &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
  &lt;script type=&quot;module&quot; src=&quot;/src/index.jsx&quot;&gt;&lt;/script&gt;
&lt;/body&gt;</code></pre>
<h2 id="js-파일-확장자-jsx-로-변경">js 파일 확장자 jsx 로 변경</h2>
<p>CRA 에서는 .js 로 사용하던 파일을 Vite 에서는 .jsx 로 변경해주어야 한다.</p>
<h2 id="실행">실행</h2>
<p>해본다</p>
<pre><code class="language-bash">npm run dev</code></pre>
<p>안되는가?</p>
<p>기존 /node_modules 폴더를 삭제하고 <code>npm install</code> 해서 패키지 재설치 하고 다시 실행시켜본다.</p>
<hr>
<h2 id="vite-프로젝트-빌드-후-github-pages에-배포하면-흰-화면인-현상">Vite 프로젝트 빌드 후 Github Pages에 배포하면 흰 화면인 현상</h2>
<p>빌드되어진 dist 폴더의 index.html 파일을 보니 src, href 등 경로들이 절대경로로 표시되어있음
<img src="https://velog.velcdn.com/images/bang_rr/post/52ea09aa-0eca-4ced-a342-67e0db2e316a/image.png" alt=""></p>
<p>vite.config.js 에서 base 옵션을 설정하지 않으면 기본 값이 ‘/’ 으로 되어있었다.
<img src="https://velog.velcdn.com/images/bang_rr/post/d0e566ee-48bd-4790-8a40-c5aec04b5fa9/image.png" alt=""></p>
<p>vite.config.js 파일에서 base: ‘’ 를 추가해서 해결하였다.
<img src="https://velog.velcdn.com/images/bang_rr/post/176adca0-aea0-4e07-a38c-1f269f1d9345/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/bang_rr/post/c15df403-50df-4b36-965f-75f08a245e98/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[에러해결] Syntax error in SQL statement ~ expected "identifier"]]></title>
            <link>https://velog.io/@bang_rr/Syntax-error-in-SQL-statement-expected-identifier</link>
            <guid>https://velog.io/@bang_rr/Syntax-error-in-SQL-statement-expected-identifier</guid>
            <pubDate>Fri, 05 Jan 2024 17:58:18 GMT</pubDate>
            <description><![CDATA[<p>에러로그:
org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement &quot;\000d\000a    drop table if exists [*]user CASCADE &quot;; expected &quot;identifier&quot;;</p>
<p>상황설명:
<code>User.java</code>안에 <code>@Entity 와 @Table(name = &quot;user&quot;)</code>로 설정되어있고, <code>data.sql</code>에 <code>insert into user (~) values (~)</code> 라고 되어있는 상태로 Spring Boot 서버를 실행했을 때 위 오류가 발생했다.
(Spring Boot 2.7.7 버전, h2database 2.1.214 버전 사용중)</p>
<p>찾아본 내용:
일반적인 원인은 예약된 키워드를 식별자로 사용하는 것이다.
알고보니 H2가 1.x.x에서 2.x.x로 올라오면서 &#39;user&#39;라는 키워드가 <a href="https://www.h2database.com/html/advanced.html#keywords">h2의 예약어</a>로 사용되는 것이다.</p>
<p>해결방법:</p>
<ol>
<li>테이블 이름을 예약어가 아닌 것으로 <code>@Table(name = &quot;member&quot;)</code> 처럼 변경하면 된다.</li>
<li>application.yml(properties) 파일에 <code>spring.datasource.url</code>을 <code>jdbc:h2:mem:testdb;NON_KEYWORDS=USER</code>와 같이 <code>NON_KEYWORDS=USER</code>를 추가해서 h2에게 예약어가 아님을 명시해준다.</li>
<li>h2database 버전을 1.4.200 으로 낮춰서 사용한다.</li>
</ol>
<p>참조:
<a href="https://www.h2database.com/html/advanced.html#keywords">https://www.h2database.com/html/advanced.html#keywords</a>
<a href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.7-Release-Notes#h2-21">https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.7-Release-Notes#h2-21</a>
<a href="https://www.baeldung.com/spring-boot-h2-jdbcsqlsyntaxerrorexception-expected-identifier">https://www.baeldung.com/spring-boot-h2-jdbcsqlsyntaxerrorexception-expected-identifier</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[에러해결] Error creating bean with name 'dataSourceScriptDatabaseInitializer' ~ Invocation of init method failed]]></title>
            <link>https://velog.io/@bang_rr/Error-creating-bean-with-name-dataSourceScriptDatabaseInitializer-Invocation-of-init-method-failed</link>
            <guid>https://velog.io/@bang_rr/Error-creating-bean-with-name-dataSourceScriptDatabaseInitializer-Invocation-of-init-method-failed</guid>
            <pubDate>Fri, 05 Jan 2024 17:01:08 GMT</pubDate>
            <description><![CDATA[<p>에러로그:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name &#39;dataSourceScriptDatabaseInitializer&#39; defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Invocation of init method failed;</p>
<p>상황설명:
data.sql 파일을 이용해 Spring Boot 서버가 시작될 때마다 초기 데이터를 DB에 넣어주려고 했지만 서버를 실행하니 에러가 발생하였다.
(Spring Boot 2.7.7 버전 사용중)</p>
<p>찾아본 내용:
Spring Boot 2.5 버전부터는 Hibernate가 초기화되기 전에 <code>data.sql</code>이 실행되는게 기본이다.
Hibernate를 통해 만들어진 스키마에 데이터를 채우기 위해서 <code>data.sql</code>을 사용하려면 <code>spring.jpa.defer-datasource-initialization</code>을 <code>true</code>로 설정해야 한다.</p>
<p>해결방법:
<code>application.yml(properties)</code> 파일에 <code>spring.jpa.defer-datasource-initialization: true</code> 추가</p>
<p>참조 :
<a href="https://unhosted.tistory.com/83">https://unhosted.tistory.com/83</a>
<a href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.5-Release-Notes#hibernate-and-datasql">https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.5-Release-Notes#hibernate-and-datasql</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 10814번 나이순 정렬]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-10814%EB%B2%88-%EB%82%98%EC%9D%B4%EC%88%9C-%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-10814%EB%B2%88-%EB%82%98%EC%9D%B4%EC%88%9C-%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Mon, 22 Aug 2022 04:07:43 GMT</pubDate>
            <description><![CDATA[<p>링크: <a href="https://www.acmicpc.net/problem/10814">https://www.acmicpc.net/problem/10814</a></p>
<p>문제:
온라인 저지에 가입한 사람들의 나이와 이름이 가입한 순서대로 주어진다. 이때, 회원들을 나이가 증가하는 순으로, 나이가 같으면 먼저 가입한 사람이 앞에 오는 순서로 정렬하는 프로그램을 작성하시오.</p>
<p>입력:
첫째 줄에 온라인 저지 회원의 수 N이 주어진다. (1 ≤ N ≤ 100,000)</p>
<p>둘째 줄부터 N개의 줄에는 각 회원의 나이와 이름이 공백으로 구분되어 주어진다. 나이는 1보다 크거나 같으며, 200보다 작거나 같은 정수이고, 이름은 알파벳 대소문자로 이루어져 있고, 길이가 100보다 작거나 같은 문자열이다. 입력은 가입한 순서로 주어진다.</p>
<p>출력:
첫째 줄부터 총 N개의 줄에 걸쳐 온라인 저지 회원을 나이 순, 나이가 같으면 가입한 순으로 한 줄에 한 명씩 나이와 이름을 공백으로 구분해 출력한다.</p>
<p>제출:</p>
<pre><code class="language-java">import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;

        int n = Integer.parseInt(br.readLine());

        String[][] a = new String[n][2];
        for (int i=0; i&lt;n; i++) {
            st = new StringTokenizer(br.readLine(), &quot; &quot;);
            a[i][0] = st.nextToken();
            a[i][1] = st.nextToken();
        }
        Arrays.sort(a, (o1, o2) -&gt; {
                return Integer.parseInt(o1[0]) - Integer.parseInt(o2[0]);
        });
        for (int i=0; i&lt;n; i++) {
            System.out.println(a[i][0] + &quot; &quot; + a[i][1]);
        }
    }
}</code></pre>
<p>2차원 배열을 나이를 기준으로 오름차순 정렬하는 문제였다.
2차원 배열을 정렬하기 위해서는 Comparator 익명클래스를 구현해주어야 하는데 Java8 버전 이상에서는 간단하게 람다식으로 구현할 수 있다.</p>
<pre><code class="language-java">Arrays.sort(a, (o1, o2) -&gt; {
    return Integer.parseInt(o1[0]) - Integer.parseInt(o2[0]);
});</code></pre>
<p>나이와 이름을 함께 String으로 입력받았기 때문에 o1[0]과 o2[0]의 값인 나이를 숫자로 변환하여 비교한 후 오름차순으로 정렬해주었다.
만약 내림차순으로 정렬하고 싶으면 다음과 같이 return 부분에서 비교하는 앞뒤 순서를 바꾸어 주면 된다.</p>
<pre><code class="language-java">Arrays.sort(a, (o1, o2) -&gt; {
    return Integer.parseInt(o2[0]) - Integer.parseInt(o1[0]);
});</code></pre>
<p>Comparator의 comparing 메서드를 이용하는 방법도 있는데 아래와 같다.</p>
<pre><code class="language-java">// a 배열의 첫 번째 요소 기준 오름차순
Arrays.sort(a, Comparator.comparing((String[] o) -&gt; Integer.parseInt(o[0])));
// a 배열의 첫 번째 요소 기준 내림차순
Arrays.sort(a, Comparator.comparing((String[] o) -&gt; Integer.parseInt(o[0])).reversed());
// a 배열의 두 번째 요소 기준 오름차순
Arrays.sort(a, Comparator.comparing((String[] o) -&gt; Integer.parseInt(o[1])));
// a 배열의 두 번째 요소 기준 내림차순
Arrays.sort(a, Comparator.comparing((String[] o) -&gt; Integer.parseInt(o[1])).reversed());</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[갑자기 생각난 진수변환 문제]]></title>
            <link>https://velog.io/@bang_rr/%EA%B0%91%EC%9E%90%EA%B8%B0-%EC%83%9D%EA%B0%81%EB%82%9C-%EC%A7%84%EC%88%98%EB%B3%80%ED%99%98-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@bang_rr/%EA%B0%91%EC%9E%90%EA%B8%B0-%EC%83%9D%EA%B0%81%EB%82%9C-%EC%A7%84%EC%88%98%EB%B3%80%ED%99%98-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Fri, 19 Aug 2022 06:51:05 GMT</pubDate>
            <description><![CDATA[<p>IQ 테스트를 하고 결과가 나왔는데 값을 바꿔주고 싶어서 갑자기 문제가 생각나서 적어보았고 코드로 작성해보았다.</p>
<p>문제:
민국이가 IQ검사를 했는데 자기 생각보다 낮은 n값이 나왔다 (0 &lt;= n &lt; 100)
너무 낮아서 친구들한테 무시당할까봐 원하는 IQ값 W가 되도록 n옆에 작게 (t)라고 진법표시를 하려고 하는데
몇으로 해야 원하는 W값이 될 지 모르겠다고 한다. 필요할 때마다 사용할 수 있도록 민국이를 도와주자.</p>
<p>입력:
첫째 줄에 원래 값인 n과 원하는 값인 w를 공백 하나를 사이에 두고 입력한다.</p>
<p>출력:
조건을 만족하는 진법 t를 출력한다. 만족하는 t진법이 없을 시에는 0을 출력한다.</p>
<p>예제 입력:
48 100</p>
<p>예제 출력:
23</p>
<p>코드:</p>
<pre><code class="language-java">import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String n = sc.next();    // 0 ~ 99
        int w = sc.nextInt();
        int t;
        int sum;

        sc.close();

        char[] cArr = n.toCharArray();
        System.out.println(cArr[cArr.length-1]);

        for (t=cArr[cArr.length-1]-&#39;0&#39;+1; t&lt;w; t++) {
            sum = 0;
            System.out.println(t);
            for (int i=0; i&lt;n.length(); i++) {
                sum = sum + (int)Math.pow(t, n.length()-i-1)*(n.charAt(i)-&#39;0&#39;);
                if (sum &gt; w) {
                    break;
                }
            }
            if (sum == w) {
                System.out.println(t);
                break;
            }
        }
        if (t == w) {
            System.out.println(0);
        }
    }
}</code></pre>
<p>조건도 아직 빈약할 것이고 누구한테도 검수받지 않은 문제지만 일단 풀어보았다.
코드를 다 작성하고 나서 스스로 봐도 코드가 더러워보여서 깔끔하게 다시 풀어서 다음 포스트에 올려볼 생각이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1장 스프링부트 개발 준비! (feat. 점프 투 스프링부트)]]></title>
            <link>https://velog.io/@bang_rr/1%EC%9E%A5-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EA%B0%9C%EB%B0%9C-%EC%A4%80%EB%B9%84-feat.-%EC%A0%90%ED%94%84-%ED%88%AC-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8</link>
            <guid>https://velog.io/@bang_rr/1%EC%9E%A5-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EA%B0%9C%EB%B0%9C-%EC%A4%80%EB%B9%84-feat.-%EC%A0%90%ED%94%84-%ED%88%AC-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8</guid>
            <pubDate>Wed, 27 Jul 2022 03:38:57 GMT</pubDate>
            <description><![CDATA[<h1 id="0-공식-주소">0. 공식 주소</h1>
<blockquote>
<p><a href="https://wikidocs.net/book/7601">https://wikidocs.net/book/7601</a></p>
</blockquote>
<hr>
<h1 id="1-스프링부트란">1. 스프링부트란?</h1>
<p>자바의 웹 프레임워크로 기존 스프링(Spring) 프레임워크에 톰캣 서버를 내장하고 여러 편의 기능들을 추가한 프레임워크이다.</p>
<p>웹 프레임워크란 웹 프로그램을 만들기 위한 기능(쿠키나 세션 처리, 로그인/로그아웃 처리, 권한 처리, 데이터베이스 처리 등)을 가지고 있는 스타터 키트라고 생각하면 된다.</p>
<p>스프링만 사용하여 웹 애플리케이션을 개발한다면 톰캣과 같은 WAS(Web Application Server)가 필요한데 톰캣 서버가 내장되어 있고 설정도 자동 적용되기 때문에 신경쓸 필요가 없다.</p>
<p>보안 기능도 포함되어 있는데 SQL 인젝션, XSS(cross-site scripting), CSRF(cross-site request forgery), 클릭재킹(clickjacking)과 같은 보안 공격을 기본으로 막아 준다.</p>
<blockquote>
<ul>
<li>SQL 인젝션은 악의적인 SQL을 주입하여 공격하는 방법이다.</li>
</ul>
</blockquote>
<ul>
<li>XSS는 자바스크립트를 삽입해 공격하는 방법이다.</li>
<li>CSRF는 위조된 요청을 보내는 공격 방법이다.</li>
<li>클릭재킹은 사용자의 의도하지 않은 클릭을 유도하는 공격 방법이다.</li>
</ul>
<hr>
<h1 id="2-개발-환경-준비하기">2. 개발 환경 준비하기</h1>
<h2 id="jdk-설치">JDK 설치</h2>
<p>자바 프로그래밍을 하기 위해 필수적으로 필요한 JDK를 설치한다. JDK는 <code>Java Development Kit</code>의 약자이다.</p>
<ul>
<li><a href="https://www.oracle.com/java/technologies/downloads/">https://www.oracle.com/java/technologies/downloads/</a></li>
</ul>
<p>만약 위 URL이 더이상 유효하지 않다면 구글 검색창에서 &quot;JDK Download&quot; 로 검색하고 들어가면 된다.</p>
<h2 id="sts-설치">STS 설치</h2>
<p>STS는 스프링부트 프로그램 작성을 도와주는 도구이다. IDE(Intergrated Development Environment), 통합개발환경이라고 부른다. STS는 이클립스 기반으로 제작된 스프링 개발에 최적화된 에디터이다. 인텔리제이나 이클립스도 많이 사용된다.</p>
<blockquote>
<p>STS 설치 파일 주소: <a href="https://spring.io/tools">https://spring.io/tools</a></p>
</blockquote>
<p>설치한 후 &quot;Create new Spring Starter Project&quot;를 눌러 프로젝트를 생성한다.
<img src="https://velog.velcdn.com/images/bang_rr/post/5b60e21a-e7ce-487b-a626-889cf75c94da/image.png" alt=""></p>
<p>이 부분은 중요하므로 주의깊게 입력하자.</p>
<ul>
<li>Name - Name은 프로젝트의 이름에 해당된다. 여기서는 &quot;Spring Boot Board&quot;의 이니셜인 sbb를 사용했다.</li>
<li>Type - Type은 프로젝트를 관리하는 도구를 선택하는 항목이다. 디폴트로 Maven이 설정되어 있지만 이 책에서는 Gradle을 사용할 것이다. Gradle은 Maven 보다 나중에 개발되었고 Maven보다 성능이 좋고 설정도 편리하다.</li>
<li>Java Version - 11 버전을 선택한다.</li>
<li>Group, Artifact, ... 등은 다르게 설정해도 되지만 이후 예제를 수월하게 진행하기 위해 위와 동일하게 설정하는것을 추천한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/bang_rr/post/312ccf5d-dac4-4c66-84dc-fa86ddcae0f7/image.png" alt=""></p>
<p>다음은 스프링부트 버전을 선택하는 화면인데 버전이름 뒤에 다른 말이 붙지 않은 안정화 버전 중에 최신 버전을 사용했고, Available 항목에서 web을 입력하여 &quot;Spring Web&quot; 항목을 찾아서 선택한다.</p>
<blockquote>
<p>&quot;Spring Web&quot;을 선택하지 않고 지나치면 웹 기능을 사용할 수 없으니 실수하지 않도록 주의하자.</p>
</blockquote>
<hr>
<h1 id="3-hello-world-in-spring-boot">3. Hello World in Spring Boot</h1>
<p><code>http://localhost:8080/hello</code>와 같은 브라우저의 요청을 처리하기 위해서는 컨트롤러가 필요하다. 컨트롤러는 서버에 전달된 클라이언트의 요청(URL과 전달된 파라미터 등)을 처리하는 자바 클래스이다.</p>
<pre><code class="language-java">package com.mysite.sbb;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
    @RequestMapping(&quot;/hello&quot;)
    @ResponseBody
    public String hello() {
        return &quot;Hello World&quot;;
    }
}</code></pre>
<p><code>@Controller</code> 애너테이션은 HelloController 클래스가 컨트롤러의 기능을 수행한다는 의미이다. 이 애너테이션이 있어야 스프링부트 프레임워크가 컨트롤러로 인식한다.</p>
<p><code>@RequestMapping(&quot;/hello&quot;)</code> 애너테이션은 <a href="http://localhost:8080/hello">http://localhost:8080/hello</a> URL 요청이 발생하면 hello 메서드가 실행됨을 의미한다. 즉, /hello URL과 hello 메서드를 매핑하는 역할을 한다.</p>
<blockquote>
<p>URL명과 메서드명은 동일할 필요는 없다. 즉 /hello URL일 때 메서드명을 hello가 아닌 hello2와 같이 해도 상관없다.</p>
</blockquote>
<p><code>@ResponseBody</code> 애너테이션은 hello 메서드의 응답 결과가 문자열 그 자체임을 나타낸다. hello 메서드는 &quot;Hello World&quot; 라는 문자열을 리턴하므로 출력으로 &quot;Hello World&quot; 문자열이 나갈 것이다. <em>단순한 문자열 보다는 HTML 파일과 같은 템플릿을 주로 사용한다.</em></p>
<hr>
<h1 id="4-스프링부트-도구-설치하기">4. 스프링부트 도구 설치하기</h1>
<p>다음으로는 스프링부트 개발을 도와주는 도구들에 대해 알아본다</p>
<pre><code>Spring Boot Devtools
Live Reload
롬복
- 롬복 설치
- Getter, Setter
- RequiredArgsConstructor</code></pre><h2 id="spring-boot-devtools">Spring Boot Devtools</h2>
<p>프로그램이 변경 되더라도 로컬서버가 변경된 클래스를 리로딩하지 않기 떄문에 수정하고 변경된 사항을 확인하려면 매번 서버를 재시작 해야 하는데, Spring Boot Devtools를 사용하면 서버 재시작 없이도 클래스 변경시 서버가 자동으로 재기동 된다.</p>
<pre><code class="language-java">plugins {
    id &#39;org.springframework.boot&#39; version &#39;2.6.4&#39;
    id &#39;io.spring.dependency-management&#39; version &#39;1.0.11.RELEASE&#39;
    id &#39;java&#39;
}

group = &#39;com.mysite&#39;
version = &#39;0.0.1-SNAPSHOT&#39;
sourceCompatibility = &#39;11&#39;

repositories {
    mavenCentral()
}

dependencies {
    implementation &#39;org.springframework.boot:spring-boot-starter-web&#39;
    testImplementation &#39;org.springframework.boot:spring-boot-starter-test&#39;
    developmentOnly &#39;org.springframework.boot:spring-boot-devtools&#39;
}

tasks.named(&#39;test&#39;) {
    useJUnitPlatform()
}</code></pre>
<p>사용하기 위해서는 그레이들(Gradle)로 설치해야 하는데 build.gradle 파일의 dependencies 항목에 <code>developmentOnly &#39;org.springframework.boot:spring-boot-devtools&#39;</code>를 추가해준다.</p>
<blockquote>
<p><strong>developmentOnly</strong>
Gradle의 developmentOnly는 개발환경에만 적용되는 설정이다. 즉, 운영환경에 배포되는 jar, war 파일에는 developmentOnly로 설치된 라이브러리는 제외된다.</p>
</blockquote>
<p>build.gradle 파일의 내용을 적용하려면 파일을 오른쪽 마우스 버튼을 눌러 <code>[Gradle -&gt; Refresh Gradle Project]</code>를 선택하여 필요한 라이브러리를 다운로드해야 한다.
<img src="https://velog.velcdn.com/images/bang_rr/post/3d5ae66a-d720-47f5-b8e2-5c56875d5090/image.png" alt=""></p>
<p>설치가 완료되면 Boot Dashboard의 서버명에[devtools]가 붙은 것을 확인할 수 있다. 이후 서버를 재시작하면 준비완료이다.</p>
<h2 id="live-reload">Live Reload</h2>
<p>Spring Boot Devtools를 통해 수정사항이 서버에 잘 적용되는 것은 확인할 수 있었지만 브라우저에서는 URL을 다시 호출하던가 Refresh를 해야만 확인할 수 있었는데 <code>Spring Boot Devtools</code>의 <code>Live Reload</code> 기능을 통해 <del>크롬에서만</del> 브라우저 재호출 없이 변경 사항을 확인할 수 있다.
크롬 브라우저에서 <a href="https://chrome.google.com/webstore/detail/livereload%20%20/ciehpookapcdlakedibajeccomagbfab">LiveReload++</a> 확장 프로그램을 설치하고 적용해주면 된다.</p>
<h2 id="롬복lombok">롬복(Lombok)</h2>
<p>롬복은 자바 클래스에 Getter, Setter, 생성자 등을 자동으로 만들어 주는 도구이다.
프로젝트를 진행하면서 데이터를 처리하기 위한 엔티티 클래스나 DTO 클래스등을 사용해야 하는데 이때 클래스의 속성들에 대한 Getter, Setter를 만들어야 한다.
물론 Getter, Setter 메서드를 직접 만들어도 되지만 롬복(lombok)을 사용하면 좀 더 깔끔한 소스코드를 만들수 있다.</p>
<h3 id="롬복-설치">롬복 설치</h3>
<p>롬복을 사용하려면 <a href="https://projectlombok.org/download">플러그인</a>을 먼저 설치 해야한다.
다운로드한 lombok.jar 파일을 실행시키고 다음과 같은 순서로 롬복을 설치한다.</p>
<pre><code>1. &quot;Specify location&quot;을 눌러 롬복 플러그인을 사용할 IDE인 STS가 설치된 경로를 선택한다.
2. &quot;Install / Update&quot;를 눌러 롬복 플러그인을 설치한다.
3. &quot;Quit Installer&quot;를 눌러 설치 프로그램을 종료한다.</code></pre><p>그리고 STS를 종료하고 재시작한 후 build.gradle 파일의 dependencies{} 안에 다음 코드를 추가해준다.</p>
<pre><code class="language-java">(...생략...)

dependencies {
    implementation &#39;org.springframework.boot:spring-boot-starter-web&#39;
    testImplementation &#39;org.springframework.boot:spring-boot-starter-test&#39;
    developmentOnly &#39;org.springframework.boot:spring-boot-devtools&#39;
    // 추가된 코드 -&gt;
    compileOnly &#39;org.projectlombok:lombok&#39;
    annotationProcessor &#39;org.projectlombok:lombok&#39;
    // &lt;-
}

(...생략...)</code></pre>
<p>롬복 관련 라이브러리를 설치하고 컴파일시 롬복이 적용되도록 했다.
build.gradle 파일을 수정한 후에는 반드시 프로젝트에 우클릭을 해서 <code>[Gradle -&gt; Refresh Gradle Project]</code>를 선택하여 라이브러리를 다운로드 해야 한다.</p>
<blockquote>
<p><strong>compileOnly</strong>
build.gradle 파일의 compileOnly는 해당 라이브러리가 컴파일 단계에서만 필요한 경우에 사용한다.<br>
<strong>annotationProcessor</strong>
컴파일 단계에서 애너테이션을 분석하고 처리하기 위해 사용한다.</p>
</blockquote>
<h3 id="getter-setter">Getter, Setter</h3>
<p>다음처럼 HelloLombok 클래스를 작성하여 롬복이 정상적으로 동작하는지 확인해본다.
아래 코드 작성시 오류가 없어야 한다.</p>
<pre><code class="language-java">package com.mysite.sbb;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class HelloLombok {

    private String hello;
    private int lombok;

    public static void main(String[] args) {
        HelloLombok helloLombok = new HelloLombok();
        helloLombok.setHello(&quot;헬로&quot;);
        helloLombok.setLombok(5);

        System.out.println(helloLombok.getHello());
        System.out.println(helloLombok.getLombok());
    }
}</code></pre>
<p>HelloLombok 클래스에 hello, lombok 2개의 속성을 추가한 후 클래스명 바로 위에 @Getter, @Setter라는 애너테이션을 적용했더니 Getter, Setter 메서드를 추가하지 않아도 setHello, setLombok, getHello, getLombok 등의 메서드를 사용할수 있게 되었다.</p>
<blockquote>
<p>롬복으로 컴파일된 클래스에는 Getter와 Setter 메서드가 실제로 포함된다</p>
</blockquote>
<h3 id="requiredargsconstructor">RequiredArgsConstructor</h3>
<p>이번에는 HelloLombok 클래스를 다음과 같이 수정해 보자.</p>
<pre><code class="language-java">package com.mysite.sbb;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Getter
public class HelloLombok {

    private final String hello;
    private final int lombok;

    public static void main(String[] args) {
        HelloLombok helloLombok = new HelloLombok(&quot;헬로&quot;, 5);
        System.out.println(helloLombok.getHello());
        System.out.println(helloLombok.getLombok());
    }
}</code></pre>
<p>hello, lombok 속성에 final을 적용하고 롬복의 @RequiredArgsConstructor 애너테이션을 적용하면 해당 속성을 필요로하는 생성자가 롬복에 의해 자동으로 생성된다. (※ final이 없는 속성은 생성자에 포함되지 않는다.)</p>
<blockquote>
<p>final을 적용했기 때문에 @Setter는 의미가 없으며 Setter 메서드들도 사용할수 없다. final은 한번 설정한 값을 변경할수 없게 하는 키워드이다.</p>
</blockquote>
<p>즉, 다음과 같이 생성자를 직접 작성한 경우와 동일하다.</p>
<pre><code class="language-java">package com.mysite.sbb;

import lombok.Getter;

@Getter
public class HelloLombok {

    private final String hello;
    private final int lombok;

    public HelloLombok(String hello, int lombok) {
        this.hello = hello;
        this.lombok = lombok;
    }

    public static void main(String[] args) {
        HelloLombok helloLombok = new HelloLombok(&quot;헬로&quot;, 5);
        System.out.println(helloLombok.getHello());
        System.out.println(helloLombok.getLombok());
    }
}</code></pre>
<p>@RequiredArgsConstructor 애너테이션은 이후 진행되는 챕터에서 의존성 주입(Dependency Injection)시 사용된다.</p>
<blockquote>
<p>DI(Dependency Injection) - 스프링이 객체를 대신 생성하여 주입한다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Error] dbcp.SQLNestedException - DB설정 에러]]></title>
            <link>https://velog.io/@bang_rr/Error-dbcp.SQLNestedException-DB%EC%84%A4%EC%A0%95-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@bang_rr/Error-dbcp.SQLNestedException-DB%EC%84%A4%EC%A0%95-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Tue, 26 Jul 2022 16:51:50 GMT</pubDate>
            <description><![CDATA[<p>org.apache.commons.dbcp.SQLNestedException : Cannot create PoolableConnectionFactory (IO 오류: The Network Adapter could not establish the connection)] with root cause
java.net.ConnectException: Connection refused: connect</p>
<p>위 에러는 톰캣을 실행했을 시에 톰캣과 DB가 제대로 연동되지 않을 때 발생하는 에러다.</p>
<p>DB 커넥션, SQL Session 등 스프링 내 jdbc 연결을 담당하고 있는 <strong>root-context.xml</strong> 파일을 찾아서 DB 설정을 확인해야 한다.
이 파일은 이름 및 경로가 개인마다 다를 수 있고, 구성에 따라 연결되어 있는 다른 파일을 수정해야 할 수도 있다.</p>
<p>context파일을 먼저 열어보았는데 db.properties파일로 연결되어 있었고 여기에서 DB커넥션 경로와 username 잘못 매핑되어 있었다.
db.username=test -&gt; c##test ( oracleDB버전에 따라 이름앞에 c##을 추가함 )
db.url=jdbc:oracle:thin:@경로 -&gt; 재설정</p>
<blockquote>
<p>참고
<a href="https://prinha.tistory.com/entry/Error-dbcpSQLNestedException-DB%EC%BB%A4%EB%84%A5%EC%85%98-%EC%97%90%EB%9F%AC">https://prinha.tistory.com/entry/Error-dbcpSQLNestedException-DB커넥션-에러</a>
<a href="https://snepbnt.tistory.com/246">https://snepbnt.tistory.com/246</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 11659번 구간 합 구하기 4]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-11659%EB%B2%88-%EA%B5%AC%EA%B0%84-%ED%95%A9-%EA%B5%AC%ED%95%98%EA%B8%B0-4</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-11659%EB%B2%88-%EA%B5%AC%EA%B0%84-%ED%95%A9-%EA%B5%AC%ED%95%98%EA%B8%B0-4</guid>
            <pubDate>Wed, 13 Jul 2022 06:34:38 GMT</pubDate>
            <description><![CDATA[<p>문제:
수 N개가 주어졌을 때, i번째 수부터 j번째 수까지 합을 구하는 프로그램을 작성하시오.</p>
<p>입력:
첫째 줄에 수의 개수 N과 합을 구해야 하는 횟수 M이 주어진다. 둘째 줄에는 N개의 수가 주어진다. 수는 1,000보다 작거나 같은 자연수이다. 셋째 줄부터 M개의 줄에는 합을 구해야 하는 구간 i와 j가 주어진다.</p>
<p>출력:
총 M개의 줄에 입력으로 주어진 i번째 수부터 j번째 수까지 합을 출력한다.</p>
<p>제출:</p>
<pre><code class="language-java">import java.io.IOException;
import java.util.Scanner;

public class Bj_11659 {
    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        StringBuilder sb = new StringBuilder();

        int n = sc.nextInt();
        int m = sc.nextInt();

        int[] arr = new int[n+1];
        int[] sum = new int[n+1];
        for (int i=1; i&lt;=n; i++) {
            arr[i] = sc.nextInt();
            sum[i] = sum[i-1] + arr[i];
        }

        for (int i=0; i&lt;m; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();

            sb.append(sum[b]-sum[a-1] + &quot;\n&quot;);
        }
        System.out.print(sb);
    }
}</code></pre>
<p>누적 합 문제는 입력받는 숫자배열에 들어가는 값이 바뀌지 않는다는 점을 이용해야 한다.
배열이 변하지 않으니 구간의 합도 변하지 않는다.
arr배열에 수를 입력받을 때 sum배열에도 구간의 합을 저장해준다.</p>
<pre><code class="language-java">sum[b] = arr[1]+...+arr[b];
sum[a-1] = arr[1]+...+arr[a-1];
sum[b] - sum[a-1] = arr[a]+...+arr[b]; // (1≤i≤j≤N)</code></pre>
<p>예를 들어 a=3, b=5이면 <code>arr[3]+arr[4]+arr[5]</code>의 값을 구해야 하는데
<code>sum[b] = arr[1]+...+arr[5]</code> 이고, <code>sum[a-1] = arr[1]+...+arr[2]</code>이므로
sum[b] - sum[a-1]을 하면 <code>sum[b] - sum[a-1] = arr[3]+...+arr[5]</code>라는 원하는 답이 나온다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 3009번 네 번째 점]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-3009%EB%B2%88-%EB%84%A4-%EB%B2%88%EC%A7%B8-%EC%A0%90</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-3009%EB%B2%88-%EB%84%A4-%EB%B2%88%EC%A7%B8-%EC%A0%90</guid>
            <pubDate>Sun, 03 Jul 2022 12:21:44 GMT</pubDate>
            <description><![CDATA[<p>문제:
세 점이 주어졌을 때, 축에 평행한 직사각형을 만들기 위해서 필요한 네 번째 점을 찾는 프로그램을 작성하시오.</p>
<p>입력:
세 점의 좌표가 한 줄에 하나씩 주어진다. 좌표는 1보다 크거나 같고, 1000보다 작거나 같은 정수이다.</p>
<p>출력:
직사각형의 네 번째 점의 좌표를 출력한다.</p>
<p>제출:</p>
<pre><code class="language-java">import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int[] x = new int [4];
        int[] y = new int [4];
        for (int i=0; i&lt;3; i++) {
            x[i] = sc.nextInt();
            y[i] = sc.nextInt();
        }

        if (x[0] != x[1]) {
            if (x[1] == x[2]) {
                x[3] = x[0];
            } else {
                x[3] = x[1];
            }
        } else {
            x[3] = x[2];
        }

        if (y[0] != y[1]) {
            if (y[1] == y[2]) {
                y[3] = y[0];
            } else {
                y[3] = y[1];
            }
        } else {
            y[3] = y[2];
        }
        System.out.println(x[3] + &quot; &quot; + y[3]);
        sc.close();
    }
}</code></pre>
<p>정답은 맞았는데 억지로 어떻게든 구현해낸 모습이 안쓰럽기도 하고 코딩 처음 배웠을 때 같은 느낌이다.
일단 내가 풀어본 방법은 3개의 점을 입력받았을 때 x, y 각각 한번만 입력된 좌표값이 있으면 그게 네 번째 좌표의 x, y값이 된다는 것을 이용해서 문제를 풀었다.
그래서 if-else 문으로만 문제를 해결할 수는 있었다.
그러나 맞았다고 그냥 넘어가면 실력이 향상될 리가 없기 때문에 다른 사람들의 풀이를 찾아보았다.</p>
<pre><code class="language-java">import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int x = 0, y = 0;
        for (int i = 0; i &lt; 3; i++) {
            x = x ^ sc.nextInt();
            y = y ^ sc.nextInt();
        }
        System.out.print(x + &quot; &quot; + y);
        sc.close();
    }
}</code></pre>
<p>처음에는 왜 XOR을 썼을까 생각을 했고, 하나하나 적어본 뒤에 이해했을때는 감탄스러웠다.
비트 XOR 연산자를 사용하면 다음과 같은 특성을 볼 수 있다.  <code>a^b=c</code>, <code>c^b=a</code>, <code>c^a=b</code>
또한 XOR 연산자를 가지고 d라는 숫자와 0을 연산하면 d가 나온다. <code>d^0=d</code>
이를 이용해서 예를 들어 <code>5 5</code>, <code>5 7</code>, <code>7 5</code> 세 개의 점을 입력받았을 때 처음 두 점의  x좌표만 연산했을 때 <code>5^5=0</code> 이 나오고 0을 세 번째 점과 연산을 하면 <code>0^7=7</code> 이라는 값이 나오는데 이것이 네 번째 점의 x좌표(7)가 된다.
y좌표도 계산을 해보면 <code>5^7=2</code> 라는 의미없어 보이는 2가 나오게 되는데 세 번째 점과 연산을 하면 <code>2^5=7</code> 이라는 값이 나오게 되고 이것이 네 번째 점의 y좌표(7)가 된다.</p>
<p>XOR을 단순히 비트연산에서의 0과 1의 논리 연산자로써만 생각했었는데, 위에서 봤던 특성을 이용해 암/복호화에서도 사용된다는 것을 알 수 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 10989번 수 정렬하기 3]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-10989%EB%B2%88-%EC%88%98-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0-3</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-10989%EB%B2%88-%EC%88%98-%EC%A0%95%EB%A0%AC%ED%95%98%EA%B8%B0-3</guid>
            <pubDate>Tue, 28 Jun 2022 05:29:53 GMT</pubDate>
            <description><![CDATA[<p>문제:
N개의 수가 주어졌을 때, 이를 오름차순으로 정렬하는 프로그램을 작성하시오.</p>
<p>입력:
첫째 줄에 수의 개수 N(1 ≤ N ≤ 10,000,000)이 주어진다. 둘째 줄부터 N개의 줄에는 수가 주어진다. 이 수는 10,000보다 작거나 같은 자연수이다.</p>
<p>출력:
첫째 줄부터 N개의 줄에 오름차순으로 정렬한 결과를 한 줄에 하나씩 출력한다.</p>
<p>제출:</p>
<pre><code class="language-java">import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;

public class Bj_10989 {
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        int n = Integer.parseInt(br.readLine());

        int[] a = new int[n];
        for (int i=0; i&lt;n; i++) {
            a[i] = Integer.parseInt(br.readLine());
        }
        Arrays.sort(a);
        for (int i=0; i&lt;n; i++) {
            bw.write(a[i] + &quot;\n&quot;);
        }
        bw.flush();
    }
}</code></pre>
<p>어제 해결한 <a href="https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-15552%EB%B2%88-%EB%B9%A0%EB%A5%B8-AB">[백준] 15552번 빠른 A+B</a> 문제를 통해 공부했던 <code>BufferReader, BufferWriter, StringTokenizer</code>를 사용해서 문제를 해결해보았다.
로직으로는 처음 입력받은 n개의 수를 <code>br.readLine();</code>을 사용해서 배열에 저장하고, 배열을 <code>Arrays.sort(a);</code> 코드를 사용해서 오름차순 정렬을 해주고 난 다음 반복문을 사용해서 <code>bw.write(a[i] + &quot;\n&quot;);</code> 코드를 사용하여 버퍼에 저장해주고 <code>bw.flush();</code> 코드를 사용해 한꺼번에 출력을 해주었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 15552번 빠른 A+B]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-15552%EB%B2%88-%EB%B9%A0%EB%A5%B8-AB</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-15552%EB%B2%88-%EB%B9%A0%EB%A5%B8-AB</guid>
            <pubDate>Tue, 28 Jun 2022 02:19:46 GMT</pubDate>
            <description><![CDATA[<p>문제:
본격적으로 for문 문제를 풀기 전에 주의해야 할 점이 있다. 입출력 방식이 느리면 여러 줄을 입력받거나 출력할 때 시간초과가 날 수 있다는 점이다.</p>
<p>Java를 사용하고 있다면, Scanner와 System.out.println 대신 BufferedReader와 BufferedWriter를 사용할 수 있다. BufferedWriter.flush는 맨 마지막에 한 번만 하면 된다.</p>
<p>또한 입력과 출력 스트림은 별개이므로, 테스트케이스를 전부 입력받아서 저장한 뒤 전부 출력할 필요는 없다. 테스트케이스를 하나 받은 뒤 하나 출력해도 된다.</p>
<p>입력:
첫 줄에 테스트케이스의 개수 T가 주어진다. T는 최대 1,000,000이다. 다음 T줄에는 각각 두 정수 A와 B가 주어진다. A와 B는 1 이상, 1,000 이하이다.</p>
<p>출력:
각 테스트케이스마다 A+B를 한 줄에 하나씩 순서대로 출력한다.</p>
<p>제출:</p>
<pre><code class="language-java">import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Bj_15552 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st;

        int t = Integer.parseInt(br.readLine());

        for (int i=0; i&lt;t; i++) {
            st = new StringTokenizer(br.readLine());

            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            bw.write(a+b + &quot;\n&quot;);
        }
        bw.flush();
        bw.close();
    }
}</code></pre>
<p>이 문제를 처음에는 <code>BufferReader, BufferWriter, StringTokenizer</code> 를 사용해서 풀어보았다. 기본적인 사용법을 익히는 시간이였다. 근데 볼수록 코드가 너무 복잡해서 더 간단한 방법이 없나 찾아보게 되었고, 아래 코드처럼 <code>StringBuilder</code> 라는 것을 찾아서 한번 더 풀어보았다.</p>
<pre><code class="language-java">import java.util.Scanner;

public class Bj_15552_2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        StringBuilder sb = new StringBuilder();

        int t = sc.nextInt();

        for (int i=0; i&lt;t; i++) {
            sb.append(sc.nextInt() + sc.nextInt() + &quot;\n&quot;);
        }
        System.out.println(sb);
        sc.close();
    }
}</code></pre>
<p>훨씬 더 코드가 간단해졌지만 <code>Scanner</code>와 <code>StringBuilder</code>를 같이 사용해서 그런지 <del>코드 길이는 줄어들었지만</del> 처리시간이 길어졌다.
<img src="https://velog.velcdn.com/images/bang_rr/post/ca67160f-2e92-480a-ac70-127329c1df27/image.png" alt=""></p>
<p>위: <code>Scanner, StringBuilder</code>사용
아래: <code>BufferReader, BufferWriter, StringTokenizer</code>사용</p>
<p><code>StringBuilder</code>는 감을 잡았는데 <code>BufferReader, BufferWriter, StringTokenizer</code>에 대해서 조금 더 공부가 필요한 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 1181번 단어 정렬]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-1181%EB%B2%88-%EB%8B%A8%EC%96%B4-%EC%A0%95%EB%A0%AC</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-1181%EB%B2%88-%EB%8B%A8%EC%96%B4-%EC%A0%95%EB%A0%AC</guid>
            <pubDate>Mon, 27 Jun 2022 06:26:55 GMT</pubDate>
            <description><![CDATA[<p>문제:
알파벳 소문자로 이루어진 N개의 단어가 들어오면 아래와 같은 조건에 따라 정렬하는 프로그램을 작성하시오.</p>
<ol>
<li>길이가 짧은 것부터</li>
<li>길이가 같으면 사전 순으로</li>
</ol>
<p>입력:
첫째 줄에 단어의 개수 N이 주어진다. (1 ≤ N ≤ 20,000) 둘째 줄부터 N개의 줄에 걸쳐 알파벳 소문자로 이루어진 단어가 한 줄에 하나씩 주어진다. 주어지는 문자열의 길이는 50을 넘지 않는다.</p>
<p>출력:
조건에 따라 정렬하여 단어들을 출력한다. 단, 같은 단어가 여러 번 입력된 경우에는 한 번씩만 출력한다.</p>
<p>제출:</p>
<pre><code class="language-java">import java.util.Arrays;
import java.util.Scanner;

public class Bj_1181 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        String[] arr = new String[n];

        for (int i=0; i&lt;n; i++) {
            arr[i] = sc.next();
        }
        Arrays.sort(arr);

        if (n&gt;1) {
            for (int j=1; j&lt;=50; j++) {
                for (int i=0; i&lt;n; i++) {
                    if (i==n-1 &amp;&amp; arr[i].length() == j) {
                            System.out.println(arr[i]);
                    } else if (arr[i].length() == j &amp;&amp; !(arr[i].equals(arr[i+1]))) {
                            System.out.println(arr[i]);
                    }
                }
            }
        } else if (n==1) {
            System.out.println(arr[0]);
        }
        sc.close();
    }
}</code></pre>
<p>문제에서 주어진 조건은 길이가 짧은 것 부터 길이가 같으면 사전 순으로 출력하는 프로그램이다.
그래서 나는 먼저 <code>Arrays.sort(arr);</code>를 통해 사전순으로 정렬을 했고, 그 이후에 배열에 저장한 문자열들 중에 길이가 짧은 것 부터 가져오면서 뒤에 있는 배열과 비교하면서 중복인 경우에는 출력되지 않도록 해서 마지막 남은 배열값은 체크할 필요없이 출력하도록 하였다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 1712번 손익분기점]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-1712%EB%B2%88-%EC%86%90%EC%9D%B5%EB%B6%84%EA%B8%B0%EC%A0%90</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-1712%EB%B2%88-%EC%86%90%EC%9D%B5%EB%B6%84%EA%B8%B0%EC%A0%90</guid>
            <pubDate>Fri, 24 Jun 2022 15:20:30 GMT</pubDate>
            <description><![CDATA[<p>문제:
월드전자는 노트북을 제조하고 판매하는 회사이다. 노트북 판매 대수에 상관없이 매년 임대료, 재산세, 보험료, 급여 등 A만원의 고정 비용이 들며, 한 대의 노트북을 생산하는 데에는 재료비와 인건비 등 총 B만원의 가변 비용이 든다고 한다.</p>
<p>예를 들어 A=1,000, B=70이라고 하자. 이 경우 노트북을 한 대 생산하는 데는 총 1,070만원이 들며, 열 대 생산하는 데는 총 1,700만원이 든다.</p>
<p>노트북 가격이 C만원으로 책정되었다고 한다. 일반적으로 생산 대수를 늘려 가다 보면 어느 순간 총 수입(판매비용)이 총 비용(=고정비용+가변비용)보다 많아지게 된다. 최초로 총 수입이 총 비용보다 많아져 이익이 발생하는 지점을 손익분기점(BREAK-EVEN POINT)이라고 한다.</p>
<p>A, B, C가 주어졌을 때, 손익분기점을 구하는 프로그램을 작성하시오.</p>
<p>입력:
첫째 줄에 A, B, C가 빈 칸을 사이에 두고 순서대로 주어진다. A, B, C는 21억 이하의 자연수이다.</p>
<p>출력:
첫 번째 줄에 손익분기점 즉 최초로 이익이 발생하는 판매량을 출력한다. 손익분기점이 존재하지 않으면 -1을 출력한다.</p>
<p>제출:</p>
<pre><code class="language-java">import java.util.Scanner;

public class Bj_1712 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();
        int c = sc.nextInt();

        if (b&gt;=c) {
            System.out.println(-1);
        } else {
            System.out.println(a/(c-b)+1);
        }
        sc.close();
    }
}</code></pre>
<p>손익분기점이 나오려면 b 보다 c 가 커야 하고, a인 초기비용이므로 한 개씩 더 생산했을때 수입은 c-b씩 증가해서 최초로 이익이 발생하는 판매량은 <code>a/(c-b)+1</code>로 계산해 줄 수 있다.</p>
<p>실수:
문제를 보고는 쉬운 문제라고 생각하고 쉽게 덤벼들었다. 단순하게 수학식을 세워보았다.
<code>a + b*cnt &lt; c*cnt</code> 라는 식이 성립하는 <code>cnt</code> 값을 찾으면 된다고 생각했다.</p>
<pre><code class="language-java">if (b&gt;=c) {
    System.out.println(-1);
} else {
    while(a+b*cnt &gt;= c*cnt) {
        cnt++;
    }
    System.out.println(cnt);
}</code></pre>
<p>첫 시도는 틀렸습니다..? 다시 차근차근 문제랑 코드를 보고서는 아 이게 a,b,c는 int형일 수 있지만 <code>a+b*cnt</code>를 계산했을때는 int형을 넘어가는 구나 하고 long형으로 수정해서 다시 제출 해보았다.
결과는 시간초과... <del>맞는데 왜 틀리지 생각이 들었다</del>
<img src="https://velog.velcdn.com/images/bang_rr/post/ed82e160-7330-463f-8a30-5704ac4c42eb/image.png" alt=""></p>
<p>다시 내가 세웠던 식을 쳐다보았다. <code>a + b*cnt &lt; c*cnt</code>
흠... cnt가 중복해서 들어가니까 정리를 해보았다.  <code>a &lt; (c-b)*cnt</code>
그러고는 예제 입,출력을 보았더니 패턴이 보였다.
입력 1000 70 170 -&gt; 출력 11 , 입력 2100000000 9 10 -&gt; 출력 2100000001
그렇다 c-b를 계산한 것으로 a를 나누면 손익분기점을 아쉽게 넘기지 못한 판매량이 나오고 여기서 한 개만 더 만들면 손익분기점을 넘는 지점이 되는 것이었다.
다시 변수들을 int형으로 다 수정하고 코드도 간단하게 <code>a/(c-b)+1</code> 로 정리를 했더니 문제가 해결되었다.</p>
<p>문제를 항상 꼼꼼히 읽어서 힌트를 잘 얻어내고 예제부터 먼저 체크하고 입력할 수 있는 특이한 케이스까지 생각해서 문제를 잘 해결해 낼 수 있도록 더욱 노력해야겠다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 2798번 블랙잭]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-2798%EB%B2%88-%EB%B8%94%EB%9E%99%EC%9E%AD</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-2798%EB%B2%88-%EB%B8%94%EB%9E%99%EC%9E%AD</guid>
            <pubDate>Thu, 16 Jun 2022 07:39:26 GMT</pubDate>
            <description><![CDATA[<p>문제:
카지노에서 제일 인기 있는 게임 블랙잭의 규칙은 상당히 쉽다. 카드의 합이 21을 넘지 않는 한도 내에서, 카드의 합을 최대한 크게 만드는 게임이다. 블랙잭은 카지노마다 다양한 규정이 있다.</p>
<p>한국 최고의 블랙잭 고수 김정인은 새로운 블랙잭 규칙을 만들어 상근, 창영이와 게임하려고 한다.</p>
<p>김정인 버전의 블랙잭에서 각 카드에는 양의 정수가 쓰여 있다. 그 다음, 딜러는 N장의 카드를 모두 숫자가 보이도록 바닥에 놓는다. 그런 후에 딜러는 숫자 M을 크게 외친다.</p>
<p>이제 플레이어는 제한된 시간 안에 N장의 카드 중에서 3장의 카드를 골라야 한다. 블랙잭 변형 게임이기 때문에, 플레이어가 고른 카드의 합은 M을 넘지 않으면서 M과 최대한 가깝게 만들어야 한다.</p>
<p>N장의 카드에 써져 있는 숫자가 주어졌을 때, M을 넘지 않으면서 M에 최대한 가까운 카드 3장의 합을 구해 출력하시오.</p>
<p>입력:
첫째 줄에 카드의 개수 N(3 ≤ N ≤ 100)과 M(10 ≤ M ≤ 300,000)이 주어진다. 둘째 줄에는 카드에 쓰여 있는 수가 주어지며, 이 값은 100,000을 넘지 않는 양의 정수이다.</p>
<p>합이 M을 넘지 않는 카드 3장을 찾을 수 있는 경우만 입력으로 주어진다.</p>
<p>출력:
첫째 줄에 M을 넘지 않으면서 M에 최대한 가까운 카드 3장의 합을 출력한다.</p>
<p>제출:</p>
<pre><code class="language-java">import java.util.Arrays;
import java.util.Scanner;

public class Bj_2798 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[] a = new int[n];

        for (int i=0; i&lt;n; i++) {
            a[i] = sc.nextInt();
        }
        sc.close();

        int t=0;
        int[] tmp = new int[n*(n-1)*(n-2)/6];
        while (t &lt; tmp.length) {
            for (int i=0; i&lt;n-2; i++) {
                for (int j=i+1; j&lt;n-1; j++) {
                    for (int k=j+1; k&lt;n; k++) {
                        tmp[t] = a[i] + a[j] + a[k] &lt;= m ? a[i] + a[j] + a[k] : 0;
                        t++;
                    }
                }
            }
        }
        Arrays.sort(tmp);
        System.out.println(tmp[tmp.length-1]);
    }
}</code></pre>
<p>3장의 카드씩 더해야 되는 것을 보고 어떻게 한번에 핸들링 할 수 있을까 하다가 결국 반복문을 3번을 돌리는 선택을 했고, 카드 3장의 합들 중에서 m보다 크지 않은 합을 임시 배열에 저장을 한 뒤 오름차순 정렬을 하고 그 중에서 m에 최대한 가까운 수를 출력하도록 하였다.</p>
<p>처음 제출은 이렇게 하였지만 생각해보니까 굳이 이렇게 풀어야 되나 싶었다.
그래서 배열이 아니라 단순히 <code>max</code>에 조건에 맞는 값을 대입하는 식으로 다시 풀어보았다.</p>
<pre><code class="language-java">int max=0;
for (int i=0; i&lt;n-2; i++) {
    for (int j=i+1; j&lt;n-1; j++) {
        for (int k=j+1; k&lt;n; k++) {
            if (a[i] + a[j] + a[k] &lt;= m &amp;&amp; a[i] + a[j] + a[k] &gt; max) {
                max = a[i] + a[j] + a[k];
            }
        }
    }
}
System.out.println(max);</code></pre>
<p>이렇게 하고 나니 불필요하게 tmp배열과 while반복문을 사용할 필요가 없고 더 깔끔해졌다.
이 문제에서 중요한 것은 <code>i, j, k</code>를 통한 3중 반복문의 범위를 잘 설정하고 조작하는 능력이였다고 생각한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 10699번 오늘 날짜]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-10699%EB%B2%88-%EC%98%A4%EB%8A%98-%EB%82%A0%EC%A7%9C</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-10699%EB%B2%88-%EC%98%A4%EB%8A%98-%EB%82%A0%EC%A7%9C</guid>
            <pubDate>Wed, 15 Jun 2022 04:57:12 GMT</pubDate>
            <description><![CDATA[<p>문제:
서울의 오늘 날짜를 출력하는 프로그램을 작성하시오.</p>
<p>입력:
입력은 없다.</p>
<p>출력:
서울의 오늘 날짜를 &quot;YYYY-MM-DD&quot; 형식으로 출력한다.</p>
<p>제출:</p>
<pre><code class="language-java">import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class Bj_10699 {
    public static void main(String[] args) {
        Date date = new Date();
        DateFormat df = new SimpleDateFormat(&quot;YYYY-MM-dd&quot;);
        df.setTimeZone(TimeZone.getTimeZone(&quot;Asia/Seoul&quot;));
        System.out.println(df.format(date));
    }
}</code></pre>
<p>단순히 <code>System.out.println(&quot;2022-06-15&quot;);</code> 라고 해서 풀 수 있는 문제였다.
하지만 아래 힌트를 보았을 때, date 명령어라는 말이 나오는 것을 보고 <code>Date</code> 클래스를 사용해서 풀어보기로 마음을 먹었다.
<code>Date</code> 클래스를 통해서 현재 시간을 가져왔고, <code>SimpleDateFormat</code>으로 <code>YYYY-MM-dd</code> 형식을 잡아주었고, 채점 서버의 시간대가 UTC+0 이라는 것을 감안하여 문제에서 처럼 정확하게 서울의 날짜를 출력하려고 <code>TimeZone</code>을 설정하였다.</p>
<p>답안을 제출한 후, 다른 사람들의 풀이도 보려고 찾아보니 단순 출력으로 푼 사람들도 많았고, <code>LocalDate</code> 클래스를 사용하였던데, 이것은 현지 시간을 나타내는 클래스로 알고 있다.
만약 문제가 시간까지 나타낸다던가, 오전 9시이전에 제출을 하였으면 오답으로 처리되었을 거라고 생각한다.
문제처럼 정확히 <code>TimeZone</code>이 나와있는 경우에는 설정을 해주는게 맞다고 생각한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 4153번 직각삼각형]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-4153%EB%B2%88-%EC%A7%81%EA%B0%81%EC%82%BC%EA%B0%81%ED%98%95</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-4153%EB%B2%88-%EC%A7%81%EA%B0%81%EC%82%BC%EA%B0%81%ED%98%95</guid>
            <pubDate>Mon, 13 Jun 2022 13:43:09 GMT</pubDate>
            <description><![CDATA[<p>문제:
과거 이집트인들은 각 변들의 길이가 3, 4, 5인 삼각형이 직각 삼각형인것을 알아냈다. 주어진 세변의 길이로 삼각형이 직각인지 아닌지 구분하시오.</p>
<p>입력:
입력은 여러개의 테스트케이스로 주어지며 마지막줄에는 0 0 0이 입력된다. 각 테스트케이스는 모두 30,000보다 작은 양의 정수로 주어지며, 각 입력은 변의 길이를 의미한다.</p>
<p>출력:
각 입력에 대해 직각 삼각형이 맞다면 &quot;right&quot;, 아니라면 &quot;wrong&quot;을 출력한다.</p>
<p>제출:</p>
<pre><code class="language-java">import java.util.Arrays;
import java.util.Scanner;

public class Bj_4153 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int[] a = new int[3];

        while(true) {
            for (int i=0; i&lt;a.length; i++) {
                a[i] = sc.nextInt();
            }
            if (a[0]==0 &amp;&amp; a[1]==0 &amp;&amp; a[2]==0) {
                break;
            }
            Arrays.sort(a);
            if (a[0]*a[0] + a[1]*a[1] == a[2]*a[2]) {
                System.out.println(&quot;right&quot;);
            } else {
                System.out.println(&quot;wrong&quot;);
            }
        }
        sc.close();
    }
}</code></pre>
<p>숫자 3개를 입력받는데 어떤 숫자가 가장 큰 숫자 인지를 모르기 때문에 정수형 배열에 입력을 받아 <code>Arrays.sort(a);</code>를 통해서 오름차순으로 정렬을 해놓고 피타고라스 정리 a<sup>2</sup> + b<sup>2</sup> = c<sup>2</sup> 에 맞춰서 식을 세워서 풀었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[포맷까지 간 "git clean -f -d -x"]]></title>
            <link>https://velog.io/@bang_rr/%ED%8F%AC%EB%A7%B7%EA%B9%8C%EC%A7%80-%EA%B0%84-git-clean-f-d-x</link>
            <guid>https://velog.io/@bang_rr/%ED%8F%AC%EB%A7%B7%EA%B9%8C%EC%A7%80-%EA%B0%84-git-clean-f-d-x</guid>
            <pubDate>Sat, 11 Jun 2022 13:54:47 GMT</pubDate>
            <description><![CDATA[<p>eclipse IDE에서 git terminal을 이용해서 &quot;git add .&quot;을 했는데 Untracked 파일과 디렉토리가 많아서 add명령을 취소하고 싶어서 찾아보다가 &quot;git clean -f -d -x&quot;라는 명령어를 입력하였는데 수많은 로그들이 지나가더니 내 컴퓨터의 작업표시줄과 바탕화면 폴더는 아래와 같이 변해버렸다. <del>백업하지 않은 여러 문서들과 파일들...</del>
<img src="https://velog.velcdn.com/images/bang_rr/post/ebab0c17-4cb6-4ffd-9c8b-ea0b62e0709c/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/bang_rr/post/5f870bcf-f266-4fcc-8be5-d0280aaf5473/image.png" alt=""></p>
<p>상황을 알아차린 순간 머리가 뜨거워지고 바탕화면처럼 되어버렸다. 대체 왜 이런 일이 일어났는지 찾아보니까 이게 <strong>실제로 파일이 삭제되는줄도 몰랐고</strong> 경로가 root(~) 즉, &quot;<strong>C:\Users\username</strong>&quot;으로 되어있던 것이다. 정신차리고 다시 보니 내가 따라하던 유튜버가 설명을 해주지는 않았지만 나는 <strong>경로설정이 되어있지 않았다.</strong> 어이없고 허탈하면서도 작업이 이루어지는 경로조차 확인하지 못한 내가 한심했다.
이번 일을 경험으로 삼아 절대 비슷한 실수를 하지 않기를 바라는 마음에서 기록을 남겼다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 2675번 문자열 반복]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-2675%EB%B2%88-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%B0%98%EB%B3%B5</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-2675%EB%B2%88-%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%B0%98%EB%B3%B5</guid>
            <pubDate>Sat, 11 Jun 2022 13:17:43 GMT</pubDate>
            <description><![CDATA[<p>문제:
문자열 S를 입력받은 후에, 각 문자를 R번 반복해 새 문자열 P를 만든 후 출력하는 프로그램을 작성하시오. 즉, 첫 번째 문자를 R번 반복하고, 두 번째 문자를 R번 반복하는 식으로 P를 만들면 된다. S에는 QR Code &quot;alphanumeric&quot; 문자만 들어있다.</p>
<p>QR Code &quot;alphanumeric&quot; 문자는 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$%*+-./: 이다.</p>
<p>입력:
첫째 줄에 테스트 케이스의 개수 T(1 ≤ T ≤ 1,000)가 주어진다. 각 테스트 케이스는 반복 횟수 R(1 ≤ R ≤ 8), 문자열 S가 공백으로 구분되어 주어진다. S의 길이는 적어도 1이며, 20글자를 넘지 않는다. </p>
<p>출력:
각 테스트 케이스에 대해 P를 출력한다.</p>
<p>제출: </p>
<pre><code class="language-java">import java.util.Scanner;

public class Bj_2675 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();

        for (int i=0; i&lt;t; i++) {
            int r = sc.nextInt();
            String s = sc.next();

            for (int j=0; j&lt;s.length(); j++) {
                for (int k=0; k&lt;r; k++) {
                    System.out.print(s.charAt(j));
                }
            }
            System.out.println();
        }
        sc.close();
    }
}</code></pre>
<p>이중 반복문을 통해서 예를 들어 입력이 &quot;5 /HTP&quot; 이면 출력이 &quot;/////HHHHHTTTTTPPPPP&quot;로 나오게 문자 s의 한 글자씩 입력받은 숫자 r만큼 반복하는 형태로 만들었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 1546번 평균]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-1546%EB%B2%88-%ED%8F%89%EA%B7%A0</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-1546%EB%B2%88-%ED%8F%89%EA%B7%A0</guid>
            <pubDate>Tue, 31 May 2022 14:04:47 GMT</pubDate>
            <description><![CDATA[<p>문제:
세준이는 기말고사를 망쳤다. 세준이는 점수를 조작해서 집에 가져가기로 했다. 일단 세준이는 자기 점수 중에 최댓값을 골랐다. 이 값을 M이라고 한다. 그리고 나서 모든 점수를 점수/M*100으로 고쳤다.</p>
<p>예를 들어, 세준이의 최고점이 70이고, 수학점수가 50이었으면 수학점수는 50/70*100이 되어 71.43점이 된다.
세준이의 성적을 위의 방법대로 새로 계산했을 때, 새로운 평균을 구하는 프로그램을 작성하시오.</p>
<p>입력:
첫째 줄에 시험 본 과목의 개수 N이 주어진다. 이 값은 1000보다 작거나 같다. 둘째 줄에 세준이의 현재 성적이 주어진다. 이 값은 100보다 작거나 같은 음이 아닌 정수이고, 적어도 하나의 값은 0보다 크다.</p>
<p>출력:
첫째 줄에 새로운 평균을 출력한다. 실제 정답과 출력값의 절대오차 또는 상대오차가 10-2 이하이면 정답이다.</p>
<p>제출:</p>
<pre><code class="language-java">import java.util.Scanner;

public class Bj_1546 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        double[] score = new double[n];

        double max = 0;
        double sum = 0;

        for (int i=0; i&lt;n; i++) {
            score[i] = sc.nextInt();
            max = max &lt; score[i] ? score[i] : max;
        }

        for (int j=0; j&lt;n; j++) {
            score[j] = score[j]/max*100;
            sum += score[j];
        }

        sc.close();
        System.out.println(sum/n);
    }
}</code></pre>
<p>입력한 N개의 점수를 입력받으면서 최댓값을 구해놓고, 점수들을 새로운 방법에 맞게 수정한 후 평균을 출력하면 되는 int형과 double형만 구별하면 되는 간단한 문제였다.</p>
<p>정수형으로 계산하면 나눗셈(/) 계산에서 몫만 남게되어 점수 수정이나 평균 계산이 틀릴 수 있으니 double형으로 까먹지 말고 하도록 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 2562번 최댓값]]></title>
            <link>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-2562%EB%B2%88-%EC%B5%9C%EB%8C%93%EA%B0%92</link>
            <guid>https://velog.io/@bang_rr/%EB%B0%B1%EC%A4%80-2562%EB%B2%88-%EC%B5%9C%EB%8C%93%EA%B0%92</guid>
            <pubDate>Mon, 30 May 2022 07:45:22 GMT</pubDate>
            <description><![CDATA[<p>문제:
9개의 서로 다른 자연수가 주어질 때, 이들 중 최댓값을 찾고 그 최댓값이 몇 번째 수인지를 구하는 프로그램을 작성하시오.</p>
<p>예를 들어, 서로 다른 9개의 자연수 3, 29, 38, 12, 57, 74, 40, 85, 61 이 주어지면,
이들 중 최댓값은 85이고, 이 값은 8번째 수이다.</p>
<p>입력:
첫째 줄부터 아홉 번째 줄까지 한 줄에 하나의 자연수가 주어진다. 주어지는 자연수는 100 보다 작다.</p>
<p>출력:
첫째 줄에 최댓값을 출력하고, 둘째 줄에 최댓값이 몇 번째 수인지를 출력한다.</p>
<p>제출:</p>
<pre><code class="language-java">import java.util.Scanner;

public class Bj_2562 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int[] a = new int[9];

        int max = 0;
        int idx = 0;
        for (int i=0; i&lt;a.length; i++) {
            a[i] = sc.nextInt();
            if (max &lt; a[i]) {
                max = a[i];
                idx = i+1;
            }
        }
        sc.close();

        System.out.println(max);
        System.out.println(idx);
    }
}</code></pre>
<p>정수형 배열에 자연수들을 입력받아 하나씩 비교해서 최댓값을 구했고,
배열인덱스는 0부터 시작이므로 idx=i+1 로 몇 번째 수인지 계산하였다.</p>
]]></description>
        </item>
    </channel>
</rss>