[Tistory] [내배캠][TIL] 9일 차 – 목요일, 알고리즘 문제 풀이 시작과 개인 과제

원글 페이지 : 바로가기

📢 오늘의 목표 📢 ✔️ 알고리즘 특강 ✔️ 알고리즘, SQL 문제 풀이 ✔️ 데일리 루틴 알고리즘 ✔️ 데일리 루틴 SQL ✔️ 프로그래머스 Level 1 ✔️ Java 문법 강의 보충 ✔️ 5강 숙제 ✔️ Lock, Condition ✔️ 개인 과제 Level 2 ⏱️ 오늘의 일정 ⏱️ 9:00 ~ 10:30 – 알고리즘 특강 10:30 ~ 12:30 – 알고리즘, SQL 문제 풀이 12:30 ~ 13:00 – 개인 공부 (강의 숙제) 12:30 ~ 14:00 – 점심시간 14:00 ~ 17:00 – 개인 과제 Level 2 17:00 ~ 18:00 – 머리 식히기 (인텔리제이 깃 사용법 서치, 스프링 책 서치) 18:00 ~ 19:00 – 저녁 시간 19:00 ~ 20:00 – 개인 공부 (5강 놓친 부분) 20:00 ~ 21:00 – TIL 작성 📜 Chapter 1. 알고리즘 특강 9:00 ~ 10:30 – 알고리즘 특강 ✔️ 알고리즘 특강 알고리즘에 대해 학교에서 배운 적이 없고 오롯이 독학했었기 때문에 이번 특강을 좀 기대했었는데 완전 초보자 대상 강의였어서 다 아는 내용이라 좀 아쉬웠다. 그래도 내일은 알고리즘 심화 특강이 있다고 하니 또 내일을 기다려야지! 그리고 나만 몰랐는지 데일리 루틴이라는 시트에 매일 풀 알고리즘, SQL 문제가 제시되어 있었다! 이럴 수가! 밀린 거 오늘 빨리 다 풀어야겠다. 📜 Chapter 2. 알고리즘, SQL 문제 풀이 10:30 ~ 12:30 – 알고리즘, SQL 문제 풀이 ✔️ 알고리즘, SQL 문제 풀이 ✔️ 데일리 루틴 알고리즘 ✔️ 데일리 루틴 SQL ✔️ 프로그래머스 Level 1 ✔️ 데일리 루틴 알고리즘 왕창 밀려 있지만 다행히 간단한 문제들이다. 다만 나는 프로그래머스 문제를 처음 풀어봤는데 여기 에디터에서 문제를 푸려니 코드 자동완성, 에러표시가 되지 않는다는 게 힘들다 ㅠㅠ 오타가 정말 꼭 빠지지 않고 난다. 코드는 이걸 굳이 써 놓을 필요가 있을까? 정도로 쉽지만 일단 남겨 놓는다. 주석이나 설명은 굳이 안 달았다… 두 수의 차 class Solution {
public int solution(int num1, int num2) {
int answer = 0;
answer = num1 – num2;
return answer;
}
} 두 수의 곱 class Solution {
public int solution(int num1, int num2) {
int answer = 0;
answer = num1 * num2;
return answer;
}
} 몫 구하기 class Solution {
public int solution(int num1, int num2) {
int answer = 0;
answer = num1 / num2;
return answer;
}
} 나이 출력 class Solution {
public int solution(int age) {
int answer = 0;
answer = 2022 – age + 1;
return answer;
}
} ✔️ 데일리 루틴 SQL SQL 문제는 처음 풀어보지만 난 SQLD도 딴 사람… 적응에만 좀 시간이 걸렸지 이 정도는 아무 문제없었다. 이름이 있는 동물의 아이디 SELECT ANIMAL_ID
FROM ANIMAL_INS
WHERE NAME IS NOT NULL
ORDER BY 1 역순 정렬하기 SELECT NAME, DATETIME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID DESC 중복 제거하기 SELECT COUNT(DISTINCT NAME)
FROM ANIMAL_INS
WHERE NAME IS NOT NULL 동물의 아이디와 이름 SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID 그리고 코드카타를 제출하려고 하니 깃허브 링크를 작성하라는데… 1년 전 내가 자동으로 올라가게 하는 법을 써 놨으니까 모두 참고하도록 하자 ㅋㅋ https://mountain-noroo.tistory.com/38 백준 GitHub 연동 손쉽게 하기 오늘은 흥미로운 구글 확장 프로그램을 발견해서 포스팅하려 한다. 무엇이냐 하면, 제목에서 볼 수 있듯이 백준을 풀면 내 GitHub에 자동으로 커밋해 주는 프로그램이다. (프로그래머스, SW Expert Ac mountain-noroo.tistory.com 나는 이 참에 새로운 레포지터리를 만들어서 다시 연동했다. 근데 오늘 문제들을 이미 풀어서 자동으로 올라가지지 않는다 ㅠㅠ 깃헙 작성은 필수가 아닌 듯 하니 그냥 내일부터 올리자. 귀찮다. ✔️ 프로그래머스 Level 1 레벨 2를 바로 들어가자니 나도 알고리즘 문제 풀이가 너무 오랜만이라 레벨 1 문제를 좀 풀어보았다. 별 어려운 문제도 아닌데 1시간이나 걸리고 정리하는 시간까지 30분 추가… 그래도 내일부터는 푸는 시간이 좀 빨라지겠거니 기대한다. 해당 문제에 대한 해설은 따로 포스팅했으니 아래를 참고! https://mountain-noroo.tistory.com/127 [프로그래머스][Java] 가장 많이 받은 선물 – level 1 문제 보기https://school.programmers.co.kr/learn/courses/30/lessons/258712 프로그래머스코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합 mountain-noroo.tistory.com 📜 Chapter 3. Java 문법 강의 보충 12:30 ~ 13:00 – 개인 공부 (강의 숙제) 19:00 ~ 20:00 – 개인 공부 (5강 놓친 부분) ✔️ Java 문법 강의 보충 ✔️ 5강 숙제 ✔️ Lock, Condition ✔️ 5강 숙제 이번 숙제는 stream을 사용해 볼 수 있는 5가지 문제로 구성되어 있다. 처음에 출력을 어떤 형식으로 하면 좋을지 가이드라인이 없어서 힌트를 살짝 봤는데 foreach로 순회하며 출력하는 걸 보여주길래 그대로 작성하였다. 카테고리가 여행인 책 제목 조회 import java.util.Arrays;
import java.util.List;

public class Main {
public static void main(String[] args) {
List bookList = Arrays.asList(
new Book(1L, “모두의 딥러닝”, “조태호”, “IT”, 21600),
new Book(2L, “이득우의 게임 수학”, “이득우”, “IT”, 40500),
new Book(3L, “자바 웹 개발 워크북”, “구멍가게 코딩단”, “IT”, 31500),
new Book(4L, “실전 시계열 분석”, “에일린 닐슨”, “IT”, 34200),
new Book(5L, “데이터 분석가의 숫자유감”, “권정민”, “IT”, 14400),
new Book(6L, “스프링 부트 실전 활용 마스터”, “그렉 턴키스트”, “IT”, 25200),
new Book(7L, “오늘부터 IT를 시작합니다”, “고코더”, “IT”, 16200),
new Book(8L, “그림으로 이해하는 인지과학”, “기타하라 요시노리”, “IT”, 16200),
new Book(9L, “괜찮아, 그 길 끝에 행복이 기다릴 거야”, “손미나”, “여행”, 17100),
new Book(10L, “여행의 이유”, “김영하”, “여행”, 12150),
new Book(11L, “여행의 시간”, “김진애”, “여행”, 16200),
new Book(12L, “로봇 시대 살아남기”, “염규현”, “역사”, 14850),
new Book(13L, “경제 전쟁의 흑역사”, “이완배”, “역사”, 15750),
new Book(14L, “100가지 동물로 읽는 세계사”, “사이먼 반즈”, “역사”, 29700),
new Book(15L, “k 배터리 레볼루션”, “박순혁”, “경제”, 17100),
new Book(16L, “정하준의 경제학 레시피”, “장하준”, “경제”, 16200),
new Book(17L, “레버리지”, “롭 무어”, “경제”, 16200)
);

// 카테고리가 여행인 책 제목 조회
bookList.stream().filter(o -> o.getCategory().equals(“여행”))
.forEach(o -> {
System.out.println(“카테고리가 여행인 책 제목: ” + o.getBookName());
});

}
}

class Book {
// 분류번호
private Long id;
// 책 이름
private String bookName;
// 작가 이름
private String author;
// 카테고리
private String category;
// 가격
private double price;

public Book(Long id, String bookName, String author, String category, double price) {
this.id = id;
this.bookName = bookName;
this.author = author;
this.category = category;
this.price = price;
}

public String getBookName() {
return bookName;
}

public String getCategory() {
return category;
}

public double getPrice() {
return price;
}

public void setPrice(double price) {
this.price = price;
}
} 첫 문제는 filter()를 사용해 category를 검사하면 된다. 이 와중에 집에 있는 책이 보여서 반가웠다 ㅋㅋ 가격이 16200원 이하인 책 제목 조회 // 가격이 16200원 이하인 책 제목 조회
bookList.stream().filter(o -> o.getPrice() <= 16200) .forEach(o -> System.out.println(o.getBookName())); 책 제목에 “경제”라는 용어가 들어간 책 제목 조회 // 책 제목에 “경제” 라는 용어가 들어간 책 제목 조회
bookList.stream().filter(o -> o.getBookName().contains(“경제”))
.forEach(o -> System.out.println(o.getBookName())); 가격이 가장 비싼 책 가격 조회 // 가격이 가장 비싼 책 가격 조회
double maxPrice = bookList.stream().max(Comparator.comparing(Book::getPrice)).get().getPrice();

System.out.println(“책 목록 중 가장 비싼 금액: ” + maxPrice);
System.out.println(); max(), min()을 이용해 최대 최소를 구할 수 있다. 여기서 직접 만든 클래스 내의 필드로 max를 구할 것이기 때문에 Comparator.comparing()이라는 메서드를 이용해 기준 값을 설정해줘야 한다. get()으로는 해당 객체를 가져올 수 있다. 카테고리가 IT인 책들의 가격 합 조회 // 카테고리가 IT인 책들의 가격 합 조회
double sum = bookList.stream().filter(o -> o.getCategory().equals(“IT”)).mapToDouble(Book::getPrice).sum();

System.out.println(“카테고리 IT 책들의 가격 합: ” + sum);
System.out.println(); map()은 스트림을 함수가 적용된 새로운 요소로 반환해 준다. 이 기능을 이용해 특정 필드들만 추출할 수 있다. (mapToDouble은 더블로 반환하겠다는 뜻이다.) sum()으로 전체 값을 더해준다. IT 책 할인 이벤트! // IT 책 할인 이벤트!
List discountedBookList = bookList.stream()
.filter(o->o.getCategory().equals(“IT”))
.map(o -> {
o.setPrice(o.getPrice() * 0.5);
return o;
}).toList();

for (Book book : discountedBookList) {
System.out.println(“할인된 책 제목: ” + book.getBookName());
System.out.println(“할인된 책 가격: ” + book.getPrice() + “\n”);
} 위에서 썼던 map과는 달리 book 객체를 반환해야 하는 경우이다. ✔️ lock과 condition 여전히 이해가 어려워 가볍게 무슨 느낌인지 체득하는 것을 목표로 했다… Lock synchronized는 괄호 안 혹은 메서드 안을 임계구역으로 만들지만 lock은 lock.lock()과 lock.unlock() 사이를 임계구역으로 만든다. 괄호 안 혹은 메서드가 끝나면 해제되는 synchronized와 달리 더 유연하게 해제 시점을 정할 수 있고, 타임 아웃 Condition 적용과 같이 다양한 기능 또한 적용 가능하다. 개인적으로 제일 이해에 도움이 된 포스팅 https://velog.io/@may_yun/JAVA-synchronized-VS-Reentrant-Lock-%EC%B0%A8%EC%9D%B4%EC%A0%90 [JAVA] synchronized VS Reentrant Lock (차이점) 상호 배제를 통한 동기화의 개념을 선행하고 보면 이해하는데 도움이 됩니다.현재 데이터를 사용하고 있는 해당 스레드를 제외하고 나머지 스레드들은 데이터에 접근 할 수 없도록 막는 개념Jav velog.io lock의 종류 ReentrantLock: 가장 일반적인 배타적인 lock. ReentrantReadWriteLock: 읽기, 쓰기에 대한 lock을 따로 적용한다. 쓰기만 배타적인 lock. StampedLock: ReentrantReadWriteLock에 낙관적인 lock을 추가. 데이터를 변경할 때만 lock이 걸려 읽기 쓰기 모두 빠르게 처리되나 변경이 잦을 경우는 사용하지 않는 것이 좋다. Condition wait() & notify()의 단점인 waiting fool 내에서 원하는 쓰레드를 깨울 수 없다는 점 보완. wait() 대신 condition.await()로 원하는 쓰레드를 재우고, notify()대신 condition.signal()로 원하는 쓰레드를 깨운다. private ReentrantLock lock = new ReentrantLock();

// lock으로 condition 생성
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();

// 작업 메서드
public void addMethod(String task) {
lock.lock(); // 임계영역 시작
try {
try {
condition1.await(); // wait(); condition1 재우기
Thread.sleep(500);
} catch(InterruptedException e) {}
condition2.signal(); // notify(); condition2 깨우기
} finally {
lock.unlock(); // 임계영역 끝
}
} 덧붙여 샘플 코드에서 볼 수 있듯 lock.unlock은 finally 안에서만 실행 가능하다. 아무래도 실전에서 써 봐야 내가 제대로 익힐 수 있을 것 같다… 📜 Chapter 4. 개인 과제 Level 2 14:00 ~ 17:00 – 개인 과제 Level 2 ✔️ 개인 과제 Level 2 ✔️ 잔디 실종 사건 본격적으로 과제를 시작하기 전에… github에 잔디가 올라가지 않았다는 걸 발견했다 ㅠㅠ 찾아보니 같은 문제를 겪은 사람이 있었고 이메일 정보가 일치하지 않아서 생기는 문제였다. https://velog.io/@kimseungki94/%ED%94%84% EB% A1% 9C% EC% A0% 9D% ED% 8A% B8-%EA% B9%83-%ED%97%88% EB% B8%8C-%ED%91% B8% EC%89% AC% ED%95% A0-%EB%95%8C-%EC% 9E%94% EB%94%94% EC%97%90-%EB% B0%98% EC%98%81% EC% 9D% B4-%EC%95%88% EB%90%98% EB% 8A%94-%EA% B2% BD% EC% 9A% B0 Git 푸쉬할 때, GitHub의 잔디가 재대로 반영이 안되는 경우 알고리즘 공부를 할 때 IntelliJ에 별도로 프로젝트 생성 후 진행했다.IntelliJ를 통해 푸쉬를 했는데 GitHub에 푸쉬한 변경데이터는 잘 반영이 되었지만, GitHub 잔디 심는게 재대로 반영이 안됬다.(터 velog.io 그래서 깃허브 이메일을 추가하고 대표 이메일을 변경하였다. setting -> access -> email에 들어가면 Add email address으로 새 이메일을 추가할 수 있다. 이메일 인증을 완료하면 아래에 있는 Primary email address에서 새로 추가한 이메일로 변경한 뒤, Save 버튼을 누른다. 어제 심은 잔디가 잘 돌아왔다. ㅎㅎ 이 아래로는 푼 문제들을 올릴 건데 주석이 달려 있으니 따로 설명을 적진 않겠다. ⬇️ 과제 보기 ⬇️ 더보기 ✔️ 1번 public class InputErrorException extends Exception{ // 인풋에 문제가 있다는 걸 알리는 Exception 생성
public InputErrorException(String msg){ // 생성자. 파라미터로 메세지를 받는다.
super(msg); // 부모 생성자로 전달
}
} import java.util.LinkedList;

public class Calculator {
// 1. 양의 정수 2개(0 포함)와 연산 기호를 매개변수로 받아 사칙연산(+,-,*,/)
// 기능을 수행한 후 결과 값을 반환하는 메서드와 연산 결과를 저장하는 컬렉션 타입 필드를 가진 Calculator 클래스를 생성합니다.
private LinkedList results = new LinkedList<>(); // 연산 결과를 저장하기 적합한 컬렉션인 LinkedList 선언 및 생성

public int calculate(int firstNumber, int secondNumber, char operator) throws InputErrorException {
int result = 0;
switch (operator) { // operator 값에 따라 네 가지 case로 분류
case ‘+’: // 덧셈 연산 수행하여 result에 저장
result = firstNumber + secondNumber;
break;
case ‘-‘: // 뺄셈 연산 수행하여 result에 저장
result = firstNumber – secondNumber;
break;
case ‘*’: // 곱샘 연산 수행하여 result에 저장
result = firstNumber * secondNumber;
break;
case ‘/’: // 나눗셈 연산 수행하여 result에 저장
if(secondNumber == 0) // 분모가 0일 경우 exception 발생!
throw new InputErrorException(“나눗셈 연산에서 분모(두번째 정수)에 0이 입력될 수 없습니다.”); // exception 만들어 던짐
else
result = firstNumber / secondNumber;
break;
}

return result;
}
}
✔️ 2번 import java.util.Scanner;

public class App {
public static void main(String[] args) {
// 2. Level 1에서 구현한 App 클래스의 main 메서드에 Calculator 클래스가 활용될 수 있도록 수정합니다.
Calculator calculator = new Calculator();

Scanner sc = new Scanner(System.in); // 스캐너 생성

boolean isEnd = false; // 종료 할지 여부를 boolean에 저장하기 위해 변수 생성.
do { // 첫번째는 무조건 실행.
System.out.print(“첫 번째 숫자를 입력하세요: “);
int firstNumber = sc.nextInt(); // int를 입력 받는다.
System.out.print(“두 번째 숫자를 입력하세요: “);
int secondNumber = sc.nextInt(); // int를 입력 받는다.

System.out.print(“사칙연산 기호를 입력하세요: “);
char operator = sc.next().charAt(0); // 입력 받은 string의 인덱스 0번 char을 가져온다.

try {
int result = calculator.calculate(firstNumber, secondNumber, operator);

System.out.println(“결과: ” + result);

calculator.results.add(result); // 리스트에 결과 추가

System.out.println(“가장 먼저 저장된 연산 결과를 삭제하시겠습니까? (remove 입력 시 삭제)”);
if(sc.next().equals(“remove”)) { // 입력 받은 답변이 “remove”일 경우
calculator.results.removeFirst(); // 첫 결과 삭제
}

System.out.println(“저장된 연산결과를 조회하시겠습니까? (inquiry 입력 시 조회)”);
if(sc.next().equals(“inquiry”)) { // 입력 받은 답변이 “inquiry”일 경우
for(int element : calculator.results ) { // foreach 문 사용하여 results linkedlist 순회
System.out.print(element + ” “); // 출력하고 한 칸 띄기
}
System.out.println(); // 구분을 위한 한 줄 내리기
}

System.out.println(“더 계산하시겠습니까? (exit 입력 시 종료)”);
isEnd = sc.next().equals(“exit”); // 입력 받은 답변이 “exit”라면 isEnd는 true 아니면 false 유지
} catch (InputErrorException e) {
System.out.println(e.getMessage());
}

} while (!isEnd);
}
} public class Calculator {
// 2번 기능을 수행하기 위해 잠시 public으로 바꿨습니다.
public LinkedList results = new LinkedList<>(); // 연산 결과를 저장하기 적합한 컬렉션인 LinkedList 선언 및 생성

// …
} ✔️ 3번 public class App {
public static void main(String[] args) {
// …
try {

// 3. App 클래스의 main 메서드에서 Calculator 클래스의 연산 결과를 저장하고 있는 컬렉션 필드에 직접 접근하지 못하도록 수정합니다. (캡슐화)
calculator.getResults().add(result); // 리스트에 결과 추가

System.out.println(“가장 먼저 저장된 연산 결과를 삭제하시겠습니까? (remove 입력 시 삭제)”);
if(sc.next().equals(“remove”)) { // 입력 받은 답변이 “remove”일 경우
calculator.getResults().removeFirst(); // 첫 결과 삭제
}

System.out.println(“저장된 연산결과를 조회하시겠습니까? (inquiry 입력 시 조회)”);
if(sc.next().equals(“inquiry”)) { // 입력 받은 답변이 “inquiry”일 경우
for(int element : calculator.getResults() ) { // foreach 문 사용하여 results linkedlist 순회
System.out.print(element + ” “); // 출력하고 한 칸 띄기
}
System.out.println(); // 구분을 위한 한 줄 내리기
}

// …
}
// …
} public class Calculator {
// 3. App 클래스의 main 메서드에서 Calculator 클래스의 연산 결과를 저장하고 있는 컬렉션 필드에 직접 접근하지 못하도록 수정합니다. (캡슐화)
private LinkedList results = new LinkedList<>(); // 연산 결과를 저장하기 적합한 컬렉션인 LinkedList private로 선언 및 생성

public LinkedList getResults() { // results getter
return results;
};

public void setResults(LinkedList results) { // results setter
this.results = results;
}

// …
} ✔️ 4번 public class App {
public static void main(String[] args) {
// …
System.out.println(“가장 먼저 저장된 연산 결과를 삭제하시겠습니까? (remove 입력 시 삭제)”);
// 4. Calculator 클래스에 저장된 연산 결과들 중
// 가장 먼저 저장된 데이터를 삭제하는 기능을 가진 메서드를 구현한 후 App 클래스의 main 메서드에 삭제 메서드가 활용될 수 있도록 수정합니다.
if(sc.next().equals(“remove”)) { // 입력 받은 답변이 “remove”일 경우
calculator.removeResult(); // 첫 결과 삭제
}
// …
}
} public class Calculator {
//…
// 4. Calculator 클래스에 저장된 연산 결과들 중
// 가장 먼저 저장된 데이터를 삭제하는 기능을 가진 메서드를 구현한 후 App 클래스의 main 메서드에 삭제 메서드가 활용될 수 있도록 수정합니다.
public void removeResult() {
results.removeFirst(); // 첫 결과 삭제
}
} ✔️ 5번 public class App {
public static void main(String[] args) {
// …
// 5. Calculator 클래스에 저장된 연산 결과들을 조회하는 기능을 가진 메서드를 구현한 후
// App 클래스의 main 메서드에 조회 메서드가 활용될 수 있도록 수정합니다.
System.out.println(“저장된 연산결과를 조회하시겠습니까? (inquiry 입력 시 조회)”);
if(sc.next().equals(“inquiry”)) { // 입력 받은 답변이 “inquiry”일 경우
calculator.inquiryResults(); // 결과 조회
}
// …
}
} public class Calculator {
// …
// 5. Calculator 클래스에 저장된 연산 결과들을 조회하는 기능을 가진 메서드를 구현한 후
// App 클래스의 main 메서드에 조회 메서드가 활용될 수 있도록 수정합니다.
public void inquiryResults() {
for(int element : results ) { // foreach 문 사용하여 results linkedlist 순회
System.out.print(element + ” “); // 출력하고 한 칸 띄기
}
System.out.println(); // 구분을 위한 한 줄 내리기
}
} ✔️ 6번 public class Calculator {
private LinkedList results; // 연산 결과를 저장하기 적합한 컬렉션인 LinkedList private로 선언

// 6. Calculator 인스턴스를 생성(new)할 때 생성자를 통해 연산 결과를 저장하고 있는 컬렉션 필드가 초기화 되도록 수정합니다
public Calculator() {
results = new LinkedList<>(); // 생성자에서 컬렉션 필드를 초기화
}

// …
} ✔️ 7번 public class App {
public static void main(String[] args) {
// …
do { // 첫번째는 무조건 실행.
// 7. Calculator 클래스에 반지름을 매개변수로 전달받아 원의 넓이를 계산하여 반환해주는 메서드를 구현합니다.
System.out.println(“계산기 옵션(번호 입력): 1. 사칙연산, 2. 원의 너비 구하기”); // 사칙연산 원의 너비 중 선택하도록 제시
switch (sc.nextInt()) { // 입력 받은 값에 따라 두 갈래로 나뉜다.
case 1: // 사칙 연산 로직
// ..
break;
// 7. Calculator 클래스에 반지름을 매개변수로 전달받아 원의 넓이를 계산하여 반환해주는 메서드를 구현합니다.
case 2: // 원의 너비 구하기 로직
System.out.print(“원의 반지름을 입력하세요: “);
int radius = sc.nextInt(); // int를 입력 받는다.

double result = calculator.calculateCircleArea(radius); // 원 넓이 구하는 메서드 호출하고 값 result에 저장

System.out.println(“결과: ” + result);

calculator.getCircleAreaResult().add(result); // 컬렉션에 결과 저장
calculator.inquiryCircleAreaResult(); // 원의 넓기 결과들 바로 전체 조회
System.out.println(“더 계산하시겠습니까? (exit 입력 시 종료)”);
isEnd = sc.next().equals(“exit”); // 입력 받은 답변이 “exit”라면 isEnd는 true 아니면 false 유지
break;
}
} while (!isEnd);
}
} public class Calculator {
// …
// 7. Calculator 클래스에 반지름을 매개변수로 전달받아 원의 넓이를 계산하여 반환해주는 메서드를 구현합니다.
private static final double PI = 3.14; // 절대 변할 일 없는 필드이기 때문에 static final 활용
private LinkedList circleAreaResult; // 원의 넓이 결과를 저장하는 컬렉션 타입의 필드 선언

public Calculator() {
results = new LinkedList<>(); // 생성자에서 컬렉션 필드를 초기화
circleAreaResult = new LinkedList<>(); // 생성자에서 컬렉션 필드를 초기화
}

public LinkedList getCircleAreaResult() { // circleAreaResult getter
return circleAreaResult;
}

public void setCircleAreaResult(LinkedList circleAreaResult) { // circleAreaResult setter
this.circleAreaResult = circleAreaResult;
}

// …

// 7. Calculator 클래스에 반지름을 매개변수로 전달받아 원의 넓이를 계산하여 반환해주는 메서드를 구현합니다.
public double calculateCircleArea(int radius) { // 원의 넓이를 구하는 메서드
return PI * radius * radius; // 원 넓이 구하는 공식
}

// 원 넓이 컬렉션 조회
public void inquiryCircleAreaResult() {
for(double element : circleAreaResult ) { // foreach 문 사용하여 circleAreaResult linkedlist 순회
System.out.print(element + ” “); // 출력하고 한 칸 띄기
}
System.out.println(); // 구분을 위한 한 줄 내리기
}
} ✔️ 8번 public class App {
public static void main(String[] args) {
// 8. 사칙연산을 수행하는 계산기 ArithmeticCalculator 클래스와 원과 관련된 연산을 수행하는 계산기 CircleCalculator 클래스 2개를 구현합니다.
// 사칙연산, 원 넓이 계산기 각각 생성
ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculator();
CircleCalculator circleCalculator = new CircleCalculator();

Scanner sc = new Scanner(System.in); // 스캐너 생성

boolean isEnd = false; // 종료 할지 여부를 boolean에 저장하기 위해 변수 생성.
do { // 첫번째는 무조건 실행.
System.out.println(“계산기 옵션(번호 입력): 1. 사칙연산, 2. 원의 너비 구하기”); // 사칙연산 원의 너비 중 선택하도록 제시
switch (sc.nextInt()) { // 입력 받은 값에 따라 두 갈래로 나뉜다.
case 1: // 사칙 연산 로직
System.out.print(“첫 번째 숫자를 입력하세요: “);
int firstNumber = sc.nextInt(); // int를 입력 받는다.
System.out.print(“두 번째 숫자를 입력하세요: “);
int secondNumber = sc.nextInt(); // int를 입력 받는다.

System.out.print(“사칙연산 기호를 입력하세요: “);
char operator = sc.next().charAt(0); // 입력 받은 string의 인덱스 0번 char을 가져온다.

try {
double result = arithmeticCalculator.calculate(firstNumber, secondNumber, operator);

System.out.println(“결과: ” + result);

arithmeticCalculator.getResults().add(result); // 리스트에 결과 추가

System.out.println(“가장 먼저 저장된 연산 결과를 삭제하시겠습니까? (remove 입력 시 삭제)”);
if(sc.next().equals(“remove”)) { // 입력 받은 답변이 “remove”일 경우
arithmeticCalculator.removeResult(); // 첫 결과 삭제
}

System.out.println(“저장된 연산결과를 조회하시겠습니까? (inquiry 입력 시 조회)”);
if(sc.next().equals(“inquiry”)) { // 입력 받은 답변이 “inquiry”일 경우
arithmeticCalculator.inquiryResults(); // 결과 조회
}

System.out.println(“더 계산하시겠습니까? (exit 입력 시 종료)”);
isEnd = sc.next().equals(“exit”); // 입력 받은 답변이 “exit”라면 isEnd는 true 아니면 false 유지

} catch (InputErrorException e) {
System.out.println(e.getMessage()); // 예외 발생시 로그 출력
}
break;
case 2: // 원의 너비 구하기 로직
System.out.print(“원의 반지름을 입력하세요: “);
int radius = sc.nextInt(); // int를 입력 받는다.

double result = circleCalculator.calculate(radius); // 원 넓이 구하는 메서드 호출하고 값 result에 저장

System.out.println(“결과: ” + result);

circleCalculator.getResults().add(result); // 컬렉션에 결과 저장
circleCalculator.inquiryResults(); // 원의 넓기 결과들 바로 전체 조회
System.out.println(“더 계산하시겠습니까? (exit 입력 시 종료)”);
isEnd = sc.next().equals(“exit”); // 입력 받은 답변이 “exit”라면 isEnd는 true 아니면 false 유지
break;
}
} while (!isEnd);
}
} // 8. 사칙연산을 수행하는 계산기 ArithmeticCalculator 클래스와 원과 관련된 연산을 수행하는 계산기 CircleCalculator 클래스 2개를 구현합니다.
public abstract class Calculator {
private LinkedList results; // 결과를 저장하는 컬렉션 타입의 필드 선언

public Calculator() {
results = new LinkedList<>(); // 생성자에서 컬렉션 필드를 초기화
}

public LinkedList getResults() { // results getter
return results;
};

public void setResults(LinkedList results) { // results setter
this.results = results;
}

// calculate는 두 경우에 매개 변수를 다르게 받아야 해서 오버로딩 하였다.
protected abstract double calculate(int firstNumber, int secondNumber, char operator) throws InputErrorException;
protected abstract double calculate(int number);

public void removeResult() { // 첫 결과 삭제 메서드
results.removeFirst(); // 첫 결과 삭제
}

public void inquiryResults() { // 컬렉션 조회 메서드
for(double element : results ) { // foreach 문 사용하여 results linkedlist 순회
System.out.print(element + ” “); // 출력하고 한 칸 띄기
}
System.out.println(); // 구분을 위한 한 줄 내리기
}
} public class ArithmeticCalculator extends Calculator {

// 사용할 오버라이딩 메서드는 public으로 변경
@Override
public double calculate(int firstNumber, int secondNumber, char operator) throws InputErrorException {
double result = 0;
switch (operator) { // operator 값에 따라 네 가지 case로 분류
case ‘+’: // 덧셈 연산 수행하여 result에 저장
result = firstNumber + secondNumber;
break;
case ‘-‘: // 뺄셈 연산 수행하여 result에 저장
result = firstNumber – secondNumber;
break;
case ‘*’: // 곱샘 연산 수행하여 result에 저장
result = firstNumber * secondNumber;
break;
case ‘/’: // 나눗셈 연산 수행하여 result에 저장
if(secondNumber == 0) // 분모가 0일 경우 exception 발생!
throw new InputErrorException(“나눗셈 연산에서 분모(두번째 정수)에 0이 입력될 수 없습니다.”); // exception 만들어 던짐
else
result = firstNumber / secondNumber;
break;
}

return result;
}

// 사용하지 않는 오버라이딩 메서드는 protected로 밖에서 접근 불가능하게 하였다
@Override
protected double calculate(int radius) {
return 0;
}

} public class CircleCalculator extends Calculator {
private static final double PI = 3.14; // 절대 변할 일 없는 필드이기 때문에 static final 활용

// 사용하지 않는 오버라이딩 메서드는 protected로 밖에서 접근 불가능하게 하였다
@Override
protected double calculate(int firstNumber, int secondNumber, char operator) throws InputErrorException {
return 0;
}

// 사용할 오버라이딩 메서드는 public으로 변경
@Override
public double calculate(int radius) {
return PI * radius * radius; // 원 넓이 구하는 공식
}
} ✔️ 9번 public class ArithmeticCalculator extends Calculator {
private AddOperator addOperator; // 사칙연산 클래스 필드들 선언
private SubstractOperator substractOperator;
private MultiplyOperator multiplyOperator;
private DivideOperator divideOperator;

public ArithmeticCalculator() {
// 부모의 생성자는 자동으로 호출 된다.
addOperator = new AddOperator(); // 사칙연산 클래스 필드들 생성
substractOperator = new SubstractOperator();
multiplyOperator = new MultiplyOperator();
divideOperator = new DivideOperator();
}

// 사용할 오버라이딩 메서드는 public으로 변경
@Override
public double calculate(int firstNumber, int secondNumber, char operator) throws InputErrorException {
double result = 0;
switch (operator) { // operator 값에 따라 네 가지 case로 분류
case ‘+’: // 덧셈 연산 수행하여 result에 저장
result = addOperator.operate(firstNumber, secondNumber); // 사칙연산 클래스로 책임을 분산하였다.
break;
case ‘-‘: // 뺄셈 연산 수행하여 result에 저장
result = substractOperator.operate(firstNumber, secondNumber);
break;
case ‘*’: // 곱샘 연산 수행하여 result에 저장
result = multiplyOperator.operate(firstNumber, secondNumber);
break;
case ‘/’: // 나눗셈 연산 수행하여 result에 저장
if(secondNumber == 0) // 분모가 0일 경우 exception 발생!
throw new InputErrorException(“나눗셈 연산에서 분모(두번째 정수)에 0이 입력될 수 없습니다.”); // exception 만들어 던짐
else
result = divideOperator.operate(firstNumber, secondNumber);
break;
}

return result;
}

// …
} public class AddOperator {
public int operate(int firstNumber, int secondNumber) { // 더하기 기능을 하는 메서드 구현
return firstNumber + secondNumber;
}
}

public class SubstractOperator {
public int operate(int firstNumber, int secondNumber) { // 빼기 기능을 하는 메서드 구현
return firstNumber – secondNumber;
}
}

public class MultiplyOperator {
public int operate(int firstNumber, int secondNumber) { // 곱하기 기능을 하는 메서드 구현
return firstNumber * secondNumber;
}
}

public class DivideOperator {
public int operate(int firstNumber, int secondNumber) { // 나누기 기능을 하는 메서드 구현
return firstNumber / secondNumber;
}
} ✔️ 10번 public class ArithmeticCalculator extends Calculator {
// …
private ModOperator modOperator;

public ArithmeticCalculator() {
// …
modOperator = new ModOperator();
}

// 사용할 오버라이딩 메서드는 public으로 변경
@Override
public double calculate(int firstNumber, int secondNumber, char operator) throws InputErrorException {
double result = 0;
switch (operator) { // operator 값에 따라 네 가지 case로 분류
case ‘+’: // 덧셈 연산 수행하여 result에 저장
result = addOperator.operate(firstNumber, secondNumber); // 사칙연산 클래스로 책임을 분산하였다.
break;
case ‘-‘: // 뺄셈 연산 수행하여 result에 저장
result = substractOperator.operate(firstNumber, secondNumber);
break;
case ‘*’: // 곱샘 연산 수행하여 result에 저장
result = multiplyOperator.operate(firstNumber, secondNumber);
break;
case ‘/’: // 나눗셈 연산 수행하여 result에 저장
if(secondNumber == 0) // 분모가 0일 경우 exception 발생!
throw new InputErrorException(“나눗셈 연산에서 분모(두번째 정수)에 0이 입력될 수 없습니다.”); // exception 만들어 던짐
else
result = divideOperator.operate(firstNumber, secondNumber);
break;
case ‘%’: // 나머지 연산 수행하여 result에 저장
result = modOperator.operate(firstNumber, secondNumber);
break;
}

return result;
}
// …
} public abstract class Operator {
// 사칙 연산 메서드가 전부 같은 형태로 이루어져 있기 때문에 추상 메서드로 만듦
public abstract int operate(int firstNumber, int secondNumber);
} public class AddOperator extends Operator {
@Override
public int operate(int firstNumber, int secondNumber) { // 더하기 기능을 하는 메서드 구현
return firstNumber + secondNumber;
}
}

public class SubstractOperator extends Operator {
@Override
public int operate(int firstNumber, int secondNumber) { // 빼기 기능을 하는 메서드 구현
return firstNumber – secondNumber;
}
}

public class MultiplyOperator extends Operator {
@Override
public int operate(int firstNumber, int secondNumber) { // 곱하기 기능을 하는 메서드 구현
return firstNumber * secondNumber;
}
}

public class DivideOperator extends Operator {
@Override
public int operate(int firstNumber, int secondNumber) { // 나누기 기능을 하는 메서드 구현
return firstNumber / secondNumber;
}
}

public class ModOperator extends Operator {
@Override
public int operate(int firstNumber, int secondNumber) { // 추상 메서드 상속 받아 나머지 기능 구현
return firstNumber % secondNumber;
}
} 이제 내일은 3단계를 하고 애노테이션, 리플렉션을 추가 해볼 것이다. 애노테이션은 잘 모르는 부분이라 찾아보니 C#의 애트리뷰트와 비슷한 듯. 🌙 오늘을 마치며 🌙 개인 과제를 레벨 2까지 하고 좀 쉬어야겠다 싶어서 스프링을 공부할만한 자료를 찾아봤다. 튜터님이 추천해 주신 책도 물론 좋지만 지금은 좀 무작정 따라 해 보면서 아 이런 것이구나 하는 게 필요했다. 그래서 스프링 부트라고 딱 검색을 하자마자 괜찮은 책을 발견했다. https://wikidocs.net/book/7601 점프 투 스프링부트 점프 투 스프링부트는 Spring Boot Board(SBB)라는 이름의 게시판 서비스를 만들어가는 과정을 설명한 스프링부트 입문서이다. 자바 설치부터 시작하여 서비스 운… wikidocs.net 조금 읽고 따라 해 봤는데 꽤 괜찮은 것 같아서 이제 내일부터는 남는 시간마다 이 책을 뽀개보려고 한다. 다만 초벌구이가 목표여서 개념 정리 같은 건 따로 올리지 않을 것 같다. 하다가 안 되는 게 있을 때 정리하는 정도지 않을까? 아무튼 고생했다!

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다