>>프로그램 오류
: 에러는 어쩔 수 없지만 예외는 처리해야 함
에러 : 프로그램 코드에 의해서 수습될 수 없는 심각한 오류
예외 : 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류
>>예외 클래스의 계층구조
- Object를 가장 상위계층으로
- Throwable => Exception + Error
- RunException 클래스 -> 프로그래머의 실수로 발생하는 예외(예외처리 선택)
- Exception 클래스 들 => 사용자의 실수와 같은 외적인 요인에 의해 발생(예외처리 필수)
>>예외 처리하기
: 프로그램 실행시 발생가능한 예외에 대비한 코드를 작성하는 것
=> 프로그램 비정상 종료를 막음
try-catch문
- 1. 하나의 메서드에 여러개의 try-catch문 사용 가능
- 2. try블록 / catch 블록 에 또다른 try-catch문 포함 가능
ex)
public class ExceptionEx3 {
public static void main(String[] args) {
int num= 100;
int result=0;
for(int i=0; i<10; i++){
try{
result= num/(int)(Math.random()*10);
System.out.println(result);
}catch(ArithmeticException e){
System.out.println(0);
}
}
}
}
random값이 0일 때 => ArthmeticException
>>실행결과
20
33
14
12
20
11
0 => 예외처리
33
25
16
>>try-catch문에서의 흐름
=> try블럭에서 예외가 발생하면, 이후의 코드는 수행되지 않으므로
코드의 범위를 잘 선택해야 함
>> 예외의 발생과 catch 블럭
- 괄호 안에 예외와 같은 타입의 참조변수 선택
- 차례로catch 블럭을 내려가면서 catch블럭 괄호 안에 참조변수의 종류와 생성된 예외 클래스의 인스턴스에 instanceof연산자를 이용해서 검사하게 됨
=> Exception 클래스 처리 == 어떤 종류의 예외라도 처리됨
package ch8;
public class ExceptionEx7 {
public static void main(String[] args) {
System.out.println(1);
System.out.println(2);
try{
System.out.println(3);
System.out.println(0/0); //예외 발생
System.out.println(4); // 실행되지 않음
}catch( ArithmeticException ae){
if( ae instanceof ArithmeticException){
System.out.println("true");
System.out.println("ArithmeticException");
}
}catch(Exception e) //이미 위에서 처리가 되었기에 실행 x
{
System.out.println("Exception");
}
System.out.println(6);
}
}
>>실행결과
1
2
3
true
ArithmeticException
6
=> 첫번째 catch문에서 일치하는 블럭을 찾아씩 때문에 두번째 catch 블럭은 검사x
>>printStackTrace()와 getMessage()
printStackTrace()
: 예외 발생 당시 호출 스택에 있었던 메서드 정보와 예외메시지를 한번에 출력
getMessage()
: 예외 인스턴스에 저장된 메시지를 얻을 수 있음
ex)
public class ExceptionEx8 {
public static void main(String[] args) {
System.out.println(1);
System.out.println(2);
try{
System.out.println(3);
System.out.println(0/0);
System.out.println(4);
}catch(ArithmeticException ae){
ae.printStackTrace();
System.out.println("예외 메시지 : " +ae.getMessage());
}
System.out.println(6);
}
}
>>실행결과
1
2
3
java.lang.ArithmeticException: / by zero
at ch8.ExceptionEx8.main(ExceptionEx8.java:9)
예외 메시지 : / by zero
6
>>멀티 캐치 블럭
: |를 이용해서 하나의 catch블록으로 합칠 수 있게 됨
: 조상과 자손 관계에 있으면 컴파일 에러 => 조상 클래스 하나만 예외 처리해도 되므로
: 둘 중 어떤 예외가 발생한 것인지 알 수 없으므로 instacneof로 객체 확인 필요
>>예외 발생시키기
- Exception 인스턴스 생성자에 String을 넣으면 => String이 인스턴스의 메시지로 저장
- Exception 클래스들은 오류가능성이 있는데 예외처리를 안하면 컴파일x =>checked
- RuntimeException 클래스들은 오류가능성이 있어도 컴파일이 됨 => unchecked
>>메서드에 예외 선언하기
- 메서드 선언부에 throws를 사용해서 발생가능한 예외를 적어주면 됨
=> 메서드를 사용하는 사람이 보았을 때, 어떤 예외가 처리되어야 하는지 파악가능
=> 보통 Exception 클래스들(반드시 처리되어야 하는 것들)만 적음
ex)
알 수 있는 것
- 3개의 메서드(method2, method1, main)이 스택에 있었음
- method2에서 예외가 발생
- main -> method1 -> method2를 호출
=> 예외처리를 분담할 수도, 한 메서드에서 자체적으로 처리하게 할 수도 있음
>>finally 블록
- 예외 발생여부와 상관없이 실행
- 주로 try와 catch블럭에 공통적으로 들어가하는 부분을 포함
- return이 되어도 finally 실행 후 종료
ex) finally를 실행이 보장된다. => return되어도 실행!!
package ch8;
public class FinallyTest {
public static void main(String[] args) {
FinallyTest.method1();
System.out.println("method1의 수해을 마치고 main으로 돌아옴");
}
static void method1(){
try{
System.out.println("method1이 호출됨");
return;
}catch(Exception e){
e.printStackTrace();
}finally{ //실행됨
System.out.println("method1()의 finally블록이 실행되었습니다.");
}
System.out.println(1); //실행안됨
}
}
>>실행결과
method1이 호출됨
method1()의 finally블록이 실행되었습니다.
method1의 수해을 마치고 main으로 돌아옴
>>try-with-resource 자원 자동반환
- 괄호 안에 객체를 생성하는 문장을 넣으면 try문을 벗어나느 순간 자동적으로 close() 호출
public class TryWithResourceEx {
public static void main(String[] args) {
try(CloseableResource cr = new CloseableResource()){
cr.exceptionWork(false);
}catch(WorkException e){
e.printStackTrace();
}catch(CloseException e){
e.printStackTrace();
}
System.out.println();
try(CloseableResource cr = new CloseableResource()){
cr.exceptionWork(true);
}catch(WorkException e){
e.printStackTrace();
}catch(CloseException e){
e.printStackTrace();
}
}
}
class CloseableResource implements AutoCloseable{
public void exceptionWork(boolean flag) throws WorkException{
System.out.println("ExceptionWork가 호출됨");
if(flag){
throw new WorkException("WorkException 발생!!");
}
}
public void close() throws CloseException{
System.out.println("close()가 호출됨");
throw new CloseException("CloseException발생!!");
}
}
class WorkException extends Exception{
WorkException(String msg){super(msg);}
}
class CloseException extends Exception{
CloseException(String msg){super(msg);}
}
>>실행결과
ExceptionWork가 호출됨
close()가 호출됨
ch8.CloseException: CloseException발생!!
at ch8.CloseableResource.close(TryWithResourceEx.java:35)
at ch8.TryWithResourceEx.main(TryWithResourceEx.java:9)
ExceptionWork가 호출됨
close()가 호출됨
ch8.WorkException: WorkException 발생!!
at ch8.CloseableResource.exceptionWork(TryWithResourceEx.java:30)
at ch8.TryWithResourceEx.main(TryWithResourceEx.java:16)
Suppressed: ch8.CloseException: CloseException발생!!
at ch8.CloseableResource.close(TryWithResourceEx.java:35)
at ch8.TryWithResourceEx.main(TryWithResourceEx.java:15)
=> 첫번째 try-catch에서는 CloseException
=> 두번째 try-catch에서는 WorkException + CloseException(Surppressed)
>>사용자 정의 예외 만들기
- Exception 혹은 RuntimeException 클래스를 상속받아 만듦
=> 만약 exception을 상속했다면 반드시, 예외처리를 해주어야 함 == checked
=> 만약 RuntimeException을 상속했다면 예외처리를 선택적으로 == unchecked(트렌드)
>>예외 되던지기
- 메서드 내에서 예외를 처리하고 나머지는 caller에서 처리되게 하는 것
- catch하고 같은 예외를 발생시키면 됨
- 예외가 발생한 메서드와 호출한 메서드 양쪽 모두에서 처리해주어야 할 작업이 있을 때
-> 되던지기를 하면 return을 적어주지 않는 것이 가능하다.
>>연결된 예외
- 예외 a가 예외 b를 발생시키게 함
- a를 b의 원인예외로 지정함
=> 왜 원인을 지정할까?
이유1. 하나의 큰 분류의 예외로 묶어서 다루기 위해서
ex) SpaceException -> InstallException
상속관계로 처리하게 되면 SpaceException인지 MemeoryException인지 알수가 없게 됨
이유2. checked예외를 unchecked로 바꿀 수 있도록 하기 위해서
=> MemoryException은 Exception을 상속받음(필수 예외)
그러나, RuntimeException으로 MemoryException을 감싸서 unchecked가 됨
'기술 서적 > 자바의 정석' 카테고리의 다른 글
[자바의 정석] ch11-1 : 컬렉션프레임워크 -- List / Stack-Queue (0) | 2024.01.14 |
---|---|
[자바의 정석] ch9-1. java.lang 패키지와 유용한 클래스 (0) | 2024.01.09 |
[자바의 정석] ch7. 객체지향 프로그래밍 II (0) | 2024.01.05 |
[자바의 정석] ch5. 배열 (0) | 2023.12.02 |
[자바의 정석] ch4. 조건문/반복문 (0) | 2023.10.09 |