프로그램 수행 시 치명적 상황이 발생하여 비정상 종료 상황이 발생한 것, 프로그램 에러라고도 함
√ 오류의 종류
1. 컴파일 에러 : 프로그램 실행을 막는 소스 코드상의 문법 에러. 소스 코드 수정으로 해결.
2. 런타임 에러 : 프로그램 실행 중 발생하는 에러. 주로 if문 사용으로 에러 처리
(ex. 배열의 인덱스 범위를 벗어났거나, 계삭식의 오류)
3. 시스템 에러 : 컴퓨터 오작동으로 인한 에러, 소스 코드 수정으로 해결 불가
√ 오류 해결 방법
소스 코드 수정으로 해결 가능한 에러를 예외(Exception)라고 하는데 이러한 예외 상황(예측 가능한 에러) 구문을 처리하는 방법인 예외 처리를 통해 해결
√ Exception 확인하기
Java API Document에서 해당 클래스에 대한 생성자나 메서드를 검색하면 그 메서드가 어떤 Exception을 발생시킬 가능성이 있는지 확인 가능.
→ 발생하는 예외를 미리 확인하여 상황에 따른 예외 처리 코드를 작성할 수 있음
Java 프로그램 실행 중
Exception 상황이 발생하면 해당 상황과 일치하는 예외 클래스를 찾고 객체로 만들어서 문제가 발생한 위치로 던짐.
√ 예시
Exception과 Error 클래스 모두 Object 클래스의 자손이며 모든 예외의 최고 조상은 Exception 클래스
반드시 예외 처리해야 하는 Checked Exception과 해주지 않아도 되는 Unchecked Exception으로 나뉨
√ RuntimeException 클래스
Unchecked Exception으로 주로 프로그래머의 부주의로 인한 오류인 경우가 많기 때문에 예외 처리보다는 코드를 수정해야 하는 경우가 많음
if문으로 처리 가능한 경우가 많다.
√ RuntimeException 후손 클래스
Java API에서 제공하는 Exception Class 만으로는 처리할 수 없는 예외가 있을 경우
사용자의 필요에 의해 생성하는 Exception Class.
Exception 발생하는 곳에서 throw new 예외클래스명()으로 발생
public class UserException extends Exception{
public UserException() {}
public UserException(String msg) {
super(msg);
}
}
public class UserExceptionController {
public void method() throws UserException{
throw new UserException("사용자정의 예외발생");
}
}
public class Run {
public static void main(String[] args) {
UserExceptionController uc = new UserExceptionController();
try {
uc.method();
} catch(UserException e) {
System.out.println(e.getMessage());
}
}
}
public void method() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("입력 : ");
String str = br.readLine();
System.out.println("입력된 문자열 : " + str);
} catch (IOException e) {
e.printStackTrace();
}
}
√ try ~ catch ~ finally로 예외 처리 후 반드시 수행해야 하는 로직 처리
public void method() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("입력 : ");
String str = br.readLine();
System.out.println("입력된 문자열 : " + str);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
System.out.println("BufferedReader 반환");
br.close();
} catch (IOException e)
e.printStackTrace();
}
}
}
오버라이딩 시 throws하는 Exception의 개수와 상관없이 처리 범위가 같거나 후손이여야 함
package edu.kh.exception.service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.InputMismatchException;
import java.util.Scanner;
import edu.kh.exception.user.exception.ScoreInputException;
public class ExceptionService {
public void ex1() throws IOException {
// 해당 메서드 내에서 IOException이 발생할 것을
// 대비한 에외처리 코드
// 예외(Exception) 확인하기
// 키보드 입력을 효율적으로 읽어오는 객체
// (Scanner보다 기능은 부족하지만 속도는 빠름)
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("입력 : ");
String input = br.readLine();
// readLine() : 한 줄 읽어오기 (엔터까지)
// 왜 빨간줄이 뜰까??
// - readLine() 메서드는 IOException 이라고 하는 예외를
// 발생시킬(던질) 가능성이 있기 때문에
// 그 상황에 대한 대비책(예외처리)를 하라고 경고하는 것
System.out.println("입력값 : " + input);
// Checked Exception :
// 컴파일 단계에서 예외가 발생할 가능성이 있는지
// 반드시 확인해야하는 예외
// -> 공식 API 문서의 메서드 설명에
// throws OOOException 으로 작성 되어있는 메서드가 있으면
// 해당 코드 사용 시 문제가 발생할 것이다 라고 생각하고
// 그 상황에 대한 예외 처리 코드를 꼭 작성
// Unchecked Exception :
// 컴파일 단계에서 예외가 발생할 가능성이 있는지
// 확인하지 않는 예외
// -> 개발자의 부주의로 나타나는 예외
// -> 대부분 쉽게 해결(if)
// -> 치명적인 문제가 아님
System.out.println(5/0);
int[] arr = new int[4];
System.out.println(arr[10]);
String s = null;
System.out.println(s.equals("bbb"));
}
public void ex2() {
// 예외(Exception) : 코드 수정으로 해결 가능한 에러
// 예외 처리 : 예외를 처리할 수 있는 구문
// [예외 처리 1] try ~ catch ~ finally
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// try : {} 내부에 예외가 발생할 것 같은 코드를 작성하고 실행 시도
try {
System.out.print("입력 : ");
String input = br.readLine();
// public String readLine() throws IOException
// -> IOException 이라는 Checked Exception을 발생시키는 메서드
// -> Exception이 발생할 경우에 대비해서 예외처리 구문 작성(강제)
/* 예외 강제 발생 */
// -> 예외 객체를 새로 만들어서 던짐
System.out.println(input);
throw new IOException();
} catch(IOException e) {
// catch : try 구문 내에서 던져진 예외가 있을 경우
// 해당 예외 객체를 잡아채서 catch 구문을 수행해 처리
// catch의 매개 변수에는
// 던져진 예외 객체를 저장할 수 있는 참조 변수를 작성
System.out.println("키보드 문제로 입력을 진행할 수 없습니다.");
// 발생된 예외가 처리된 후
// 프로그램이 종료되지 않고 다음 코드가 수행됨
}
System.out.println("try-catch가 수행되도 프로그램이 종료되지 않음");
}
public void ex3() {
// 입력 받은 두 정수 나누기
Scanner sc = new Scanner(System.in);
try {
System.out.print("입력1 : ");
int num1 = sc.nextInt();
System.out.print("입력2 : ");
int num2 = sc.nextInt();
System.out.printf("%d / %d = %d", num1, num2, num1/num2);
} catch(ArithmeticException e) {
// 산술적 예외를 잡아 처리
System.out.println("0으로 나눌 수 없습니다.");
} catch(InputMismatchException e){
// ** catch문 여러 개 작성 가능 **
// ** 다형성 적용 가능(업캐스팅) **
// -> 상위 타입 예외를 대개변수로 작성하면
// 하위 타입의 예외를 모두 처리할 수 있다.
} catch(Exception e) {
// !!!!!!!!!! 주의 사항 !!!!!!!!!!
// - 상위 타입을 처리하는 catch문을
// 하위 타입을 처리하는 catch문 보다
// 먼저 작성하면 오류 발생
// Unreachable catch block for ArithmeticException.
// It is already handled by the catch block for Exception
// 해결방법 : 상위 타입 catch를 뒤쪽에 배치해서
// 하위 타입 catch에 대한 검사가 먼저 진행되게 한다.
// InputMismatchException
// 스캐너 사용 시 작성법이 잘못되거나 범위를 초과하면 발생하는 예외
System.out.println("입력이 잘못되었습니다.");
} finally {
// finally :
// try-catch 구문이 끝난 후 마지막으로 수행
// ** 예외가 발생 하든 말든 무조건 실행 **
System.out.println("프로그램 종료");
}
}
public void ex4() {
// throw : 예외 강제 발생
// ex) throw new IOException();
// throws : 해당 메서드에서 발생한 예외를
// 호출한 메서드로 던져버리는 예외 처리 방법
System.out.println("ex4() 실행");
try {
methodA();
} catch(IOException e) {
// e.getMessage();
e.printStackTrace();
// Trace : 추적하다
// -> 예외가 발생한 지점까지의 Stack 구조를 추적하여 출력
System.out.println("catch문 처리");
}
}
public void methodA() throws IOException {
System.out.println("methodA() 실행");
methodB();
}
public void methodB() throws IOException{
System.out.println("methodB() 실행");
methodC();
// methodC()는 IOException을 던질 수도 있기 때문에
// 호출 시 예외 처리 구문을 작성해야 한다.
}
public void methodC() throws IOException{
System.out.println("methodC() 실행");
throw new IOException();
}
public void ex5() throws ScoreInputException{
// 사용자 정의 예외
// - Java에서 제공하지 않는 예외 상황이 있을 경우
// 이를 처리하기 위한 예외 클래스를 사용자가 직접 작성
Scanner sc = new Scanner(System.in);
System.out.print("점수 입력(0~100) : ");
int score = sc.nextInt();
if(score <0 || score > 100) {
// throw new ScoreInputException();
throw new ScoreInputException("ex5() 호출 중 0~100 사이 범위 초과");
}
System.out.println("입력한 점수는 : " + score);
}
public void startEx5() {
try {
ex5(); // ScoreInputException이 던져질 가능성이 있음
System.out.println("가나다");
} catch(ScoreInputException e) {
// e.printStackTrace();
System.out.println("예외 내용 : " + e.getMessage());
System.out.println("예외처리를 진행");
} finally {
System.out.println("프로그램 종료");
}
}
}
package edu.kh.exception.run;
import java.io.IOException;
import edu.kh.exception.service.ExceptionService;
public class ExceptionRun {
public static void main(String[] args) throws IOException {
ExceptionService service = new ExceptionService();
// service.ex1();
// service.ex2();
// service.ex3();
// service.ex4();
service.startEx5();
}
}
package edu.kh.exception.user.exception;
// 사용자 정의 예외를 만드는 방법!!
// - 이미 존재하는 Java의 Exception Class 중 하나를 상속 받으면 된다
// (관련성 있는 예외가 있으면 해당 예외 클래스,
// 없으면 Exception 또는 RuntimeException을 상속)
// Checked Exception을 원할 경우 : Exception 상속
// Unchecked Exception을 원할 경우 : RuntimeException 상속
public class ScoreInputException extends Exception{
// 기본 생성자
public ScoreInputException() {
super("입력된 점수가 범위를 초과하였습니다.");
}
// 매개변수 생성자
public ScoreInputException(String message) {
super(message);
}
}
package edu.kh.exception.dto;
import java.io.IOException;
public class Parent {
public void test() throws IOException{
System.out.println("부모 test()");
}
}
package edu.kh.exception.dto;
import java.io.EOFException;
public class Child extends Parent{
@Override
public void test() throws EOFException{
// 오버라이딩 시 예외처리는 같거나 좁은 범위
System.out.println("자식 test()");
}
}