[Java] 예외처리(Exception)

이용준·2022년 11월 7일
0

Java

목록 보기
26/29

프로그램을 만들다보면 다양한 오류가 발생한다.
이를 대처하기 위한 자바의 예외처리(try...cathc, throws) 방법을 알아보도록 하자

1.예외는 언제 발생하는가?

  • 존재하지 않는 파일 열기 - FileNotFoundException 예외 발생

    BufferedReader br = new BufferedReader(new  FileReader("없는파일"));
    br.readline();
    br.close();
    
    (오류구문)
    Exception in thread "main"  java.io.FileNotFoundException: test.txt (No such file or directory)
    		 at java.base/java.io.FileInputStream.open0(Native Method)
    		 at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
        ...
  • 숫자/0 - ArithmeticException 예외 발생

    int c = 4/0;
    
    (오류구문)
    Exception in thread "main" java.lang.ArithmeticException: / by zero
    		at test.main(test.java:37)
  • 배열 범위 오류 - ArrayIndexOutOfBoundsException 오류

    int [] a = {1,2,3};
    System.out.println(a[3]);
    
    (오류구문)
    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
    		at test.main(test.java:39)

2.예외 처리(try-catch)

try{
   ...
 } catch(예외1){
   ...
 } catch(예외2){
  ...
 ...
} 
  • try문내 수행할 문장들에 예외가 발생하지 않는다면 catch문 미수행
  • try문내 문장 수행 중 예외 발생 시 catch문 수행
  • 예제
     * 숫자를 0으로 나눴을때 발생하는 예외처리
     
     int c;
     try{
      c=4/0;
    } catch(AritmeticException e){ // e는 Ari~의 객체(오류객체)
      c = -1; // 예외가 발생되어 문장 수행
    }  

3.finally

  • 예외가 발생하더라도 반드시 실행해야하는 문장에 수행
  • 예 - catch문으로 미실행
    public class Sample{
      public void shouldBeRun(){
        System.out.println("ok thanks.");
      }
      
      public static void main(String[] args){
        Sample = sample = new Sample();
        int c;
        try{
          c = 4/0;
          sample.shouldBeRun(); 해당 코드 실행되지 않음
        }catch (ArithmeticException e){
          c=-1;
        }
      }
    }      
  • finally문 적용(반드시 수행)
    public class Sample{
      public void shouldBeRun(){
        System.out.println("ok bye~");
      }
      
      public static void main(String[] args){
        Sample sample = new Sample();
        int c;
        try{
          c=4/0;
        } catch (ArithmeticException e){
          c=-1;
        } finally {
          sample.shouldBeRun(); // 예외 상관없이 무조건 수행
        }
      }
    }  

4.RuntimeException과 Exception

이번에는 예외를 발생시켜보도록 한다.

class FoolException extends RuntimeException{
}

public class Sample{
  public void sayNick(String nick){
    if("fool'.equals(nick)){
      throw new FoolException(); // 에러 발생
    }
    
    public static void main(String[] args){
      Sample sample = new Sample();
      sample.sayNick("fool");
      sample.sayNick("gorgeous");
    }
  }  
  
(오류구문)
Exception in thread "main" FoolException
    at Sample.sayNick(sample.java:7)
    at Sample.main(Sample.java:14)

FoolException이 상속받은 클래스는 RuntimeException이다. Exception은 크게 두가지로 구분된다.

  • 1) RuntimeException (Unchecked Exception)

    • 실행시 발생)
    • 발생 여부 불확실할 경우 작성
  • 2) Exception (Checked Exception)

    • 컴파일시 발생
    • 발생 여부 예측 가능할 경우 작성

Exception

class FoolException extends Exception{
}

public class Sample{
  public void sayNick(String nick){
    try{
      if("fool".equals(nick)){
        throw new FoolException();
      }
      System.out.println("입력된 값은 "+nick+"입니다.");
    }catch(FoolException e){
      System.out.println("FoolException이 발생했다.");
    }
  }
  
  public static void main(String[] args){
     Sample sample = new Sample();
     sample.sayNick("fool");
     sample.sayNick("gorgeous");
   }
 }  

sayNick 메소드에서 try...catch문으로 FoolException을 처리했다.

5.예외 던지기(throws)

위 예제는 sayNick 메서드에서 FoolException을 발생과 예외 처리를 했으나, 이렇게 하지 않고 sayNick을 호출한 곳에서 FoolException을 처리하도록 예외를 위로 던질 수 있는 방법에 대해 알아보겠다.

  • 예 - 예외를 위로 던지기

    public class Sample{
      public void SayNick(String nick) throws FoolException{
        if("fool".equals(nick)){
          throws new FoolException();
        }
        System.out.println("입력된 값은 "+nick+"입니다.");
      }
      
      public static void main(String[] args){
        Sample sample = new Sample();
        sample.sayNick("fool");
        sample.sayNick("gorgeous");
      }
    }  
  • sayNick 메소드 뒷부분에 throws 구문을 사용해 FoolException을 위로 보낼 수 있다.(예외 뒤로 미루기)

  • FoolException 구문은 기존 sayNick 메소드에서 main메소드에서 처리

  • 위의 컴파일 오류 처리(main 메소드 변경)

    class FoolException extends Exception{
    }
    
    public class Sample{
      public void sayNick(String nick) throws FoolException{
        if("fool".equals(nick)){
          throw new FoolExcetpion();
        }
        System.out.println("입력된 값은 "+nick+"입니다.");
      }
      
      public static void main(String[] args){
        Sample sample = new Sample();
        try{ // 추가
          sample.sayNick("fool");
          sample.sayNick("gorgeous");
        }catch (FoolException e){
          System.out.println("FoolException 발생");
        }
      }
    }  

예외 처리 위치

위 예제를 통해 두 가지 메소드에서 예외처리를 해봤다. FoolException은 sayNick메소드에서 처리하는 것이 좋을까 main 메소드에서 처리하는 것이 좋을까? 이 두가지는 큰 차이가 있다.

  • sayNick()
    sample.sayNick("fool");     // FoolException 출력
    sample.sayNick("gorgeous"); // gorgeous 출력(수행 O)
    sample.sayNick("gorgeouse") 수행 된다.
  • main()
    try{
      sample.sayNick("fool");
      sample.sayNick("gorgeous"); // 이 문장은 수행되지 않는다.
    }catch(FoolException e){
      System.err.println("FoolException 발생);
    }

    sample.sayNick("gorgeous")는 수행되지 않음
    이미 첫 문장에서 예외가 발생해 catch문으로 빠지기 때문

6.트랜잭션

  • 트랜잭션은 하나의 작업 단위를 뜻한다.
  • 트랜잭션은 예외처리와 밀접한 관계를 갖는다.
  • 작업 단위 중 하나라도 실패시(try) / 작업을 취소한다.(catch) / 예외 처리(throws) 와 같이 사용.

쇼핑몰 운영 통한 트랜잭션 처리(예시)

쇼핑몰의 "상품 발송" 트랜잭션을 가정해보자.

  • 상품
  • 영수증 발행
  • 발송

[조건]

트랜잭션에는 다음과 같은 작업들이 있으며, 이 3가지 일들 중 하나라도 실패시 모두 취소하고 "상품발송" 전 상태로 돌린다.

아래와 같이 포장, 영수증 발행, 발송 메서드에서는 예외를 throw하고 상품발송 메서드에서 throw된 예외를 처리해 모두 취소하기

* pseudocode *

상품발송(){
  try{
    포장();
    영수증발행();
    발송();
  }catch(예외){
    모두취소();  // 하나라도 실패하면 모두 취소.
  }
}

포장() throws 예외{
  ...
}
영수증발행() throws 예외{
  ...
}
발송() throws 예외{
  ...
}
profile
뚝딱뚝딱

0개의 댓글