📢 오늘의 목표 📢
✔️ Java 문법 강의 수강
✔️ 4주 차 강의
✔️ 5주 차 강의
✔️ 학습법 특강
⏱️ 오늘의 일정 ⏱️
9:00 ~ 13:00 - 개인 공부 (강의 듣기)
13:00 ~ 14:00 - 점심시간
14:00 ~ 15:00 - 학습법 특강
15:00 ~ 17:00 - 개인 공부 (강의 듣기)
17:00 ~ 18:00 - 개인 과제 Level 1
18:00 ~ 19:00 - 저녁 시간
19:00 ~ 19:30 - 개인 과제 Level 1
19:30 ~ 20:00 - 개인 공부 (강의 듣기)
20:00 ~ 21:00 - TIL 작성
📜 Chapter 1. Java 문법 강의 수강 - 4주 차
9:00 ~ 12:00 - 개인 공부 (강의 듣기)
✔️ Java 문법 강의 수강
✔️ 4주 차 강의
✔️ 예외처리
예외처리는 그냥 파일 불러올 때, 네트워크 통신할 때 같이 꼭 필요한 곳에 기계적으로 써 본 경험뿐이었다.
그래서 지금까지는 문법 강의를 쉽게 들었는데 이 부분은 좀 이해에 시간이 걸렸다.
Exception 클래스 만들기
public class OurBadException extends Exception{
public OurBadException(){
super("위험한 행동을 하면 예외처리");
}
}
기존 Exception 클래스 아래에 이미 여러 구체화된 클래스들이 존재하지만 자신에게 딱 맞는 클래스가 없을 수도 있다.
그럴 때 Exception을 상속받아 나만의 Exception을 만들 수 있다.
throw 예외 던지기
public void thisMethodIsDangerous () throws OurBadException {
if (just) {
throw new OurBadException();
}
}
예외를 던질 때는 메서드 () 뒤에 throws 예외클래스를 붙여준다.
그리고 예외를 발생시켜야 하는 상황에서 예외 인스턴스를 생성해서 던지자.
try~catch~finally
try {
ourClass.thisMethodIsDangerous();
}
catch (OurBadException e) {
System.out.println(e.getMessage());
}
finally {
// 무조건 여기는 거쳐요!!
System.out.println("예외 handling 함");
}
try 문 내에서 예외가 발생할 경우 중단하고 catch 절로 넘어온다.
finally는 예외가 발생하든 발생하지 않든 거쳐가는 곳.
✔️ 제네릭
한 클래스(혹은 메서드)로 다양한 type을 사용할 수 있도록 해주는 도구.
원시 타입은 래퍼클래스를 사용해야 한다.
public class Generic<T> {
private T t;
public T get() {
return this.t;
}
public void set(T t) {
this.t = t;
}
}
제한
- static 사용 불가: 제네릭 타입 변수는 인스턴스로 간주된다. 제네릭 클래스에서 static이 불가능한 것으로 제네릭 메서드에서는 사용 가능하다.
- 제네릭 배열 생성 불가
와일드카드
<? extends T> : T와 T의 자손들만 가능
<? super T> : T와 T의 부모들만 가능
<?> : 제한 없음
특정 클래스에서 파생된 클래스만 받을 때 사용한다는 점에서 C# 제네릭 문법에서 where 제약 조건과 같은 일을 하는 듯.
✔️ 숙제
Parser 클래스
import java.util.regex.Pattern;
public class Parser {
private static final String OPERATION_REG = "[+\\-*/]";
private static final String NUMBER_REG = "^[0-9]*$";
private final Calculator calculator = new Calculator();
public Parser parseFirstNum(String firstInput) throws BadInputException {
// 구현 1.
if(!firstInput.matches(NUMBER_REG)) {
throw new BadInputException("숫자");
}
calculator.setFirstNumber(Integer.parseInt(firstInput));
return this;
}
public Parser parseSecondNum(String secondInput) throws BadInputException {
// 구현 1.
if(!secondInput.matches(NUMBER_REG)) {
throw new BadInputException("숫자");
}
calculator.setSecondNumber(Integer.parseInt(secondInput));
return this;
}
public Parser parseOperator(String operationInput) throws BadInputException {
// 구현 1.
if(!operationInput.matches(OPERATION_REG)) {
throw new BadInputException("연산자");
}
switch(operationInput) {
case "+":
calculator.setOperation(new AddOperation());
break;
case "-":
calculator.setOperation(new SubstractOperation());
break;
case "*":
calculator.setOperation(new MultiplyOperation());
break;
case "/":
calculator.setOperation(new DivideOperation());
break;
}
return this;
}
public double executeCalculator() {
return calculator.calculate();
}
}
Parser 클래스는 메서드 내에서 어떻게 오류 처리를 하고, 파싱 된 데이터를 어떻게 Calculator에 전달할지가 관건이다.
정규식은 이미 주어져 있기 때문에 들어온 데이터를 검사하는 부분은 순식간에 처리할 수 있었다.
숫자가 아닌(연산자가 아닌) 데이터가 들어올 경우 바로 제시된 예외를 throw 하고,
맞을 경우 Calculator의 각 setter에 전달해 준다.
마지막으로 Parser 타입을 반환하는 메서드가 제시되었기 때문에 this를 반환하였다.
Main 클래스
public class Main {
public static void main(String[] args) {
boolean calculateEnaded = false;
// 구현 2.
while (!calculateEnaded) {
try {
calculateEnaded = CalculatorApp.start();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
Main에서는 static 메서드로 만들어진 CalculatorApp의 start 메서드를 실행하기만 하면 된다.
여기서 중요한 것은 예외를 처리해 주는 것이기 때문에 try catch 문을 사용하였고,
catch에서 예외가 잡혔을 경우 메시지를 출력해 준다.
이전에 start 메서드가 완료가 되지 않았을 경우 true가 반환되지 않기 때문에
예외 없이 수행을 완료할 때까지 while문을 통해 반복해 주었다.
📜 Chapter 2. 학습법 특강
14:00 ~ 15:00 - 학습법 특강
✔️ 학습법 특강
TIL을 써야 하는 이유, 협업을 잘하는 방법, 학습을 잘하는 방법 등
당연한 내용에 대해 이야기하였지만 사실 제일 중요한 부분이기도 한 것 같다.
어쨌든 강의 듣다가 1시간 동안 리프래시하니 괜찮은 시간이었다고 생각한다. ㅎㅎ
그건 그렇고 개발 역량 표인가 저거 빨리 받고 싶다 ㅋㅋㅋ
📜 Chapter 3. Java 문법 강의 수강 - 5주 차
12:00 ~ 13:00 - 개인 공부 (강의 듣기)
15:00 ~ 18:00 - 개인 공부 (강의 듣기)
✔️ Java 문법 강의 수강
✔️ 5주 차 강의
✔️ 스레드 구현방법 3가지
1. Thread
기본적인 구현 방법으로 Thread 클래스를 상속받아 구현한다.
수행할 작업을 run 메서드에 오버라이딩해 구현.
public class TestThread extends Thread {
@Override
public void run() {
// 쓰레드 수행작업
}
}
TestThread thread = new TestThread(); // 쓰레드 생성
thread.start() // 쓰레드 실행
2. Runnable
Runnable 인터페이스를 사용해 구현하고 스레드를 생성할 때 생성자에 넣어준다.
인터페이스이기 때문에 확장성이 더 뛰어나 직접 스레드를 구현하는 것보다 자주 쓰인다.
수행할 작업을 run 메서드에 오버라이딩해 구현.
public class TestRunnable implements Runnable {
@Override
public void run() {
// 쓰레드 수행작업
}
}
Runnable run = new TestRunnable();
Thread thread = new Thread(run); // 쓰레드 생성
thread.start(); // 쓰레드 실행
3. 람다식
제일 많이 쓰는 구현 방법으로 Runnable 인터페이스에 람다식을 사용하는 것이다.
public class Main {
public static void main(String[] args) {
Runnable task = () -> {
// 쓰레드 수행 작업
};
Thread thread1 = new Thread(task);
thread1.setName("thread1");
thread1.start();
}
}
✔️ 데몬 스레드 <-> 사용자 스레드
데몬 스레드는 백 그라운드에서 실행되는, 우선순위가 낮은 스레드이다.
대표적인 데몬 스레드로는 가비지 컬렉터가 있다.
데몬 스레드로 설정하지 않은 스레드는 전부 사용자 스레드이다.
thread.setDaemon(true);
JVM은 사용자 스레드의 작업이 끝나면 데몬 스레드도 자동으로 종료시켜 버린다.
✔️ 스레드 우선순위
스레드에는 1부터 10까지 우선순위를 부여할 수 있다.
- 최대 우선순위 (MAX_PRIORITY) = 10
- 최소 우선순위 (MIN_PRIORITY) = 1
- 보통 우선순위 (NROM_PRIORITY) = 5
우선순위가 높을수록 더 많은 리소스를 부여받는다.
thread1.setPriority(8);
✔️ 스레드 그룹
스레드를 그룹으로 묶어서 한 번에 다룰 수 있다.
기본적으로는 메인 스레드는 system 그룹 하위의 main 그룹에 포함된다.
스레드 그룹을 지정하지 않으면 모두 main 그룹에 포함된다.
// ThreadGroup 클래스로 객체를 만듭니다.
ThreadGroup group1 = new ThreadGroup("Group1");
// Thread 객체 생성시 첫번째 매개변수로 넣어줍니다.
// Thread(ThreadGroup group, Runnable target, String name)
Thread thread1 = new Thread(group1, task, "Thread 1");
✔️ 스레드 상태와 제어
상태
|
Enum
|
설명
|
객체생성
|
NEW
|
쓰레드 객체 생성, 아직 start() 메서드 호출 전의 상태
|
실행대기
|
RUNNABLE
|
실행 상태로 언제든지 갈 수 있는 상태
|
일시정지
|
WAITING
|
다른 쓰레드가 통지(notify) 할 때까지 기다리는 상태
|
일시정지
|
TIMED_WAITING
|
주어진 시간 동안 기다리는 상태
|
일시정지
|
BLOCKED
|
사용하고자 하는 객체의 Lock이 풀릴 때까지 기다리는 상태
|
종료
|
TERMINATED
|
쓰레드의 작업이 종료된 상태
|
(근데 왜 표에 실행이 없지?)
스레드 상태에는 객체생성, 샐 행대기, 실행, 일시정지, 종료가 있고 실행과 일시정지, 실행대기 순서로 반복하며 run 메서드를 수행한다.
일시정지에는 세 가지 유형이 있고 각 다른 Enum 값으로 관리된다.
- sleep()
지정한 시간 동안 스레드를 멈추게 한다. ms단위로 설정한다. static 메서드이므로 특정 스레드를 지목해서 멈추게 할 수 없다. try catch 문 안에서 실행해야 한다.
try {
Thread.sleep(2000); // 2초
} catch (InterruptedException e) {
e.printStackTrace();
}
- interrupt()
일시정지 상태인 스레드를 실행 대기 상태로 만든다. sleep, join 같은 일시정지로 만드는 메서드 실행 중 interrupt가 실행되면 실행 대기 상태로 바뀌게 되기 때문에 예외가 발생한다.! Thread.currentThread(). isInterrupted()로 interrupted 상태를 체크해서 sleep을 실행하자.
thread.interrupt();
- join():
지정한 시간 동안 지정한 스레드가 작업하는 것을 기다린다. 시간을 지정하지 않았을 경우 작업이 끝날 때까지 기다린다.
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
- yield():
남은 시간을 다음 스레드에게 양보하고 자신은 실행 대기 상태가 된다.
try {
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
}
} catch (InterruptedException e) {
Thread.yield();
}
- synchronized:
한 스레드가 synchronized 구문 안에 있을 때 다른 스레드가 들어오지 못하게 한다.메서드 전체를 synchronized로 만드는 것과 특정 영역을 지정하는 것 두 가지 방법이 있다.
public synchronized void asyncSum() {
...침범을 막아야하는 코드...
}
synchronized(해당 객체의 참조변수) {
...침범을 막아야하는 코드...
}
- wait(), notify():
이 둘은 항상 같이 쓰인다. synchronized 안에서 작업을 멈추고 싶을 때 wait()를 호출하여 스레드가 Lock을 반납하고 기다리게 한다. 추후 다시 작업을 진행할 수 있게 된다면 notify()를 호출해 중단했던 스레드에게 다시 Lock을 얻게 하자.그러나 notify()에는 문제가 있는데 waiting pool의 임의의 스레드만 통지를 받는 것. (스레드를 구분하지 못함)
- Lock, Condition:
이 둘에 대해서는 내가 아직 제대로 이해하지 못했다!
synchronized, wait, notify의 단점을 보완한 것이라고만 알고 있는데 다음에 더 공부해서 따로 포스팅을 진행하겠다.
✔️ 함수형 프로그래밍
함수형 프로그래밍은 항상 개발을 하고 리팩토링을 할 때 제일 지향하고 있는 패러다임이다.프로그래밍에서의 함수를 수학적 함수처럼 취급하는데 이를 순수 함수라고 부른다.(메서드 내에서 변수 값이나 필드 값을 바꾸는 등 사이드 이펙트가 없는, 입력과 출력으로 이루어진 함수)사이드 이펙트를 없앰으로써 안정성을 보장받고 동기화에 문제가 생기지 않는다.
자세한 정보는 아래 블로그를 참고하면 좋을 것 같다.https://mangkyu.tistory.com/111
[프로그래밍] 함수형 프로그래밍(Functional Programming) 이란?
1. 함수형 프로그래밍(Functional Programming)에 대한 이해 [ 프로그래밍 패러다임(Programming Paradigm) ] 프로그래밍 패러다임(Programming Paradigm)은 프로그래머에게 프로그래밍의 관점을 갖게 하고 코드를
mangkyu.tistory.com
함수형 프로그래밍은 객체 지향 프로그래밍만큼이나 (어쩌면 더!) 금방 적응하기 어려운 개념이지만,
앞으로 더 좋은 개발자가 되려면 함수형 프로그래밍을 잘하는 개발자가 되어야 할 것이다.
✔️ 익명 함수
C#은 Action 쓰면 다 되는데 interface도 만들어야 하고 귀찮은 것 같다.
interface Predicate<T> {
boolean test(T t);
}
익명 함수를 input으로 받고는 싶은데 적절한 type이 없어 대신 추상 메서드 하나를 가진 interface를 만든다.
그리고 인터페이스에서(보통 function이라는 이름으로 쓰는 듯) 함수를 호출하면 그게 익명 함수처럼 작동한 다는 것이다.
public static List<Car> parkCars(List<Car> carsWantToPark, Predicate<Car> function) {
List<Car> cars = new ArrayList<>();
for (Car car : carsWantToPark) {
// 전달된 함수를 사용하여 구현
if (function.test(car)) {
cars.add(car);
}
}
return cars;
}
익명 함수를 전달할 때는 메서드를 그대로 넣거나 람다식을 사용한다.
parkingLot.addAll(parkCars(carsWantToPark, Car::noTicketButMoney));
parkingLot.addAll(parkCars(carsWantToPark, (Car car) -> car.hasParkingTicket() && car.getParkingMoney() > 1000));
Java의 람디식도 C#과 크게 다르진 않다.
화살표가 =>에서 ->이 됐다는 차이뿐인 것 같다.
() -> {}
✔️ stream
C#의 Linq.
컬렉션에 스트림을 이용하여 원하는 결과의 일회용 컬렉션을 리턴한다.
(e.g. filter를 이용해 원하는 값만 반환한 일회용 컬렉션 생성)
map(), forEach(), filter()가 자주 사용된다.
carsWantToPark.stream()
.filter((Car car) -> car.getCompany().equals("Benz"))
.toList();
✔️ null
자바에서 null 체크를 편하게 하기 위해 Optional이라는 클래스를 제공한다.
일단 오늘 깊게 파고 들 내용은 아닌 것 같아 괜찮아 보이는 포스팅을 미리 붙여놨다.
자바의 정석에서 발췌한 것이라 하니 다음에 정독해야 되겠다.
https://velog.io/@injoon2019/%EC%9E%90%EB%B0%94-OptionalT%EC%99%80-OptionalInt
[자바의 정석] Optional<T>와 OptionalInt
아래 내용들은 자바의 정석에 나오는 내용을 발췌한 것이다. java.util.Optional은 JDK1.8부터 추가되었다.Optional<T>은 지네릭 클래스로 'T타입의 객체'를 감싸는 래퍼 클래스이다.그래서 Optional타입의
velog.io
📜 Chapter 4. 개인 과제 Level 1
17:00 ~ 18:00 - 개인 과제 Level 1
18:00 ~ 18:30 - 개인 과제 Level 1
✔️ 개인 과제 Level 1
스레드까지 듣고 나니 솔직히 Lock, Condition 부분은 써 본 적도 없고 이해도 잘 안 되고... 강의에서도 이런 게 있구나 하고 넘어가라고 하지만 더 강의 듣다간 실신하겠다 싶어서 개인 과제를 또 건드렸다.
✔️ 일단 에러부터 고치기
error: unmappable character (0 xBC) for encoding x-windows-949
테스트 코드를 실행하니 Gradle 문제인지 에러가 뜬다. 말하는 거 보니 한글 인코딩 때문인 듯.
에러코드를 검색해 보면 해결 방법은 나온다. 따라 하자.
Intellij 한글 깨짐 & unmappable character for encoding x-windows-949
1. unmappable character for encoding x-windows-949 차라리 이 에러는 고치기 쉽다. 설정에서 인코딩만 수정해주면 됨 이렇게 해주면 뜨진 않음.. windows 기본 설정이 ms949여서 그렇다고 한다. 차후에 더 공부할
beemiel.tistory.com
✔️ 그리고 커밋 작성자도 바꿔야 해
[Git] user 정보 변경하기
github 잔디 지키기
velog.io
위 블로그에서 git user name과 user email을 바꾸는 법을 알려주고 있다.
참고: 인텔리제이에서 git 터미널 실행
이 아래로는 푼 문제들을 올릴 건데 주석이 달려 있으니 따로 설명을 적진 않겠다.
✔️ 1번
public class App {
public static void main(String[] args) {
// 1. Scanner를 사용하여 양의 정수 2개(0 포함)를 전달 받을 수 있습니다.
Scanner sc = new Scanner(System.in); // 스캐너 생성
System.out.print("첫 번째 숫자를 입력하세요: ");
int firstNumber = sc.nextInt(); // int를 입력 받는다.
System.out.print("두 번째 숫자를 입력하세요: ");
int secondNumber = sc.nextInt(); // int를 입력 받는다.
}
}
✔️ 2번
// 2. Scanner를 사용하여 사칙연산 기호를 전달 받을 수 있습니다.
System.out.print("사칙연산 기호를 입력하세요: ");
char operator = sc.next().charAt(0); // 입력 받은 string의 인덱스 0번 char을 가져온다.
✔️ 3번
// 3. 입력받은 양의 정수 2개와 사칙연산 기호를 사용하여 연산을 진행한 후 결과값을 출력합니다.
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일 경우 아래 문구 출력
System.out.println("나눗셈 연산에서 분모(두번째 정수)에 0이 입력될 수 없습니다.");
else
result = firstNumber / secondNumber;
break;
}
System.out.println("결과: " + result);
✔️ 4번
// 4. 반복문을 사용하여 반복의 종료를 알려주는 “exit” 문자열을 입력하기 전까지 무한으로 계산을 진행할 수 있도록 소스 코드를 수정합니다.
boolean isEnd = false; // 종료 할지 여부를 boolean에 저장하기 위해 변수 생성.
do { // 첫번째는 무조건 실행.
// ... 이전 로직들
System.out.println("더 계산하시겠습니까? (exit 입력 시 종료)");
isEnd = sc.next().equals("exit"); // 입력 받은 답변이 "exit"라면 isEnd는 true 아니면 false 유지
} while (!isEnd);
✔️ 5번
// 5. 연산 결과 10개를 저장할 수 있는 배열을 선언 및 생성하고 연산의 결과를 저장합니다.
int[] results = new int[10]; // 연산의 결과를 저장할 수 있도록 적합한 타입의 배열을 생성합니다.
int index = 0; // 연산의 결과가 저장된 배열의 마지막 index를 저장하는 변수를 선언
// ... 이전 로직들
// 5. 연산 결과 10개를 저장할 수 있는 배열을 선언 및 생성하고 연산의 결과를 저장합니다.
results[index++] = result; // result를 저장하고 index 증가
✔️ 6번
// 6. 연산 결과가 10개를 초과하는 경우 가장 먼저 저장된 결과를 삭제하고 새로운 연산 결과가 저장될 수 있도록 소스 코드를 수정합니다.
if(index >= 9) { // 인덱스가 9를 넘을 때만
for(int i = 0; i < results.length - 1; i++) { // 인덱스 0부터 8까지 순회하며
results[i] = results[i + 1]; // 다음 인덱스의 값을 현재 인덱스 자리에 넣는다
}
results[index] = result; // 인덱스 9에 결과를 저장
} else { // 인덱스 9 미만의 경우
// 5. 연산 결과 10개를 저장할 수 있는 배열을 선언 및 생성하고 연산의 결과를 저장합니다.
results[index++] = result; // result를 저장하고 index 증가
}
✔️ 7번
// 7. 연산 결과가 10개로 고정되지 않고 무한이 저장될 수 있도록 소스 코드를 수정합니다.
LinkedList<Integer> results = new LinkedList<>(); // 연산 결과를 저장하기 적합한 컬렉션인 LinkedList 생성
// ... 이전 코드
// 7. 연산 결과가 10개로 고정되지 않고 무한이 저장될 수 있도록 소스 코드를 수정합니다.
results.add(result); // 리스트에 결과 추가
System.out.println("가장 먼저 저장된 연산 결과를 삭제하시겠습니까? (remove 입력 시 삭제)");
if(sc.next().equals("remove")) { // 입력 받은 답변이 "remove"일 경우
results.removeFirst(); // 첫 결과 삭제
}
✔️ 8번
// 8. “inquiry”라는 문자열이 입력되면 저장된 연산 결과 전부를 출력합니다.
System.out.println("저장된 연산결과를 조회하시겠습니까? (inquiry 입력 시 조회)");
if(sc.next().equals("inquiry")) { // 입력 받은 답변이 "inquiry"일 경우
for(int element : results ) { // foreach 문 사용하여 results linkedlist 순회
System.out.print(element + " "); // 출력하고 한 칸 띄기
}
System.out.println(); // 구분을 위한 한 줄 내리기
}
✔️ Level 1 전체 코드 보기
import java.util.LinkedList;
import java.util.Scanner;
public class App {
public static void main(String[] args) {
LinkedList<Integer> results = new LinkedList<>(); // 연산 결과를 저장하기 적합한 컬렉션인 LinkedList 생성
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을 가져온다.
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일 경우 아래 문구 출력
System.out.println("나눗셈 연산에서 분모(두번째 정수)에 0이 입력될 수 없습니다.");
else
result = firstNumber / secondNumber;
break;
}
System.out.println("결과: " + result);
results.add(result); // 리스트에 결과 추가
System.out.println("가장 먼저 저장된 연산 결과를 삭제하시겠습니까? (remove 입력 시 삭제)");
if(sc.next().equals("remove")) { // 입력 받은 답변이 "remove"일 경우
results.removeFirst(); // 첫 결과 삭제
}
System.out.println("저장된 연산결과를 조회하시겠습니까? (inquiry 입력 시 조회)");
if(sc.next().equals("inquiry")) { // 입력 받은 답변이 "inquiry"일 경우
for(int element : results ) { // foreach 문 사용하여 results linkedlist 순회
System.out.print(element + " "); // 출력하고 한 칸 띄기
}
System.out.println(); // 구분을 위한 한 줄 내리기
}
System.out.println("더 계산하시겠습니까? (exit 입력 시 종료)");
isEnd = sc.next().equals("exit"); // 입력 받은 답변이 "exit"라면 isEnd는 true 아니면 false 유지
} while (!isEnd);
}
}
GitHub에 push까지 완료!
기초적인 문제들이라 어려운 점은 없었는데 양의 정수가 아닌 입력이 들어왔을 때, 사칙연산자가 아닌 입력이 들어왔을 때의 예외 처리가 되어있지 않은 부분이 신경 쓰인다.
나눗셈에서 분모가 0이라 로그를 출력했을 때에도 결과 0으로 나오기도 하고...
그런데 또 이런 부분까지 진행하며 문제의 취지에 맞지 않는 것 같아서 지금은 하지 않았지만,
전체 코드를 완성한 뒤 (Level 3까지 진행하고) 이런 빈 부분을 완성시켜야 되겠다.
🌙 오늘을 마치며 🌙
4, 5강에 들어가니 잘 모르는 것도 많아서 하나하나 공부하고 정리하느라 시간이 정말 많이 걸렸다.
정말 쉬지 못하고 21시까지 공부만 했던 것 같다.
이제 내일부터는 알고리즘 특강이 있다고 한다.
알고리즘 문제를 푼 지 꽤 오래됐는데 슬슬 두뇌를 깨워야겠다.
'공부 기록 > 내배캠Java_5기' 카테고리의 다른 글
[내배캠][TIL] 10일 차 - 금요일, 스프링 찍먹 (1) | 2024.04.26 |
---|---|
[내배캠][TIL] 9일 차 - 목요일, 알고리즘 문제 풀이 시작과 개인 과제 (1) | 2024.04.25 |
[내배캠][TIL] 7일 차 - 화요일, 자바 문법 강의 뽀개기 (0) | 2024.04.23 |
[내배캠][TIL] 6일 차 - 월요일, 프로그래밍 기초 챕터 시작 (1) | 2024.04.22 |
[내배캠][TIL] 5일 차 (0) | 2024.04.19 |