이지은님의 블로그
250103 - Java 예외 처리 개념 및 과제 코드분석(오류와 예외, throws, throw, try-catch) 본문
250103 - Java 예외 처리 개념 및 과제 코드분석(오류와 예외, throws, throw, try-catch)
queenriwon3 2025. 1. 3. 22:42▷ 코드 문제풀이
[SQL] 코드카타 - (41)~(45)
문제 (41) : 조건에 맞는 도서 리스트 출력하기BOOK 테이블에서 2021년에 출판된 '인문' 카테고리에 속하는 도서 리스트를 찾아서 도서 ID(BOOK_ID), 출판일 (PUBLISHED_DATE)을 출력하는 SQL문을 작성해주
queenriwon3.tistory.com
▷ 오늘 배운 것
JAVA 종합반 강의를 듣고 4주차 과제를 풀면서 개념을 정리하고 코드를 분석해 보고자 한다.
1. 오류와 예외
1) 예외를 정의하는 방법(throws, throw)
2) try-catch
3) Throwable 클래스 구성
4) 실제 예외를 처리하는 방법
2. 과제 코드 분석
1) Main .java
2) CalculatorApp .java
3) Parser .java
4) BadInputException .java
1. 오류와 예외
오류(Error) | 예외(Exception) |
일반적으로 회복이 불가능. 주로 코드의 문제 --> 발생시 프로그램 종료 |
회복(인지 후 대응)이 가능 |
오류와 예외는 컴파일유무와 확인유무에 따라 다시 나눌 수 있다.
- 컴파일 유무에 따른 오류(예외)분류
컴파일 에러(예외) --> 주로 코드 문법이 원인 | 런타임 에러(예외) --> 실행 중 발생 |
.java파일을 .class파일로 컴파일할 때 발생. 프로그래밍 언어의 규칙을 지키지 않았을때 사용 -> 문법에 맞게 코드를 작성하면 실행가능 |
문법적으로 오류는 아니지만(컴파일 가능) 프로그래밍 실행도중 마주할 수 있는 에러(예외) |
- 확인 유무에 따른 오류(예외)분류
확인된 에러(예외)(Checked Exception) | 미확인된 에러(예외)(Unchecked Exception) |
컴파일 시점에 확인되는 에러(not 컴파일에러) 예외처리를 하면 실행될 수 있는 에러 |
런타임 시점에서 확인되는 예외. 예외처리가 반드시 필요하진 않음. |
1) 예외를 정의하는 방법(throws, throw)
// OurBadException 클래스
class OurBadException extends Exception { // Exception을 상속받은 OurBadException
public OurBadException() {
// 생성자에서 부모클래스의 생성자 출력 설정
super("위험한 행동을 하면 예외처리를 꼭 해야합니다!");
}
}
// OurClass 클래스
class OurClass {
private final Boolean just = true;
// OurBadException을 던질 수 있다는 것을 알려주는 throws(예약어)를 지정한 메소드 생성
public void thisMethodIsDangerous() throws OurBadException {
if (just) {
throw new OurBadException(); //만약 just가 참이면 OurBadException() 메소드(에러)를 던짐
}
}
}
예외를 커스텀해서 발생시킨 후 지정한 예외 알림문구를 출력할 수 있다.
이때 사용되는 것은 메소드에 예외가 발생할 수 있다는 것을 미리 알리는 예약어 throws와 실제로 예외를 던지는 예약어 throw가 사용된다. 실제로 던지게 된 내가 만든 예외는 Exception을 상속받아 만든 클래스이므로 선언할때 new를 붙여 선언한다.
throws | throw |
메서드 이름 뒤에 붙어 이 메서드가 어떠한 예외사항을 던질 수 있는지 알려주는 예약어 | 메서드 안에서, 실제로 예외 객체를 던질 때 사용하는 예약어 |
여러 종류의 예외사항을 적을 수 있다. | 실제로 던지는 예외 객체 하나와 같이 사용 (throw new OurBadException();) |
메소드 throws OurBadException | throw 아래의 구문들은 실행되지 않고, throw문과 함께 메서드가 종료됨.(return 같은 기능) |
2) Try-catch
public class StudyException {
public static void main(String[] args) {
OurClass ourClass = new OurClass();
try {
ourClass.thisMethodIsDangerous();
} catch (OurBadException e) { // 괄호 안의 예외 발생시 실행
System.out.println(e.getMessage());
} finally {
System.out.println("우리는 방금 예외를 handling 했습니다!");
}
}
}
try: 예외가 있을 수 있는 코드를 작성한다.
catch: try를 실행하면서 괄호 안의 예외가 발생하면 catch안의 코드를 실행한다.
finally: 예외 발생 유무에 상관없이 출력한다.
3) JAVA의 Throwable 클래스 구성
- 문제상황을 뜻하는 Throwable 클래스가 Object 클래스를 상속한다.
- Throwable 클래스의 자식으로 에러(Error)와 예외(Exception) 클래스가 있다.
- 에러(Error) 클래스와 예외(Exception) 클래스는 각각 IOError 클래스, RuntimeException 클래스와 같이 구분하여 처리된다.(아래 사진 참고)
- 예외(Exception)에 입출력예외(IOException)와 실행중예외(RuntimeException)이 있다.
4) 실제 예외를 처리하는 방법
- 예외 복구하기
: try-catch 로 예외처리. 현실적으로 복구가 가능한 상황이 아닌 경우가 많거나 최소한의 대응이 많아 자주 사용되진 않음
public String getDataFromAnotherServer(String dataPath) {
try {
return anotherServerClient.getData(dataPath).toString();
} catch (GetDataException e) {
return defaultData;
}
}
- 예외 처리 회피하기
: someMethod()에서 발생한 에러가 someIrresponsibleMethod()로 흘러감
public void someMethod() throws Exception { ... }
public void someIrresponsibleMethod() throws Exception {
this.someMethod();
}
- 예외 전환하기
: 예외 처리에 더 신경 쓰고 싶은 경우나, 오히려 RuntimeException처럼 일괄적으로 처리하기 편한 예외로 바꿔서 던지고 싶은 경우 사용
public void someMethod() throws IOException { ... }
public void someResponsibleMethod() throws MoreSpecificException {
try {
this.someMethod();
} catch (IOException e) {
throw new MoreSpecificException(e.getMessage());
}
}
2. 과제 코드 분석
위 내용을 배우고 4주차 과제에서는 예외처리 기능이 담긴 계산기 문제를 풀도록 했는데,
해당 코드 구조에 대해 분석하고 넘어가면 좋을 것 같아서 정리를 해보기로 했다.
생략된 코드들도 많은데 이는 github링크 main브릿지에 올려놓았다.
https://github.com/queenriwon/Calculator_hw.git
GitHub - queenriwon/Calculator_hw
Contribute to queenriwon/Calculator_hw development by creating an account on GitHub.
github.com
1) Main.java
// Main.java
public class Main {
public static void main(String[] args) throws Exception {
boolean calculateEnded = false;
while(!calculateEnded){
try{
calculateEnded = CalculatorApp.start();
} catch (Exception e){
System.out.println(e.getMessage());
}
}
}
}
- 메인 클래스 메인 메소드에서는 throws Exception으로 예외가 올 것을 미리 예고한다.
- calculateEnded는 계산이 끝났는지 끝나지 않았는지를 알려주는 flag역할을 하며, 계산이 끝날때까지 while반복문 안을 반복한다.
- 만약, 중간에 예외가 발생하면 메세지를 출력한다.(e.getMessage())
2) CalculatorApp.java
// CalculatorApp.java
import java.util.Scanner;
public class CalculatorApp {
public static boolean start() throws Exception{
Parser parser = new Parser();
Scanner scanner = new Scanner(System.in);
System.out.println("첫번째 숫자를 입력해주세요!");
String firstInput = scanner.nextLine();
parser.parseFirstNum(firstInput);
System.out.println("연산자를 입력해주세요!");
String operator = scanner.nextLine();
parser.parseOperator(operator);
System.out.println("두번째 숫자를 입력해주세요!");
String secondInput = scanner.nextLine();
parser.parseSecondNum(secondInput);
System.out.println("연산 결과 : " + parser.executeCalculator());
return true;
}
}
- start()에서도 throws Exception으로 예외가 올 것을 미리 예고한다.
- 예외는 주로 Parser 클래스에서 자료형과 관한 에러가 주로 발생한다.
- retrun true 하는 값은 이 메소드를 빠져나왔을 때 반복문을 끝내는 flag 역할을 해준다.
3) Parser.java
// Parser.java
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 {
if(!Pattern.matches(NUMBER_REG, firstInput)){
throw new BadInputException("정수값");
}
calculator.setFirstNumber(Integer.parseInt(firstInput));
return this;
}
public Parser parseSecondNum(String SecondInput) throws ...{...}
public Parser parseOperator(String operationInput) throws BadInputException {
if(!Pattern.matches(OPERATION_REG, operationInput)){
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();
}
}
- final로 정규표현식을 지정한다.(정규표현식은 다음 TIL에서 다룰 예정이다.)
- 미리 정해둔 예외(BadInputException)를 각 메서드에서 throws로 예고한다.(throws BadInputException)
- 만약 내가 예상한 예외가 생길 경우(if문 안에있는 정규표현식에 맞지 않은 값이 입력 되었을 경우), throw new BadInputException으로 예외를 던진다.
- 예외 발생시 BadInputException 클래스 생성자에서 지정한 문자열을 받고 catch가 있는 곳으로 돌아온다.(throw는 retrun처럼 이후 코드는 실행되지 않는 특성이 있으니, setFirstNumber()나 return은 실행되지 않고 바로 catch가 실행된다.)
- Main.java의 main()메서드에서 e.getMessage() 에러메세지를 출력한다.
4) BadInputException.java (예외정의)
// BadInputException.java
public class BadInputException extends Exception {
public BadInputException(String type) {
super("잘못된 입력입니다! " + type + "을 입력해주세요!");
}
}
- Exception 클래스를 상속받아 super로 예외발생시 출력될 메세지를 생성자를 이용해 출력할 수 있다.
결과
▷ 앞으로
입력에대한 예외처리는 정규표현식과 함께 사용하면 예외사항을 지정할 수 있다. 문자열 입력에 대한 처리를 잘 활용하기 위해 다음에는 정규처리식에 대해 알아보도록 하겠다.
그리고 별개로 예외처리를 더욱 잘 활용하기 위해 많은 예제들을 찾아봐야겠다는 생각이 들었다.(듣자하니 더 자세히 파보면 예외처리에 관련해 더 어려운 개념이 있다고 한다.)
'TIL' 카테고리의 다른 글
250106 - Java 다중 작업 처리 : 프로세스와 스레드의 개념 및 활용 (0) | 2025.01.06 |
---|---|
250105 - Java 제네릭과 정규 표현식의 활용 (0) | 2025.01.05 |
250102 - Java 객체, 상속, 추상 클래스, 인터페이스의 이해 (0) | 2025.01.02 |
250101 - Java 배열, 컬렉션, 데이터 구조의 핵심 개념 정리 (0) | 2025.01.01 |
241231 - Git & GitHub의 협업 워크플로우와 심화 학습(branch, merge) (0) | 2024.12.31 |