1. 예외처리
프로그램 실행 시 발생할 수 있는 오류에 대비하는 것으로 프로그램 비정상종료를 막고 실행 상태를 유지하는 것
1-1. 오류의 종류
1) 에러(Error)
- 시스템, 운영체제, JVM의 잘못으로 발생되는 것
- 개발자가 해결할 수 있는 문제가 아님
- 예외처리의 대상이 아님
2) 예외(Exception)
- 개발자의 코딩실수나 사용자의 잘못된 프로그램 사용으로 발생하는 오류
- 예외는 예외처리를 통해서 비정상적인 종료를 예방할 수 있다.
- 예외는 UncheckedException과 CheckedException으로 구분한다.
* 최신의 라이브러리나 프레임워크는 대부분 UncheckedException을 사용
◼ UncheckedException
- RuntimeException 클래스와 그 자식 클래스들이다.
- 주로 개발자의 코딩 실수로 발생되는 오류들이다.
- 예외처리 안해도됨
- 컴파일러가 예외처리 여부를 체크하지 않는다.
- 주요 예외 클래스
- RunTimeException
모든 UnChecked Exception의 부모 클래스다. - NullPointerException
참조변수의 값이 null인 상태에서 필드나 메소드를 사용할 때 발생하는 예외 클래스다. - ClassCastException
클래스 형변환이 가능하지 않을 때 발생하는 예외 클래스다. - ArithmeticException
나눗셈에서 어떤 값을 0으로 나눌 때 발생하는 예외 클래스다. - IndexOutOfBoundsException
배열, 리스트, 문자열에서 인덱스 범위를 벗어난 위치를 조회했을 때 발생하는 예외 클래스다. - NumberFormatException
숫자가 아닌 문자를 포함하고 있는 문자열을 정수나 실수로 변환할 때 발생하는 예외 클래스다.
Integer.parseInt(s), Double.parseDouble(s) 등을 실행할 때 발생한다.
- RunTimeException
◼ CheckedException
- Exception 클래스와 Exception 클래스의 하위 클래스중에서 RuntimeException 클래스의 하위 클래스가 아닌 예외클래스다.
- 사용자의 잘못된 사용으로 인해 발생하는 오류들이다.
- 예외처리 반드시 필요
- 컴파일러가 예외처리 구현 여부를 반드시 체크한다.
- 예외처리 관련 코드가 구현되어 있지 않으면 컴파일 오류가 발생한다.
- 최신의 라이브러리나 프레임워크에서는 CheckedException의 사용비중이 점점 줄어들고 있다.
- 주요 클래스
- Exception
모든 Checked Exception의 부모 클래스다. - ParseException
올바른 형태를 입력하지 않았을 때 발생하는 예외클래스다. - ClassNotFoundException
클래스파일을 찾을 수 없을 때 발생하는 예외클래스다. - IOException
읽기/쓰기 하는 도중 오류가 발생했을 때 발생하는 예외클래스다.
네트워크를 통해서 다른 컴퓨터와 데이터 교환중 오류가 발생했을 때 발생하는 예외클래스다. - FileNotFoundException
파일을 찾을 수 없을 때 발생하는 예외 클래스다. - SQLException
데이터베이스 엑세스 작업 중 오류가 발생했을 때 발생하는 예외클래스다.
- Exception
* 오류의 발생
자바가상머신은 발생가능한 오류에 대한 다양한 예외클래스를 가지고 있음
-> 자바가상머신의 실행프로그램에서 메소드를 실행하다가 오류가 발생
-> 오류 상황에 맞는 예외클래스로 예외객체 생성
-> 예외 객체 안에 오류메세지(오류상황과 관련된 오류 정보)를 담아서
-> 이 예외객체를 자바가상머신에 전달 (throws : 오류를 던지다)
-> 오류 메세지를 출력하고 프로그램 종료
=> 예외 발생
예외를 던지면 (throw) -> 잡아야 (catch) -> 예외를 가로채서 방지 (JVM에 안가도록)
=> 예외 처리
오류 발생하면 -> db 엑세스, 업무로직에서 각각 처리하지 않고, 한군데에서 오류 페이지를 보냄 (일괄예외처리)
- UncheckedException이 발생하는 예 -> 예외처리 해도되고 안해도됨
public class ExceptionApp1 {
public static void main(String[] args) {
// UncheckedException이 발생하는 예 -> 오류 발생해도 미리 안알려줌
System.out.println("### 프로그램 시작");
int number1 = Integer.parseInt("1234"); // 형식에 맞게 적음
System.out.println("첫번째 숫자: " + number1);
int number2 = Integer.parseInt("1234A"); // 형식에 맞지 않게 적음 -> 빨간줄이 안가
System.out.println("두번째 숫자: " + number2);
System.out.println("### 프로그램 종료");
}
}
### 프로그램 시작
첫번째 숫자: 1234
Exception in thread "main" java.lang.NumberFormatException: For input string: "1234A"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at day25.ExceptionApp1.main(ExceptionApp1.java:12)
1) 어떤 오류 발생? -> java.lang.NumberFormatException
숫자형식이 아니다
parseInt -> NumberFormatException (-> UncheckedException) 을 던짐
2) 어떤 원인으로 발생? -> For input string: "1234A"
이거 때문에
3) 어디에? -> ExceptionApp1.java:12
: 위에서 아래 방향으로 내가 작성한 클래스를 찾아 (내가 작성한게 아니면 수정할 수가 없어, 내가 작성한 클래스의 몇번째 줄에 오류가 있는지 확인)
- checkedException이 발생하는 예 -> 에외처리를 무조건 해야함
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionApp2 {
public static void main(String[] args) {
// checkedException이 발생하는 예 -> 에외처리를 안하면 아예 오류
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = sdf.parse("2022-12-31"); // 형식에 맞게 적어도 -> 오류
System.out.println("첫번째 날짜: " + date1);
Date date2 = sdf.parse("20221231"); // 형식에 맞지 않게 적음 -> 명백한 오류
System.out.println("첫번째 날짜: " + date1);
}
}
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
Unhandled exception type ParseException
Unhandled exception type ParseException
at day25.ExceptionApp2.main(ExceptionApp2.java:13)
parse -> ParseException (-> CheckedException) 을 던짐
* UncheckedException과 CheckedException의 구분
따라가다보면
CheckedException의 상위는 Exception
UncheckedException의 상위는 Runtime
최상위 클래스는 Throwable 클래스
부모가 Runtime이면 전부다 UncheckedException -> 예외처리 안해도 됨
부모가 Parse면 CheckedException -> 예외처리 필수
이 parse가 오류가 발생할 수 있는 메소드인데 컴파일러가 확인을 안해
오류 체크를 안해 그냥 실행이 돼 (예외처리 했냐안헀냐 안따져) -> unchecked
예외가 발생할 수 있는데 예외처리 코드 안적어놓으면 오류 -> checked
1-2. 예외처리
- try ~ catch 구문을 사용해서 그 자리에서 바로 예외를 처리할 수 있다.
- throws를 사용해서 예외처리를 위임할 수 있다.
1) try ~ catch
- try 블록에서는 예외발생이 예상되는 수행문을 적는다.
- catch 블록은 try 블록에서 예외가 발생했을 때 해당 예외를 잡는다.
- catch 블록에서 예외를 잡지않으면 프로그램이 비정상적으로 종료된다.
- try 블록에서 여러 종류의 예외발생이 예상되는 수행문을 적었을 경우에는 그 예외의 종류만큼 catch 블록을 추가한다.
- catch 블록에서는 발생한 예외를 잡고, 그 예외발생시 실행할 수행문을 적는다.
- catch 블록에서는 작업내용
- 발생한 예외정보를 로그로 기록하기
- 사용자에게 에외발생원인 안내하기
- 개발자에게 오류 수정을 위한 디버깅메세지 출력하기
- 발생한 예외를 다른 예외로 바꾸기
- catch 블록을 작성할 때는 부모예외클래스를 잡는 catch블록을 아래쪽에 적는다.
- 맨 마지막 catch 블록에는 Exception 클래스를 지정해서 예상하지 못한 예외도 잡을 수 있도록 한다.
try {
//예외발생할 가능성이 있는 문장
} catch(Exception1 e1) { // (내가 잡을 예외의 클래스명 변수)
//Exception1이 발생했을 경우, 이 예외를 처리하기 위한 문장
//보통 이곳에 예외메세지를 출력하고 로그로 남김.
} catch(Exception2 e2) {
//Exception2이 발생했을 경우, 이를 처리하지 위한 문장적는다.
- try ~ catch 구문으로 에외처리시 수행문 실행
try {
예외발생이 예상되는 수행문1;
수행문2;
수행문3;
} catch (발생이예상되는예외클래스명 변수명) {
예외 발생시 실행될 수행문4;
예외 발생시 실행될 수행문5;
} 수행문6;
- 수행문1에서 예외발생하지 않는 경우 실행되는 수행문
- 예외발생이 예상되는 수행문1
- 수행문2
- 수행문3
- 수행문6
- 수행문1에서 예외가 발생하는 경우 실행되는 수행문
- 예외발생이 예상되는 수행문1
- 예외 발생시 실행될 수행문4
- 예외 발생시 실행될 수행문5
- 수행문6
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionApp2 {
public static void main(String[] args) {
// checkedException이 발생하는 예 -> 에외처리를 안하면 아예 오류
System.out.println("## 프로그램 시작");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
System.out.println("### 예외처리 발생이 예상되는 수행문 실행 시작");
Date date1 = sdf.parse("2022-12-31");
System.out.println("첫번째 날짜: " + date1);
Date date2 = sdf.parse("20221231"); // 여기서 예외 발생 -> catch로 감
System.out.println("두번째 날짜: " + date2);
System.out.println("### 예외처리 발생이 예상되는 수행문 실행 종료");
} catch (ParseException ex) { // ParseException을 가로채고 그 예외가 변수 ex에 들어감
System.out.println("### 가로챈 예외: " + ex);
System.out.println("### 발생한 예외를 가로채고, 예외처리 작업을 수행");
}
System.out.println("### 프로그램 종료");
}
}
## 프로그램 시작
### 예외처리 발생이 예상되는 수행문 실행 시작
첫번째 날짜: Sat Dec 31 00:00:00 KST 2022
### 가로챈 예외: java.text.ParseException: Unparseable date: "20221231"
### 발생한 예외를 가로채고, 예외처리 작업을 수행
### 프로그램 종료
try {
Date date2 = sdf.parse("20221231");
여기서 예외가 발생 -> catch문장 실행 (try안에서 예외가 발생했을 때만 catch 실행)
} catch (ParseException ex) {
-> catch에서 ParseException을 잡아냄 -> 잡아낸 예외가 변수 ex에 들어감
타입에 실제로 발생한 예외 or 그 예외의 부모 예외객체를 적어도 됨 ( = Exception )
-> 일괄처리할 때 부모객체를 적어두면 예상하지 못했던 예외들도 잡을 수 있음 ( 부모객체니까 다 담겨서 )
-> 그래서 항상 맨 마지막에 보험으로 적어둠
ex)
*오류: 네트워크 접속사가 많아서 연결이 되지 않음 ( 오류의 원인 제시 )
*오류: 사용자 아이디가 일치하지 않음 ( 오류의 원인 제시 )
*오류: 알 수 없는 이유로 연결할 수 없음 ( 오류의 원인 알 수 없을 때 )
-> 각각의 오류페이지를 다 준비를 해놓는데, 만약 예상치 못한 오류라면 마지막에 저렇게 일괄처리
2) throws 로 예외처리 위임하기
- 메소드에서 발생하는 예외를 직접 처리하지 않고, 그 메소드를 호출하는 측에서 예외처리를 위임하는 것이다.
- throws 키워드를 사용해서 예외처리를 위임할 수 있다.
- 예외가 발생하는 메소드에서 예외처리와 관련한 코드의 작성을 할 필요가 없다.
- 예외처리를 각각의 메소드에서 직접 개별적으로 처리하지 않고, 한 군데에서 일괄처리하게 만들 수 있다.
- 예외를 위임하기
public void method() throws 예외클래스명, 예외클래스명, ... {
예외발생이 예상되는 수행문;
예외발생이 예상되는 수행문;
}
* method4에서 yyyException이 발생
-> method4를 호출한 method2로 yyyException에 대한 예외처리를 대신 하라고 던짐
-> method2를 호출한 곳으로 yyyException에 대한 예외처리를 대신 하라고 던짐
-> yyyException예외를 catch해서 예외처리를 실행
-> 이렇게 하면 호출하는 메소드가 많아질 수록, throws하는 예외객체가 많아짐
( void method5() throws xxxException, yyyException, zzzException, ... )
-> unchecked (RuntimeException) -> 내가 throws를 적지 않아도 알아서 던짐 !!!
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionApp3 {
public static void main(String[] args) {
try { // 예외를 일괄처리 -> 그럼 각각의 메소드에서 예외를 처리할 필요가 없음
// Exception이 발생하는 거를 2개나 호출할거야 -> 일괄처리
Date date = ExceptionApp3.stringToDate("2012-12-31"); // 얘가 stringToDate를 호출 -> 밑에서 throws를 던져서 얘가 예외를 처리하게 됨
System.out.println(date);
ExceptionApp3.writeText("안녕하세요"); // 얘가 writeText를 호출 -> 얘가 예외를 위임하게 됨
} catch (ParseException ex) {
System.out.println("### 올바른 날짜 형식의 문자열이 아닙니다.");
} catch (IOException ex) {
System.out.println("### 입출력 작업 중 오류가 발생하였습니다.");
} catch (Exception ex) {
System.out.println("### 알 수 없는 오류가 발생하였습니다.");
}
}
// 예외처리를 이 메소드를 호출하는 측에게 위임함 (stringToDate를 호출한 메소드가 throws를 맞음)
public static Date stringToDate(String text) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(text);
return date;
}
public static void writeText(String text) throws IOException {
FileWriter writer = new FileWriter("sample.text");
writer.write(text);
writer.flush();
writer.close();
System.out.println(text);
}
}
Mon Dec 31 00:00:00 KST 2012
안녕하세요
'수업내용 > Java' 카테고리의 다른 글
[2022.10.12.수] 예외처리 실습 (0) | 2022.10.12 |
---|---|
[2022.10.11.화] 예외처리 활용 (0) | 2022.10.11 |
[2022.10.06.목] List 실습, Map<K, V> 인터페이스 (0) | 2022.10.06 |
[2022.10.05.수] 콜렉션(List<E>) (0) | 2022.10.05 |
[2022.10.04.화] 제네릭, 콜렉션(set<E>) (0) | 2022.10.05 |