Java Syntax - (14) 예외사항

가빈·2023년 12월 21일
post-thumbnail

이번챕터는 스레드와 입출력에 관한 내용도 있으므로 완강 후에 다시 보자

Exception(예외) VS Error

예외 : 연산오류, 포맷오류등으로 개발자가 해결 가능한 오류
에러 : JVM 자체의 오류로 개발자가 해결할 수 없는 오류

예외

*checked => 문법을 체크한다는 의미 = 예외처리 필수

일반 예외(checked exception)

: 예외 클래스에서 바로 상속받은 것

  • 예외처리를 반드시 해야하고 하지 않으면 컴파일 자체가 불가능함
오류사항예시예외발생명설명
Thread.sleep(1000);InterruptedExceptionthread 실행 중 interrupt 발생가능
class.forName("java.lang.Object");ClassNotFoundExceptionclass가 없는 경우 예외발생가능
isr.read();IOException입출력 수행시 예외 발생
new FileInputStream("text.txt")FileNotFoundException파일이 없을 경우 발생가능
b1.clone();CloneNotSupportedException복제기능(클론)이 안되는 클래스가 있을때 복제가 안되는 경우 발생

실행 예외

: 예외클래스에서 상속받은 RuntimeException 클래스에서 상속받은 것

  • 예외 처리를 하지 않아도 컴파일 가능 but 예외 발생시, 프로그램종료
오류사항예시예외발생명설명
(3/0);ArithmeticException분모가 0인 연산불가인 경우 발생
(B)a;ClassCastException클래스 캐스팅이 불가능한 경우 발생
a[3];ArrayIndexOutOfBoundException입출력할 수 없는 배열출력의 경우 발생
Integer.parseInt("10!");NumberFormatException숫자가 아닌 것을 숫자로 바꿀 경우 발생
Sys~(a.charAt(2))⭐️NullPointerException객체 생성없이 멤버를 사용할 경우, 발생(static제외)



예외처리

: 일반예외와 실행예외 모두 예외처리를 통해서 정상실행 가능하게 하는 것

문법

: try, catch, finally만 기억하면 된다

try{
	//예외 발생가능 코드
    //일반예외or실행예외 발생가능코드
}
catch(예외타입(클래스명) 참조변수명){
	//해당 예외가 발생한 경우 처리블록
}
finally{
	//예외 발생여부와 상관없이 무조건 실행블록
}

위에서 ArithmeticException으로 예시

try{
	System.out.println(3/0); //에외가 발생한만한 것들
}
catch(ArithmeticException e){
	System.out.pritnln("0으로 나눌 수 없습니다.");
    //예외발생하면 실행, 정상이면 실행x
}
finally{
	System.out.println("프로그램 종료");
    System.out.exit(0); //무조건 진행
}

예외처리 프로세스

  1. try{}에서 예외가 발생-->JVM에게 전달

  2. JVM은 발생한 예외클래스에 대한 객체를 생성
    -> ArithmeticException e = new ArithmeticException();
    ❗️❗️catch()를 호출해주는 개념일 뿐, _실제 메서드 아님

  3. 객체를 받을 수 있는 catch{}로 전달
    ❗️객체를 받을 수 있는 catch블록이 없는 경우, 예외처리되지 않음

다중 예외처리

처리가 서로 다른 경우

  • catch블럭을 여러개 사용하면 된다 (처리 방법블록이니까)
  • try와 finally는 한번만 사용가능
  • if-else구문처럼 위에서부터 확인
try{
	System.out.println(3/0);
    int a= Integer.parseInt("20A");
    //숫자로 바꿔주는 부분에서 예외처리대상
}
catch(ArithmeticException e){
	System.out.pritnln("0으로 나눌 수 없습니다.");
}
catch(NumverFomatException e){
	System.out.println("숫자로 변환할 수 없습니다.");
    //예외처리방법 추가
}
finally{
	System.out.println("프로그램 종료");
    System.out.exit(0); //무조건 진행
}

처리가 서로 같은 경우

: or(|)로 연결한다

try{
	//예외 발생가능 코드
    //일반예외or실행예외 발생가능코드
}
catch(예외타입A | 예외타입 B 참조변수명){
	//해당 예외가 발생한 경우 처리블록
try{
	System.out.println(3/0);
    int a= Integer.parseInt("20A");
    //숫자로 바꿔주는 부분에서 예외처리대상
}
catch(ArithmeticException | NumverFomatException e){
	System.out.pritnln("프로그램을 종료합니다.");
}

리소스 자동해제 예외처리 (try with resource)

: 리소스를 자동을 해지할 수 있는 문법구조(JDK 1.7이후)

  • 기존 리소스 예외처리 : 복잡하고 close()를 작성해야만 콘솔객체를 끝낼 수 있음

    InputStreamReader is = null;
    try{
        is = new InputStreamReader(System.in);
        System.out.println(is.read());
    }
    catch(IOException e){
        //해당 예외가 발생한 경우 처리블록
    finally {
        if(is!=null) {
            is.close();
        }
        catch (IOException e){
            //예외처리
        }
    }
  • 개정 후 : close()를 명시적으로 없어도 존재함

    try(리소스를 사용하는 코드){ 
        //리소스를 사용하지 않는 예외 발생가능코드
    }
    catch(예외타입(클래스이름) 참조변수명){
        //해당 예외가 발생한 경우 처리블록
    finally{
        //예외 여부에 상관없이 무조건 실행블록
    }
    
    try(InputStreamReader is = new InputStreamReader(system.in);) {
        System.out.println(is.read());
    }
    catch (IOException e) {
        //예외처리
    }

    -> 원래라면 try에 리소스를 사용하는 코드들은 close메서드(___.close())반드시 포함해야한다.
    -> close()가 포함되어있는지 아닌지 알 수 있는 방법은 AutoCloseable 인터페이스를 구현해야한다

system.in은 콘솔객체, close()는 콘솔을 나가는 메서드
AutoCloseable 인터페이스 내에는 abstract close()메서드가 있기 때문이다




예외(Exception)의 전가(throws)

: 예외처리를 자신이 아닌 호출한 상위위치에서 예외처리 (책임)전가
메서드이름(..)throws 예외클래스타입

  • 메서드가 스스로 예외를 처리한 경우
    -> bcd()안에 예외처리가 다 되어있으므로 abc()에서 bcd()를 호출시, 아무런 제약조건이 없다

    void abc(...){
    	bcd();
    }
    void bcd() {
    	try{
      	//예외처리 가능 블록;
      }
      catch(예외클래스타입 참조변수){
      	//예외처리
      }
    }
    	```
  • 메서드가 자신을 호출한 다른 메서드에 예외를 전가한 경우
    -> bcd()가 자기를 호출한 메서드 abc()에서 예외를 처리하도록함

    void abc(...){
    	try{
      	bcd();
      }
      catch(예외클래스타입 참조변수) {
      	//예외처리
      }
    }
    void bcd(..) throws 예외클래스타입 {
    	//예외가능블록
    }

일반예외일때, 예외처리(try-catch)가 필요했던 이유

-> 해당예외타입을 전가하는 메서드가 포함되어있기 때문이다

  • ex) Thread.sleep()에서 sleep()메서드가 해당예외처리 타입(InterruptedException)을 전가하는 메서드이기 때문에 sleep()을 호출한 상위위치에서는 try-catch구문을 써야한다.

    void abc(..){
    	try{
      	Thread.sleep(1000);
      }
      catch(InterruptedException e) {
      	//예외처리부분
      }
    }

계속 전가하게 된다면???

  1. JVM에서 가장 먼저 실행되는 메서드는 main()
    그다음에 차례대로 abc(),bcd() ... 호출하게 된다.
  2. efg()에서 예외처리를 전가하고 계속해서 전가하다보면, JVM이 예외처리를 해야한다
  3. JVM : 예외의 원인 출력 + 그냥 프로그램 종료함

다중예외처리에 대한 다중전가

똑같다 멀티 catch 구문을 쓰면 된다

void abc() {
	try{
    	bcd();
    }
    catch(ClassNotFoundException e) {
    	//예외처리
    }
    catch(InterruptedException e) {
    	//예외처리
    }
}
void bcd()throws ClassNotFoundException, InterruptedException {
	Class cls = class.forName("java.lang.object");
    Thread.sleep(1000);
}


예외클래스 사용자 정의

예외클래스 직접 상속

❗️무조건 생성자를 2개 지정해야한다

  • 일반 예외 : exception 상속
    class MyException extends Exception {
        MyException(){//일반생성자
        }
        MyException(String s){
        //문자열 생성자
        //s에 예외메세지를 저장한다
            super(s);//부모 생성자 호출
        }
    }
  • 실행 예외 : exception 클래스 내에 runtimeException 상속
    class MyRTException extends RuntimeException {
        MyRTException(){//일반생성자
        }
        MyRTException(String s){
        //문자열 생성자
        //s에 예외메세지를 저장한다
            super(s);//부모 생성자 호출
        }
    }

작성 & 발생방법

객체 생성

  • 일반예외
    MyException me1 = new MyException();
    MyException me2 = new MyException("예외메세지");
  • 실행예외
      MyRTException mre1 = new MyRTException();
      MyRTException mre2 = new MyRTException("예외메세지");

⭐️예외발생시키기

JVM에게 throw함 !철자주의

  • 일반예외: 예외처리하지 않으면 오류발생

        throw me1;
        throw me2;
    
        throw new MyException();
        throw new MyException("예외메세지");
  • 실행예외 : 처리 안 해도 오류발생 안 함

        throw mre1;
        throw mre2;
    
        throw new MyRTException();
        throw new MyRTException("예외메세지");

예외클래스의 대표 메서드

  • 모든 예외클래스는 Throwable 클래스를 상속
  • getMessage(), printStackTrace()는 throwable클래스의 메서드임

String getMessage()

: 예외 메세지. 예외 발생 시, 생성자로 넘긴 메시지를 출력

// 예외 객체 생성시 메세지를 전달하지 않는 경우
try{
	throw new Exception();
}
catch(Exception e){
	System.out.println(e.getMessage()); 
    //null -> 전달할 메세지가 없다
}

// 메세지를 전달하는 경우
try{
	throw new Exception("예외 메세지");
}
catch(Exception e){
	System.out.pritnln(e.getMessage());
    //예외 메세지
}

void printStackTrace()

: 예외 발생이 이루어지는 경로. 호출순서를 출력

class A{
	void abc() throws NumberFormatException {
    	bcd();
    }
    void bcd() throws NumberFormatException {
    	cde();
    }
    void cde() throws NumberFormatException {
    	int num = Integer.parseInt("10A");
    }
    //abc->bcd->cde cde가 예외처리 진행
}
public static void main(String[] args) {
//객체 생성
A a = new A();
// 메서드 호출 + 예외처리
try {
	a. abc;
}
catch(NumberFormatException e) {
	e.printStackTrace();
    //JVM에게서 전달받은 객체(e)의 경로를 출력한다
}
}
profile
지금부터 시작!

0개의 댓글