[Java] 예외 처리

오형상·2023년 11월 20일
0

java

목록 보기
6/7
post-thumbnail

예외 처리

예외(Exception)란?

예외(Exception)

✔ 단순한 문법 오류가 아닌 실행 중간에 발생하는 정상적이지 않은 상황 을 의미

✔ Exception과 Error는 다름

  • Exception VS Error Exception : 개발자가 구현한 로직에서 발생한 실수나 사용자의 영향에 의한 수습가능한 문제 Error : 시스템이 종료되어야 할 수준의 상황과 같이 일단 발생하면 수습할 수 없는 심각한 문제

예외처리

✔ 자바는 예외처리 매커니즘을 제공

  • 예시

    👉 line 14에서 발생한 예외
    발생한 예외 문구를 콘솔창에 띄워주는 주체 = JVM

    문제가 발생한 지점에서 프로그램을 종료시키고 해당 클래스의 어느 라인에서 어떤 에러가 발생했는지 알려줌 (자바의 기본 예외처리 매커니즘)

예외 처리 방법

1️⃣ try catch finally

💡 예제

  • 1️⃣ try~catch 문 적용 전

    public class TryCatchTest {
    
    	public static void main(String[] args) {
    		
    		int a = 1/0;  
    		System.out.println(a);
    	}
    
    }

    👉 에러가 발생 (에러 발생시키는 주체는 JVM)

  • 2️⃣ try~catch 문 적용 후

    public class TryCatchTest {
    
    	public static void main(String[] args) {
    		
    		int a = 0;  // println()에 a를 활용하기 위해 try ~ catch ~문 밖에 선언
    		try {
    			a = 1/0;
    		} catch (Exception e) {
    			
    		}
    		System.out.println("트라이캐치 밖");
    		System.out.println(a);
    	}
    
    }

    👉 프로그램이 죽지 않고 에러 없이 잘 실행됨

  • 3️⃣ catch문 활용

    public class TryCatchTest {
    
    	public static void main(String[] args) {
    		
    		int a = 1;  // println()에 a를 활용하기 위해 try ~ catch ~문 밖에 선언
    		int b = 0;
    		try {
    			b = a / b;
    			
    			System.out.println(a);
    		} catch (Exception e) {
    			
    			System.out.println("캐치" + a);
    			System.out.println("캐치" + b);
    			
    		}
    		System.out.println("try~catch~ 밖");
    	}
    
    }

    👉 try문이 아닌 catch문 내의 소스 코드 실행

  • 4️⃣ catch 문의 Exception 객체 활용하기

    public class TryCatchTest {
    
    	public static void main(String[] args) {
    		
    		int a = 1;  // println()에 a를 활용하기 위해 try ~ catch ~문 밖에 선언
    		int b = 0;  // 에러 사항 (원인)
    		try {
    			b = a / b;
    			
    			System.out.println("트라이 안" + a);
    		} catch (Exception e) {
    			
    			e.printStackTrace();
    			
    			System.out.println("캐치" + a);
    			System.out.println("캐치" + b);
    			
    		}
    		
    		System.out.println("try~catch~ 밖");
    		
    		System.out.println(a);
    	}
    
    }

    👉 디버깅을 위한 e.printStackTrace() 를 이용하여 어떤 에러가 발생하였는지 확인 가능

    👉 catch 문의 () 안에 Exception객체는 ArithmeticException객체로 대신 사용할 수 있음 (다형성)

    👉 객체를 따로 생성해주지 않아도 사용가능한 이유는 JVM이 자동으로 생성해주기 때문

  • 5️⃣ finally 활용

    public class TryCatchTest {
    
    	public static void main(String[] args) {
    		
    		int a = 1;  // println()에 a를 활용하기 위해 try ~ catch ~문 밖에 선언
    		int b = 0;  // 에러 사항 (원인)
    		try {
    			b = a / b;
    			
    			System.out.println("트라이 안" + a);
    		} catch (Exception e) {
    			
    			e.printStackTrace();
    			
    			System.out.println("캐치" + a);
    			System.out.println("캐치" + b);
    			
    		} finally {
    			System.out.println("파이널리 입니다.");
    		}
    		
    		System.out.println("try~catch~ 밖");
    		
    		System.out.println(a);
    	}
    
    }

    👉 에러와 상관없이 무조건 실행되는 코드를 finally문 안에 넣어줌

  • 6️⃣ e.getMessage()e.printStackTrace() 차이

    import java.util.Scanner;
    
    public class ExceptionCase3 {
    
    	public static void main(String[] args) {
    		Scanner kb = new Scanner(System.in);
    
    		try {
    			System.out.print("a/b... a? ");
    			int n1 = kb.nextInt();
    
    			System.out.print("a/b... b? ");
    			int n2 = kb.nextInt();
    
    			System.out.printf("%d / %d = %d \n", n1, n2, n1 / n2);
    		} catch (ArithmeticException e) {
    			
    			System.out.println("----e.getMessage()-----");
    			System.out.println(e.getMessage());  // 어떤 에러인지 메세지로 간단히 뿌려줌
    			System.out.println();
    			System.out.println("-----e.printStackTrace()------ ");
    			e.printStackTrace();
    			
    		} finally {
    			System.out.println("무조건 실행");
    		}
    		
    		System.out.println("Good bye~~!");
    	}
    
    }

  • 7️⃣ catch문을 2개 이상 사용해보기

    import java.util.InputMismatchException;
    import java.util.Scanner;
    
    public class ExceptionCase3 {
    
    	public static void main(String[] args) {
    		Scanner kb = new Scanner(System.in);
    
    		try {
    			System.out.print("a/b... a? ");
    			int n1 = kb.nextInt();
    
    			System.out.print("a/b... b? ");
    			int n2 = kb.nextInt();
    
    			System.out.printf("%d / %d = %d \n", n1, n2, n1 / n2);
    		} catch (ArithmeticException e) {
    			
    			System.out.println("----e.getMessage()-----");
    			System.out.println(e.getMessage());  // 어떤 에러인지 메세지로 간단히 뿌려줌
    			System.out.println();
    			System.out.println("-----e.printStackTrace()------ ");
    			e.printStackTrace();
    			
    		} catch (InputMismatchException e) {
    			
    			System.out.println("문자가 입력되었습니다.");
    			System.out.println(e.getMessage());
    		
    		} catch (Exception e) {  // 다형성의 원리로 위의 에러에 해당되지 않는 예외들은 모두 여기로 넘어옴
    			e.printStackTrace();
    			System.out.println(e.getMessage());
    		}finally {
    		
    		
    			System.out.println("무조건 실행");
    		}
    		
    		System.out.println("Good bye~~!");
    	}
    
    }

    ⚠ Exception을 이용한 catch문이 가장 위에 있다면 Exception으로 모든 에러를 잡아내서 그 밑의 예외 처리 코드들이 Dead Code가 되기 때문에 컴파일 에러 발생

2️⃣ throws

✔ 메서드에서 처리해야 할 하나 이상의 예외를 호출한 곳으로 전달 (처리를 위임)

👉 예외가 없어지는 것❌ 단순히 전달

👉 예외를 전달받은 메서드는 다시 예외 처리의 책임이 발생함

💡 예제

import java.io.IOException;

// throws
public class ThrowsTest {

	public static void main(String[] args) throws IOException {
		byte[] byteArr = {'a', 'b', 'c'};  // 숫자로 변환되어 배열에 저장됨
		
		System.out.write(byteArr); 
	}

}
  • System.out.write() 란?
    @Override
    public void write(byte b[]) throws IOException {
        write(b, 0, b.length);
    }
    👉 byte를 출력하거나 아스키 코드 등을 출력할 때 쓰이는 메소드

✔ write함수는 IOExceptionthrows를 이용하여 예외처리를 하였으므로
write 함수를 호출한 main() 함수에도 마찬가지로 IOException을 위한 예외처리를 해주어야 함

✔ 위의 코드처럼 main 함수에서 throws 를 이용한 예외처리를 할 경우, (main함수를 호출하는)
JVM이 예외처리를 받아 콘솔에 발생한 예외 메세지를 띄우고 프로그램을 종료하게 됨


예외 클래스 구분

예외의 종류

✔ 자바에서는 예외를 클래스를 통해 관리한다.

✔ 모든 예외 클래스는 java.lang패키지의 Exception 클래스의 상속을 받는다.

✔ 크게 두 종류로 구분할 수 있다.

  • 체크 예외(checked exception)
  • 실행 예외(runtime exception) 또는 언체크 예외 (unchecked exception)

1️⃣ 체크 예외

✔ 체크 예외는 컴파일 과정에서 예외를 검사하고 예외 처리를 하지 않으면 컴파일 오류가 발생된다.

✔ 컴파일 시 발생 가능한 예외에 대한 대부분의 처리가 가능하다.

✔ 체크 예외는 Exception 클래스를 상속받으나 RuntimeException 클래스는 상속받지 않는다.

2️⃣ 언체크 예외

✔ 언체크 예외는 컴파일 시 예외를 검사하지 않는다.

✔ 따라서 예외 처리를 하지 않아도 컴파일이 가능하다.

✔ 하지만 컴파일이 가능하다고 해서 예외처리가 필요 없는 것이 아니다.

예외 처리를 프로그래머가 해야 하는 경우

✔ 체크 예외는 개발자가 처리하지 않아도 컴파일 과정에서 처리가 가능하다.

✔ 언체크 예외는 개발자의 경험에 따라서 예외가 발생 가능한 코드에 대해서 예외 처리를 알아서 해줘야 한다.

  • 예시
    public static void main(String[] args) {
    		Path file = Paths.get("C:\\javastudy\\Simple.txt");
    		BufferedWriter writer = null;
    		try {
    			writer = Files.newBufferedWriter(file); // IOException 발생 가능
    			writer.write('A'); // IOException 발생 가능
    		} catch (IOException e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				if (writer != null) // IOException 발생 가능
    					writer.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    	}

0개의 댓글