본문 바로가기

Java

14 - 2장 예외 처리

1. 예외 처리 문법

try {
	//일반 예외, 실행 예외 발생 가능 코드
} catch (예외 클래스명 참조 변수명) {
	//예외가 발생했을 떄 처리 
} finally {
	//예외 발생 여부에 상관없이 무조건 실행
}

 -try {}

  -> 예외가 발생할 수 있는 코드 포함

 

 - catch{} 

  -> 예외가 발생했을 때 처리할 코드 포함

  -> 모든 예외를 처리하는 것은 아니며, 소괄호 안의 예외 타입에 해당하는 예외에 한해서만 처리 가능

  -> 예외가 발생했을 때만 동작하며 예외 없이 정상적으로 동작할 때는 실행되지 않음

 

 - finally {}

  -> 예외가 발생하든, 발생하지 않든 항상 실행되는 블록

  -> 리소스 해제, try{}, catch{} 블록의 공통 기능 코드 포함

  -> 생략 가능

 

try {
	System.out.println(3/0);
    System.out.println("프로그램 종료");
} catch(ArithmeticException e) {
	System.out.println("숫자는 0으로 나눌 수 없습니다.");
    System.out.println("프로그램 종료");
}

- try{},catch{} 내의 공통된 코드는 예외 발생 여부와 상관없이 항상 실행되는 코드 

 -> finally{} 블록을 사용해 작성하면 코드의 중복을 제거 가능

try {
	System.out.println(3/0);
} catch (ArithmeticException e) {
	System.out.println("숫자는 0으로 나눌 수 없습니다.");
} finally {
	System.out.println("프로그램 종료"); //중복된 코드는 finally{} 블록에 입력
}

 

2. 예외 처리 과정

 

- ArithmeticException 실행예외가 발생하는 코드 

try {
	System.out.println(3/0);
}
catch(ArithmeticException e){
	System.out.println("숫자는 0으로 나눌 수 없습니다.");
}
finally {
	System.out.println("프로그램 종료");
    System.exit(0);
}

 - 먼저 try{}구문 실행

 - 예외가 발생하지 않는다면 catch()블록은 실행안됨

 

 - 예외가 발생하면 자바 가상 머신이 가장 먼저 인지

 - 자바 가상 머신은 발생한 예외 타입의 객체를 생성해 catch(){} 블록의 매개변수로 전달 

   ex) ArithmeticException이 발생하면 JVM은 ArithmeticException 객체를 생성하고, 

       생성 객체를 catch(){}블록의 매개변수로 전달

 

  - 자바 가상 머신이 생성해 넘겨 준 객체 타입을 catch(){} 블록이 처리할 수 없을때, 예외처리가 되지 않아 프로그램이 강제 종료

 

3. 다중 예외 처리 

 

 - 메서드가 다양한 입력매개변수 타입으로 오버로딩될 수 있는 것 처럼

  catch(){}블록도 예외 타입에 따라 여러개 포함 가능

//1) 분모가 0일 때 ArithmeticException을 처리하는 예외 처리 구문
try {
	System.out.println(3/0);
}catch (ArithmeticException e) {
	System.out.println("숫자는 0으로 나눌 수 없습니다.");
} finally {
	System.out.println("프로그램 종료");
}

//2) 숫자가 아닌 문자열을 숫자로 변환하는 과정에서 발생하는 NumberFormatException을 처리하는 예외처리 구문
try {
	int a = Integer.parseInt("20A");
}catch(NumberFormatException e) {
	System.out.println("숫자로 변환할 수 없습니다.");
}finally {
	System.out.println("프로그램 종료");
}

 - 각각의 catch(){} 블록을 하나의 예외처리 구문으로 묶어 다음과 같이 표현 가능

try {
	System.out.println(3/0);
    int a = Integer.parseInt("20A");
}
catch(ArimeticException e) {
	System.out.println("숫자는 0으로 나눌 수 없습니다.");
}
catch(NumberFormatException e) {
	System.out.println("숫자로 변환할 수 없습니다.");
}
finally {
	System.out.println("프로그램을 종료합니다.");
}

 - try{}()블록 안에는 예외가 발생할 가능성이 있는 구문이 모두 포함

  -> ArithmeticException이 발생하면 첫번째 catch{}()구문이 실행

  ->NumberFormatException이 발생하면 두번쨰 catch{}()구문이 실행

 

- 여러개의 catch(){}블록이 있을때 , 실행할 catch(){}블록의 선택과정은 항상 위에서 부터 확인 

try {
	int a = Integer.parseInt("20A");
    System.out.println(3/0);
}
catch(Exception e) {
	System.out.println("숫자는 0으로 나눌 수 없습니다."):
}
catch(NumberFormatException e) { // 도달 불가능 코드 
	System.out.println("숫자로 변환할 수 없습니다.");
}

 -  먼저 Exception 타입인지를 확인 

 - 모든 예외는 Exception 클래스의 하위 클래스 이므로 어떤 예외가 발생하든 첫 번째 catch(){} 블록만 실행 

 - 두 번째 catch(){} 블록을 절대 도달할 수 없는 코드 (unreachable code)가 되어 오류 발생

 

- 다중 예외 처리 과정에서 각각의 예외가 발생했을 때 처리하는 내용이 동일할 수 있음

  -> 1개의 catch(){}블록이 2개의 예외를 동시에 처리하도록 통합할 수 있다.

  -> 각각의 예외 타입은 OR(|) 기호를 사용해 연결

try {
	//...
}catch(예외 타입 A | 예외 타입 B 참조 변수명) {
	//...
} finally {
	//...
 }
try {
	System.out.println(3/0);
    int a = Integer.parseInt("20A");
}
catch(ArithmeticException | NumberFormatException e) {
	System.out.println("프로그램을 종료합니다.");
}

 

4. 리소스 자동 해제 예외 처리 

 

- finally{} 블록의 가장 대표적인 기능은 리소스를 해제

- 리소스 해제 : 더이상 사용하지 않는 자원을 반납하는 것 ex) 자바 입출력 리소스 

 

- try{} 블록에서 리소스를 사용하는 객체를 생성한 후 finally{} 블록에서 리소스를 해제하는 예외 처리 구문

InputStreamReader is = null;
try {
	is = new InputStreamReader(System.in);
    System.out.println(is.read());
} catch(IOEception e) {
	//예외 처리 
} finally {
	if(is !=null) {
    	try {
        	is.close();
        } catch(IOException e) {
        	//예외 처리
        }
    }
}

 - try{} 블록에서는 문자 단위로 입력을 수행하는 InputStreamReader 객체를 생성해 사용

 - finally{} 블록에서는 자원을 반납(is.close())

 

- 리소스 자동 해제 예외 처리 

try(리소스 자동 해제가 필요한 객체 생성) {
	//예외 발생 가능 코드
}
catch(예외 클래스명 참조 변수명) {
	//해당 예외가 발생했을 때 처리하는 블록
}
finally {
	//예외 발생 여부에 상관없이 무조건 실행하는 블록
}

- 자동으로 리소스를 반납해야할 객체를 생성하면 예외 처리 구문의 실행이 끝났을 때 리소스가 자동으로 해제

- 예외 처리 구문이 완료되면 try(){} 블록의 소괄호 안에서 생성된 객체 내부의 close() 메서드를 자동으로 호출함으로써 

리소스를 자동으로 해제 

 

try(InputStreamReader is = new InputStreamReader(System.in;) {
	System.out.println(is.read());
}
catch(IOException e) {
	//예외 처리
}

 

//try with resourse 구문 1
try(InputStreamReader isr1 = new InputStreamReader (System.in);) { //자동 해제
	char input = (char) isr1.read();
    System.out.println("입력 글자 =" + input);
} catch(IOException e) {
	e.printStackTrace();
}

//try with resourse 구문 2
try(InputStreamReader isr2 = new InputStreamReader(System.in);) { //리소스 반납으로 사용불가
	char input =(char)isr2.read(); // System.in 리소스가 반납돼 예외 발생
    System.out.println("입력 글자=" + input);
} catch (IOException e) {
	e.printStackTrace();
}

 - try- catch 구문을 끝낼 때 리소스를 해제하기 때문에 이후에는 콘솔 입력을 사용할 수 없게 됨

- System.in : 콘솔 입력을 처리하는 리소스로, 자바 가상 머신이 단 하나의 객체를 생성해 제공하기 때문에 이를 반납하면 더이상 콘솔을 입력할 수 없음

 

package TryWithResouce;

import java.io.IOException;
import java.io.InputStreamReader;

public class TryWithResouce {
	public static void main(String[] args) {
		
		System.out.println("문자를 입력하세요!");
		
		//System.in 리소스를 해제하면 더이상 콘솔 입력 불가 
		//1.리소스 자동 해제 
		try(InputStreamReader isr1 = new InputStreamReader(System.in);) {
			char input = (char)isr1.read();
			System.out.println("입력 글자 ="+ input);
		}
		catch(IOException e) {
			e.printStackTrace();
		}
		
		//2.리소스 수동 해제 
		InputStreamReader isr2 = null;
		try {
			isr2 = new InputStreamReader(System.in);
			char input = (char)isr2.read();
			System.out.println("입력 글자 ="+ input);
		}
		catch(IOException e) {
			e.printStackTrace();
		}
		finally {
			//리소스 해제 구문
			if(isr2!=null) {
				try { //리소스 해제
					isr2.close();
				}catch(IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

 

- 리소스 자동 해제 예외 처리 구문은 예외의 발생 여부와 관계없이 예외 처리 구문이 완료된 후 리소스 객체의 close() 메서드를 자동으로 호출

- 리소스 객체 내부에 close() 메서드가 있어야 자동해제 할 수 있는 객체가 될 수 있음

- 리소스 자동 해제를 위한 클래스는 반드시 AutoCloseable 인터페이스를 구현해야 함

- AutoCloseable 인터페이스 내부에는 close() 메서드를 포함돼 있음

 

class A implements AutoCloseable {
	String resourse;
    A(String resourse) {
    	this.resourse = resourse;
    }
    @override
    public void close() thros Exception {
    	resource = null;
        System.out.println("리소스 해제");
     }
}

 - AutoCloseable 인터페이스를 구현한 후 close() 메서드의 내부에서 오버라이딩한 클래스 정의 

 - 예외처리 구문이 실행된 이후 close() 메서드가 호출 된다는 것을 보이기 위해  

내부에서는 필드를 null값으로 초기화 하고 "리소스 해제" 구문만 출력하는 코드 작성

 

try(A a = new A("특정 파일");) {
}
catch(Exception e) {
} //"리소스 해제"출력

- 명시적으로  close() 메서드의 호출 구문이 없는데도 "리소스 해제"구문이 출력

 

package TryWithResouce;

class A implements AutoCloseable {
	String resource;
	A(String resouce){
		this.resource = resouce;
	}
	//@override
	public void close() throws Exception {
		if(resource!=null) {
			resource=null;
			System.out.println("리소스가 해제되었습니다.");
		}
	}
}

public class TryWithResouce {
	public static void main(String[] args) {
		
		//1.리소스를 사용하고 finally에서 리소스 수동 해제하기 
		A a1 = null;
		try {
			a1 = new A("특정파일");
		}catch(Exception e) {
			System.out.println("예외 처리");
		}finally {
			//리소스 수동 해제
			if(a1.resource!=null) {
				try {
					a1.close();
				}catch(Exception e) {}
			}
		}
		
		//2.리소스 자동 해제
		try(A a2 = new A("특정 파일");) {
		}catch(Exception e) {
			System.out.println("예외 처리");
		}
		
	}
}

'Java' 카테고리의 다른 글

14 - 4장 사용자 정의 예외 클래스  (0) 2023.06.13
14 - 3장 예외 전가  (0) 2023.06.13
14 - 1장 예외  (0) 2023.06.12
13 - 3 장 이너 인터페이스  (0) 2023.06.05
13 - 2 장 익명 이너 클래스  (0) 2023.06.05