1. if 문 / try-catch 문 차이 완벽 이해
1) 의문 사항 : try-catch가 아닌 if 문으로도 해결할 수 있는 예외일 경우 if문으로 해도 괜찮은지
2) 설명 :
(1) if 문
- 예상이 가능한 조건을 처리
- EX) 나눗셈을 진행할 때 분모가 0이면 안되는 경우 (당연하게도 예상 가능한 예외임)
(2) try-catch 문
- 예상하지 못하거나 예외를 미리 체크할 수 없는 상황
- EX) 우리가 사용자에게 입력을 받을 때 발생할 수 있는 입출력 오류 같은 경우에는 미리 체크할 수 없기 때문에 try-catch로 처리
(3) 표준 예외 처리
- InputMismatchException : 정수로 입력해야 하는데 문자를 입력한 경우 예외 발생
- ArithmeticException : 정수를 0으로 나눌 경우 예외 발생
- NullPointerException : null 값을 허용하지 않는 메서드에 null을 건낼 때 발생시킬 수 있는 예외
- ArrayIndexOutOfBoundException : 배열의 범위를 벗어나서 접근한 경우 예외 발생
- FileNotFoundException : 파일을 찾을 수 없을 경우 예외 발생
- IllegalArgumentException : 호출자가 인수로 부적절한 값을 넘길 때 던지는 예외. EX) 나이 입력에 음수가 할당되는 경우
- IllegalStateException : 호출된 메서드를 수행하기에 적절하지 않을 때. EX) 체스 게임을 진행하는데 체스판이 생성되지 않은 경우
- ConcurrentModificationException : 단일 스레드 환경에서 적합한 동작을, 멀티 스레드에서 동작하려고 할 때 발생하는 예외.
- (etc)
(4) 적용 분모가 0인 나눗셈 처리
//수정 전
try {
//Calculator 클래스의 연산 메서드로 연산 수행
result = calc.calculate(op, firstReal, secondReal);
}
catch (BadDivideException e){ // second가 0이고 연산자가 / 일 경우 에러메세지를 출력
System.out.println(e.getMessage());
}
//수정 후
if (op == '/' & secondReal == 0) { // 분모가 0인 경우 처음부터 재입력
System.out.println("나눗셈 연산에서 분모에 0이 입력될 수 없습니다. 처음부터 다시 입력해주세요.");
continue;
}
- 정수 간의 연산일 경우, ArithmeticException 표준 예외 활용 가능
// 정수 간 연산일 경우
try {
res = OperatorType.DIVIDE.operate(firstReal, secondReal);
}
catch (ArithmeticException ae){
System.out.println("나눗셈 연산에서 분모에 0이 입력될 수 없습니다. 처음부터 다시 입력해주세요.");
}
(5) 적용2 - 입력 연산자 예외 처리
/* symbol과 일치시키기 */
public static OperatorType fromOperator(char operator) {
for (OperatorType type : OperatorType.values()) {
if (type.symbol == operator) {
return type;
}
}
throw new IllegalArgumentException("해당하는 연산자가 없습니다." + operator);
}
2. null 안전하게 다루기 (null-safe) 참조
1) null을 참조하게 되면 NPE(Null Point Exception)라는 런타임 오류 발생
2) null-safe 방법
(1) if 문 처리
- 직접 if문에서 예외처리
void nullSafe(Box box) {
Message msg = box.getMessage();
if (msg == null) {
msg = new Message();
}
if (Objects.isNull(msg)) {
msg = new Message();
}
}
(2) 적용 종료 시 yes 입력하면 while 반복문 종료
- sc.nextLine()이 null을 반환할 가능성은 낮지만, 만약 null이 반환되면 equals("yes") 부분에서 NullPointerException이 발생할 수 있음
- null 체크를 추가하거나 "yes".equals() 방식을 사용해 null을 안전하게 처리
//수정 전
//종료 여부 묻기
System.out.println("종료하시겠습니까?(yes/no)");
if (sc.nextLine().equals("yes")) break;
//수정 후
//종료 여부 묻기
System.out.println("종료하시겠습니까?(yes/no)");
String exitCheck = sc.nextLine();
if ("yes".equals(exitCheck)) break;
3. enum 참조
1) 특징
- 안정성 => Enum 의 생성자 같은 경우 제어자가 private 으로 강제되기 때문에 컴파일 시점 이후에 다른 값이 추가되거나 바뀔 수가 없음
- 표현력 상승
- enum으로 관리되는 데이터가 빈번하게 변경(추가/제거) 되지 않아야 함.
2) 사용 이유
- 객체의 책임을 분리하기 위함. 객체가 상태와 행동 데이터를 가지고 있어야 함.
=> 그렇지 않으면, 데이터베이스에 의존하게 됨
3) enum 사용 예시
public enum Weeks {
요소들;
private한 필드들;
생성자(필드 초기화) {}
getter, setter 메서드 {}
}
EX)
public enum Weeks {
MONDAY("mon", 10),
TUESDAY("tue", 20),
WEDNESDAY("wed", 30),
THURSDAY("thu", 40),
FRIDAY("fri", 50),
STURDAY("sat", 60),
SUNDAY("sun", 70);
private final String name;
private final int value;
private Weeks(String name, int value) {
this.name = name;
this.value = value;
}
public String getName() {
return this.name;
}
public int getValue() {
return this.value;
}
}
4) 적용 - 사칙연산
//OperatorType.java
public enum OperatorType {
ADD('+'),
SUBTRACT('-'),
MULTIPLY('*'),
DIVIDE('/');
private final char symbol;
OperatorType(char symbol) {
this.symbol = symbol;
}
/* symbol과 일치시키기 */
public static OperatorType fromOperator(char operator) {
for (OperatorType type : OperatorType.values()) {
if (type.symbol == operator) {
return type;
}
}
throw new IllegalArgumentException("해당하는 연산자가 없습니다." + operator);
}
}
// ArithmeticCalculator.java
OperatorType type = OperatorType.fromOperator(op);
switch (type) {
case ADD:
res = firstReal + secondReal;
break;
case SUBTRACT:
res = firstReal - secondReal;
break;
case MULTIPLY:
res = firstReal * secondReal;
break;
case DIVIDE:
res = firstReal / secondReal;
break;
};
4. 캡슐화
1) 정리 : 필드와 메서드를 즉 상태와 행동을 묶고, 외부에는 드러나지 않게 하는 것
2) 장점 :
- 코드의 중복을 제거
- 데이터 처리하는 방식을 외부에서 확인 불가
3) 사용 예시
public void foo(Goods goods) {
double discountedPrice = goods.getPrice() * 0.9;
var(discountedPrice);
}
이 함수에서는 discount 행위가 직접 드러나며 2가지 작업을 하고 있다. goods를 discount하는 행위를 goods 클래스 내부에서 수행하고 foo함수에서는 이를 적용하도록 구현하는 것이 베스트
class Goods {
int price = 10000;
...
public int getDiscountedPrice() {
return price * 0.9;
}
}
public void foo(Goods goods) {
double discountedPrice = goods.getDiscountedPrice();
var(discountedPrice);
}
5. 컬렉션 변경
1) 요구 사항 : 저장된 연산 결과 중 Scanner로 입력받은 값보다 큰 결과값들 출력 => 기존에는 순회를 구현하지 않아 Queue로 진행했으나 순회까지 할 경우 ArrayList가 적합하다고 판단하여 순회 시 Queue를 ArrayList로 변경함.
2) 적용
/* Queue를 ArrayList로 변경 후 순회 메서드 적용 과정 */
private ArrayList<Double> resArray; //추가
public List<Double>getResultList(){
resArray = new ArrayList<>(resQueue);
return resArray;
}
public void setResultList(Double resArray){
this.resArray.add(resArray);
}
public List<Double> getGoeList1(Double targetNum){
getResultList();
return resArray.stream()
.filter(result -> result >= targetNum)
.toList();
}
6. 람다 & 스트림
1)
2) 적용 - 결과값 리스트 순회하며 입력값보다 큰 값 return
public List<Double> getGoeList1(Double targetNum){
getResultList();
return resArray.stream()
.filter(result -> result >= targetNum)
.toList();
}
'과제리뷰' 카테고리의 다른 글
[CH4개인과제] 일정 관리 앱 서버 (1) | 2024.11.08 |
---|---|
[숫자야구] 피드백 이후 개선 (0) | 2024.10.29 |
[CH3개인과제] 숫자 야구 (0) | 2024.10.23 |
[CH2개인과제] 계산기 (0) | 2024.10.16 |
[CH1팀과제] 팀소개 페이지 프로젝트 (0) | 2024.10.07 |