[11]JAVA Nam GungSung Class(02 18) chapter 8 예외처리 - Jo-Jun-Yeong/NamGungSung-class GitHub Wiki

ch8-1 프로그램 오류

  • 컴파일 에러(compile-time error) : 컴파일 할 때 발생하는 에러

  • 런타임 에러(runtime error) : 실행할 때 발생하는 에러

  • 논리적 에러(logical error) : 작성 의도와 다르게 동작

  • java 의 런타임 에러

  1. 에러(error) : 프로그램 코드에의해서 수습될 수 없는 심각한 오류 (OOME...)
  2. 예외(exception) : 프로그램. 코드에 의해서 수습될 수 있는 다소 미약한 오류 예외처리(exception handling) (1) 정의 : 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것
    (2) 목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것

ch8-3 Exception과. RuntimeException

  • Exception 클래스들 : 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외
  • RuntimeException : 프로그래머의 실수로 발생하는 예외
  • IOException : 입출력 예외(In / Out)

  • Class Not Found Exception : 클래스 인식 불가

  • ...

  • Run Time Exception

  • ArithmeticException : 산술계산 예외

  • ClassCast : 형변환 예외

  • NullPoint : Null 값 객체의 메소드를 호출 예외

  • ... *IndexOutOfBoundsException : 배열. 범위를 벗어난 예외

ch8-4 예외 처리하기, try-catch문의 흐름

예외처리(exception handling)의

  • 정의 : 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는것
  • 목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는것

ch8-5 try - catch문에서의 흐름

  1. try블럭 내에서 예외가 발생한 경우.
  • 발생한. 예외와 일치하는 catch블럭이 있는지 확인한다
  • 일치하는 catch블럭을 찾게 되면, 그 catch블럭 내의 문장들을 수행하고 전체try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행한다. 만일 일치하는 catch블럭을 찾기 못하면, 처리되지 못한다.

catch블럭을 찾지 못해서 예외처리가 되지 못하면 프로그램 비정상종료가된다

  1. try블럭 내에서 예외가 발생하지 않은 경우.
  • catch블럭을 거치지 않고 전체 try - catch문을 빠져나가서 수행을 계속한다.

	//예외가 발생하지 않았을 경우
	System.out.println(1);
	try {
		System.out.println(2);
		System.out.println();
	}  catch (Exception e) {
		System.out.println(4);
	} 
	//try - catch의 끝
	System.out.println(5);

	//예외가 발생했을 경우
	System.out.println(1);
	try {
		System.out.println(0/0); 	//1. 예외발생!!
		System.out.println(2); 		//2. 예외가 발생한 이후의 문장은 실행이 안된다.
	}  catch (ArithmeticException ae) { // 3.catch문을 수행 후. 
		System.out.println(3);
	}//try - catch의 끝 			// 4. try- catch 문 전체를 빠져나간다
	System.out.println(4);

ch8-6 예외의 발생과 catch블럭 (예제)

  • 예외가 발생하면, 이를 처리할 catch블럭을 찾아 내려감
  • 일치하는 catch블럭이 없으면, 예외는 처리 안됨
  • Exception이 선언된 catch블럭은 모든 예외 처리(마지막 catch블럭)

	System.out.println(1);
	System.out.println(2);
	try {
		System.out.println(3);
		System.out.println(0/0); 	//0으로 나눠서 ArithmeticException을 고의로 발생
		System.out.println(4);
	} catch (ArithmeticException ae) {
		if(ae instanceof ArithmeticException)
			System.out.println("true");
		System.out.println("ArithmeticException");
	} catch (Exception e){ 		//ArithmeticException을 제외한 모든 예외가 처리된다
		// Exception -> 모든 예외의 최고조상 -> 모든 예외 처리 가능
		System.out.println("Exception");
	} 	//try - catch 의 끝
	System.out.println(6);

ch8-7 PrintStackTrace() 와 getMessage()

  • printStackTrace() : 예외발생 당시의 호출스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다.
  • getMessage() : 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.

	//예제
	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());
	} 	//try - catch 의 끝
	System.out.println(6);
} 	//main메서드

//출력
1
2
3
java.lang.ArithmeticException: / by zero // <- getmessage가 반환된 부분
	at Exception_Test.main(Exception_Test.java:10)
예외 메시지 : / by zero
6

ch8-8 멀티 catch 블럭

  • 내용이 같은 catch블럭을 하나로 합친 것(JDK1.7부터)

//ex
//같은 catch블럭을 따로 
try { 
	
}
catch(ExceptionA e) {
	e.printStackTrace();
}
catch(ExceptionB e2) {
	e2.printStackTrace();
} //위처럼 같은 제외의 chatch블럭을 하나로합치면
// 같은 catch블럭을 하나로 합친 경우
try {
	
} catch (ExceptionA | ExceptionB e) {
	e.printStackTrace();
}

##주의할 점

  1. (parentException | childException e)과 같이 부모자식 관계를 묶으면 안된다.

부모타입의 예외면 자식을 굳이 쓸 필요가 없다.

  1. (ExceptionA | ExceptionB e) 일경우 ExceptionA의 메소드만 호출해서는 안된다.즉 공통된 맴버만 사용 가능하다.

사용하고자하면 if 문을 사용하여 (ExceptionA)e 와 같이 형변환을 해줘야 한다. -> 아예 따로사용할 지언정 굳이 이렇게 사용하지 않는다.

ch8-9 예외 발생시키기

  1. 연산자 new를 이용해서 발생기키려는 예외 클래스의 객체를 만든다음

Exception e = new Exception("고의로 발생기켰음");

  1. 키워트 throw를 이용해서 예외를 발생시킨다

throw e;


	try {
		Exception e = new Exception("고의로 발생시켰음"); // 1. Exception이라는 예외에대한 정보가 담겨있는 객체를 만들고
		throw e; 	// 2. throw를 통해 예외를 발생 시킴
		//throw new Exception("고의로 발생시켰음")을 통해 한문장으로 가능
		
	} catch (Exception e) { // 3. 발생한 예외와 catch블럭에 선언된 예외의 와 같으므로 참조변수에 해당 객체의 주소가 담겨짐  
		System.out.println("dpfjaptlwl : "+ e.getMessage());
		e.printStackTrace();
	}
	
	System.out.println("프로그램 정상 종료");
	
} 	//main메서드

ch8-10 checked예외, unchecked예외

  • checked예외 : 컴파일러가 예외 처리 여부를 체크(예외 처리 필수) (Exception과 그 자손)
  • unchecked예외 : 컴파일러가 예외 처리 여부를 체크 안함(예외 처리 선택) (RuntimeException과 그의 자손들)

public static void main(String[] args) {
	
	try {
		throw new Exception(); 	// Exception과 그 자손은 컴파일러가 확인을 함으로 try-catch를 써야 에러가 나지 																				않는다
		
	} catch(Exception e) {}

public static void main(String[] args) {

	
	throw new RuntimeException(); 	// throw new RuntimeException을 고의로 발생시킨다
	//예외처리(try-catch) 가 선택이기떄문에 예외처리를 하지 않아도 컴파일은 된다(오류가 안나는건 아님)
}

오류

  1. 컴파일 에러
  2. 런타임에러

Error : 심각
Exception : 덜 심각
ㄴException과 자손 : 체크드 체외(필수)(try-catch)
ㄴRuntimeException과 자손 : 언체크드예외(선택)

  1. 논리적 에러

ch8-11 메서드에 예외 선언하기 finally블럭

  • 메서드가 호출시 발생가능성이있는 예외를 호출하는 쪽에 알리는 것
  • 예외를 처리하는 방법
  1. try-catch
  2. 예외 선언하기 (떠넘기기)
  • 직접처리
  • 예외 떠넘기기
  • 은폐(덮기) (try-catch블럭에 빈공간으로 넣기 방대한 데이터를 처리할때 영양없는 데이터를 버려야할때)
  • 예외 선언하는 방법

	void method() throws Exception1, exception2,args ExceptionN{ 	//예외할 예외 선언,  ','로 구분한다.
		//메서드  내용
	}
	
	//  method()에서 exception과 그자손 예외 발생  가능
	
	void  method() throws Exception{ //Exception은 모든 Exception의 조상이므로 이 한개가 모든 자손 선언의 갯수보다 많다.
		// 메서드 내용
		
	}

	//ex
	static void startINstall() throws SpaceException, MemoryException { 	//예외시킬 예외들
		if(!enoughSpace())
			thorw new SpaceException("설치할 공간이 부족합니다.");
		if(!enoughMenory())
			throw new MemoryException("메모리가 부족합니다.");
	} 	//startINstall메서드의 끝

//ex
public class Exception_Test {

	public static void main(String[] args) throws Exception{ 	
		//최종적인 main메서드에도 try-catch문이 없어서  자바 버츄얼머신(JVM)에게 넘어간다.
		method1(); 	//같은 클래스 내의 static맴버이므로 객체생성없이 직접호출 가능.
		//ex 
	}		//main
	
	static void method1() throws Exception{
		method2();
	}	 //method1의 끝
	
	static void method2() throws  Exception{
		throw new  Exception();
	} 	//method2의 끝
	
	
} 		//public class
//출력
//자바 버츄얼머신의 예외처리기가 출력한 결과
Exception in thread "main" java.lang.Exception //JVM에의해 예외됨
at Exception_Test.method2(Exception_Test.java:15) //예외를 선언했지만 try-catch가 없어서 떠넘겨짐
at Exception_Test.method1(Exception_Test.java:11) //예외를 선언했지만 try-catch가 없어서 떠넘겨짐
at Exception_Test.main(Exception_Test.java:6) //예외를 선언했지만 try-catch가 없어서 떠넘겨짐
따라서 main에서도 예외처리되지않아서 비정상종료가 된다

즉 직접 처리하냐(수행하는 method에서 try-catch적용) 떠넘기냐(호출한 메서드에서 try-catch)를 적용하냐)의 차이이고 이를 생각하고 적용해야한다.

ch8-14 finaly블럭

  • 예외 발생여부와 관계업싱 수행되어야 하는 코드를 넣는다.
  • 작업의 성공 여부없이 실행될수있는 기능

	public static void main(String [] args) {
		try {
			// 예외가 발생할 가능성이 있는  문장들을 넣는다. 
		} catch (Exception1 e1) {
			// 예외처리를 위한 문장을  적는다.
		} finally {
			// 예외의 발생여부에 관계없이 항상 수행되어야하는  문장들을 넣는다.
			// finally블럭은 try-catch문의 맨 마지막에 위치해야 한다.
		}
		// ** try블럭 안에 return문이 있어서 try블럭을 벗어나갈 때도 finally블럭이 실행된다. **

} 		//public class

ch8-15 사용자 정의 예외 만들기

  • 우리가 직접 예외 클래스를 정의할 수 있다.
  • 조상은 Exception(필수 try-catch)과 RuntimeException(선택 try-catch)중에서 선택

가능하면 RuntimeException, 필요할떄 exception


public class Exception_Test extends Exception {
	Exception_Test extends Exception{
		Exception_Test(String msg){ 	//꼭 문자열을 매개변수로받는 생성자를 만들어야
			super(msg); 	//그리고 또 그안에는 조상생성자를 넣어줘야 한다.
		}
		
	} //main			
	} 		//public class

class MyException extends Exception{
	//에러 코드값을 저장하기 위한 필드를 추가
	
	private final int ERR_CODE; //생성자를 통해 초기화 한다.
	
	MyException(String msg, int errCode){ 	//생성자
		super(msg); 			// 조상의 생성자 호출	
		ERR_CODE = errCode; 	//매개변수 초기화
	}
	
	MyException(String msg){ 	// 생성자
		this(msg, 100); 		// ERR_CODE를 100(기본값)으로 초기화 한다.
	}
	
	
	public int getErrCode() { 	// 에러 코드를 얻을 수 있는 메서드도 추가했다.
		return ERR_CODE; 		// 이 메서드는 주로 getMessage()와 함께 사용될 것이다.
	}
}

1. Exception과 RuntimeException중 무엇을 조상으로할지 선택하는 것이 중요
2. 메소드의 매개변수로 String을 넣어준다
3. 그 안에 조상(Exception)의 생성자를 호출한다.

ch8-17 예외 되던지기(exception re-throwing)

  • 예외를 처리한 후에 다시 예외를 발생기키는 것
  • 호출한 메서드와 호출된 메서드 양쪽 모두세어 예외처리하는 것

public static void main (String [] args) {
	try { 	
		method1(); 	//  1. 예외 발생 3. 다시예외 발생
	} catch (Exception e) { // 4. 예외 처리
		System.out.println("main 메서드에서 예외가 처리되었습니다.");
	}
} //main

static void method1() throws Exception {
	try {
		throw new Exception();
	} catch  (Exception e) { // 2. 예외 처리 
		System.out.println("method1 메서드에서  예외가 처리되었습니다."); // 
		throw e; 		//  3. 다시 예외  발생
	}
} 	//method1 끝

왜하는건지 모르겠네

ch8-18 연결된 예외(chained exception)

  • 한 예외가 다른 예외를 발생시킬 수 있다.
  • 예외 A가 예외 B를 발생시키면 A는B의 원인예외(cause exception)
  • Throwable initCause(Throwable 예외A) : 지정한 예외를 원인 예외로 등록
  • Throwable getcause() : 원인 예외를 반환

void install() throws InstallException{
	 try {
		 startInstall(); 			// 여기서 SpaceException 발생
		 copyFiles();
	 } catch (SpaceException e) 	{
		 InstallException ie = new InstallException("설치중 예외 발생"); 	//예외 생성
		 ie.initCause(e); 	// InstallException의 원인 예외를 SpaceException으로 지정
		 // intitCause()를 사용해서 e를 InstallException에 포함시킨다
		 throw ie; 			// InstallException을 발생시킨다.
	 } catcg (MemoryException me) 	{
		 
	 }
}

왜 연결된 예외(chained exception)을 사용하는가?
[이유1] 여러 예외를 하나로 묶어서 다루기 위해서
-> 많아지는 catch블럭을 줄이기 위함
[이유2] checked 예외를 unchecked예외로 변경하려 할 때

checked(Exception의 자손-필수처리)
unchecked(RuntimeException의 자손 - 선택처리)
필수처리일 경우 try-catch를 꼭 써야하기때문에 불필요한 코드들이 많아지므로
연결된 예외(chained Exception)를 시용하여 checked -> unchecked로 변경한다.

  1. 세부적 예외를 포괄적 예외로 감쌀때 사용
  2. checked를 unchecked예외로 변경할때 사용한다.