코딩 기록들

[Java Programming] 10.2 예외처리 (try~catch, finally, throw) 본문

Java

[Java Programming] 10.2 예외처리 (try~catch, finally, throw)

코딩펭귄 2024. 1. 30. 15:32
자바의 예외 종류

 

  Throwable   (예외 최상위 클래스)

          |

  Exception   (try~catch : 필수) -> 을 상속받은 예외들은 if로 처리할 수 없음 

  (컴파일 exception : 컴파일 할 때 예외 발생 여부 확인)

-> 코드 쓸 때 예외가 반드시 처리 돼야함

(자바가 예외를 처리하는 방법을 완전히 분리시켜놨기 때문에, Exception만 상속받는 경우는 try~catch를 반드시 써주기)

ex) IOE  Exception / ClassNotFound Exception

          |

  RuntimeException   (try~catch : 옵션) -> 을 상속받은 예외들은 if로 처리할 수 있음

 (= 실행중 발생하는 예외) 

-> 실행 중 예외 '회피' 해줘야됨

ex) NullPointerException / ArrayIndexOutOfBoundsException / IndexOutOfBoundsException / NumberFormatException

 

try~catch~finally

- if 로 예외처리 할 수 없거나, 애매할경우 : try~catch~finally 사용

- 예외가 발생 할 확률이 있는 코드를 try 안에 넣어줌

- try에 들어가는 코드는 짧을수록 좋다

- try의 역할 : 예외가 발생할지 모르겠지만 일단 실행을 해봐!

  -> 예외발생? : JVM으로 예외 보내지 않고 그 예외를 내가 내부적으로 처리 -> catch 실행

   -> catch의 소괄호 안 : try코드가 예외를 발생시키는 예외클래스를 똑같이 작성해줌

  (catch : 예외가 발생되었을때 만 실행됨)

- finally : 예외가 발생했던, 하지않았던 무조건 실행됨 (DB 자바와 함께 연동할때 쓰일것)

try {
    // ▼ NumberFormatException 발생
    int number = Integer.parseInt("ABC"); // 문자를 숫자로 바꾸므로 NumberFormatException 발생
    System.out.println(number); // 이 코드는 실행되지 않습니다.
}
// ▼ NumberFormatException이 발생했을 때 catch가 실행됨
catch ( NumberFormatException e ) {
    // try에서 예외가 발생하면 catch 실행
    System.out.println("에러가 발생했습니다. " + e.getMessage()); //e : 예외의 인스턴스
    e.printStackTrace(); // 에러내용 모두 출력
}
finally { // 실무에서는 finally까지는 잘 쓰지 않음
    // 예외 발생 여부와 관계없이 무조건 실행됩니다.
    System.out.println("처리가 완료됐습니다.");
}

- try-catch문 너무 많이쓰면 수행속도에 영향을 미침(느려짐)

 

예제) SomeAClass의 패키지와 클래스이름을 가지고와서 그것의 인스턴스를 만들어라

1. 클래스 동적로딩

public static void main(String[] args) {
    Class.forName("SomeAClass");
}

-> Unhandled exception type ClassNotFoundException 발생 (ClassNotFoundException 타입 예외 에러를 처리하지 않았다는 뜻) -> 이를위해 try~catcth 문 사용 ??? 

public static void main(String[] args) {
    try {
        Class.forName("SomeAClass");
    }
    catch(ClassNotFoundException cnfe) {
        cnfe.printStackTrace();
    }
}

 

하나의 try에서 여러개의 Exception 발생 -> catch 여러번 사용
try { //try는 반드시 catch가 따라옴. 혼자있을수 없음!
	Class.forName("exception_handling.IfArrayIndexOutOfBoundsException"); 
	Files.readAllLines(imageFile.toPath()); 
}
//catch를 1개만 쓰는 방법 (쓰고봤더니 에러를 같은 방식으로 처리를 할 경우 아래와 같이 씀)
catch(ClassNotFoundException | IOException cnfe){ // 보통 여러개의 예외처리하는 이런상황에서는 cnfe이 아닌, 'ex' 라고 씀
	String message = cnfe.getMessage();
	System.out.println(message);
}

 

 

package exception_handling;

import java.io.File;
import java.nio.file.Files;
import java.io.IOException;

public class TryCatchExam {

	public static void main(String[] args) {
				
		// 시스템 드라이브에서 특정경로에 있는 파일 또는 폴더를 읽어온다.
		File imageFile = new File("c:\\sdfsdfsdf"); //생성자 뭐가있는지 궁금할땐 괄호쓰지않고 생성자 이름만쓰고 ctrl space
		
		try {
			Files.readAllLines(imageFile.toPath()); // 파일에 있는 내용들을 다 읽어와서 문자열타입으로 바꿔라
		}
		catch(IOException ioe) {
			String message = ioe.getMessage(); // catch 에 작성한 IOException와 실제 예외(java.nio.file.NoSuchFileException)는 다를 수 있다
			System.out.println(message); // java.nio.file.NoSuchFileException -> IOException을 상속받는 클래스 FileSystemException
			
			//아주 상세한 예외 목록(호출 스택)
			ioe.printStackTrace();
		}
	
    
//		Class.forName //-> 빠르게 에러종류 찾는방법 : ctrl + space

		try { //try는 반드시 catch가 따라옴. 혼자있을수 없음!
			Class.forName("exception_handling.IfArrayIndexOutOfBoundsException"); 
			Files.readAllLines(imageFile.toPath()); 
		}
//		catch(ClassNotFoundException cnfe){ //cnfe : 대문자만 골라서 적어주기
//			String message = cnfe.getMessage();
//			System.out.println(message);
//			
//			//아주 상세한 예외 목록(호출 스택)
//			cnfe.printStackTrace();
//		}
//		catch(IOException ioe) {
//			String message = ioe.getMessage(); 
//			System.out.println(message);
//			
//			//아주 상세한 예외 목록(호출 스택)
//			ioe.printStackTrace();
//		}
		
		//catch를 1개만 쓰는 방법 (쓰고봤더니 에러를 같은 방식으로 처리를 할 경우 아래와 같이 씀)
		catch(ClassNotFoundException | IOException ex){
			String message = ex.getMessage();
			System.out.println(message);
			
			//아주 상세한 예외 목록(호출 스택)
			ex.printStackTrace();
		}
	}
}

 

 

catch블록 안에 써야하는 예외 종류 찾는 방법 

1. ctrl + 단어(forName)클릭해서 확인

 

 

 

 

 

 

2. class.forName 치고 ctrl + space 해서 확인

error : jvm이 자체적으로 발생시키는 버그 (계속 같은에러 발생하면 자바 지우고 다시설치 해야됨)

exception : 우리가 try~catch, if 등으로 처리 가능

 

 


 

throw

- 예외를 발생시킴, 예외가 던져짐 (예외가 발생한 역순으로, 예외발생코드 위에서부터 아래로, 쿼리스택의 역순으로 예외를 던짐. 마지막에는 jvm으로 던져짐)

- 메소드 정의할 때 throws + 던지는 예외명 반드시 작성

- Exception type이 던져질때는 throw가 필수! (나머지는 throw 필수 아님)

Exception in tread "main"~ : 감싸두었던 예외

실제에러 : caused by~ 라인부터

 

- 일반적인 케이스에서는 finally 쓰지 않음 -> file, db에서 많이 사용함

 

실무에서 자주 사용하는 런타임 예외 처리 방법 예제
public class TryCatchExam {

	//Exception type이 던져질때는 throw가 필수!!!
	public static int convertToInt(String str) throws Exception { 
		try {
			int number = Integer.parseInt(str);
			return number;
		}
		catch(NumberFormatException nfe) {
			//Exception exception = new Exception( str + "는 숫자로 변환할 수 없습니다." );
			// Exception대신 RuntimeException으로 작성하면, Exception와 다르게 에러가 나오지 않음 : 예외를 변환시켜 던졌기 때문
			
            Exception exception = new Exception( 
										str + "는 숫자로 변환할 수 없습니다.", nfe); 
			//,nfe : NumberformatException을 RuntimeException으로 감싸서 예외를 던진것
            
			//throw : 예외를 발생시킴 (예외가 던져짐, jvm쪽으로. 즉, 호출한 메인코드로 던짐)
			throw exception; // 즉시 예외를 던지고 메소드를 종료시킨다. throw 아래 다른 코드를 작성해도 실행안됨(dead code)
		}		
        
		// throw를 하던말던, return을 하던말던 finally문은 언제나 반드시 실행 됨 (실제론, thorw 하기전에 잠깐멈추고 finally하고 throw 함)
		finally {
			System.out.println("변환이 완료되었습니다.");
		}
	}
	
	public static void main(String[] args) {
		
		try {
			int num = convertToInt("AAA"); //exception타입의 예외를 받으므로 반드시 try~catch문 작성해줘야됨(안쓰면 컴파일자체가 안됨)
		}
		catch(Exception ex) {
			System.out.println(ex.getMessage()); //"AAA는 숫자로 변환할 수 없습니다."
		}
    }
}

 

* 나를 호출하는 얘에게 예외위임(try-catch)하는 방법은 지양할것 *

public static List<String> readFile(File path) throws IOException { 
	return Files.readAllLines(path.toPath()); //File을 toPath로 변환시켜 진행 -> 이게 던지는 예외 : IOException
}