티스토리 뷰

728x90

서문



자바의 정석 기초편 챕터 8편을 기재합니다.
목적은 공부한 내용을 기록하는 것에 있기 때문에 완전한 문장이 아닐 수도 있습니다.
또한 모든 내용을 적은 것은 아닙니다.









자바의 정석 ( ch.8 )



프로그램 오류


  • 컴파일 에러(Compile-Time Error) : 컴파일 할 때 발생하는 에러 ( 수정 전까지 프로그램 실행 자체가 불가)

    • 컴파일러
      • 구문체크
      • 번역
      • 최적화 (간단한 계산이나 컴파일, 실행시점에 동일한 처리들)


  • 런타임 에러(Runtime Error) : 실행 할 때 발생하는 에러(프로그램이 종료됨)

    • index out of bound, NullPoint 등등


  • 논리적 에러(Logical Error) : 작성의도와 다르게 동작하는 에러(프로그램 종료는 되지 않음)

    • 재고량이 음수가 나오면 안되는데 음수가 나와버리는 경우

  • Java의 런타임에러

    • 에러(Error) : 프로그램 코드에 의해서 수습될 수 없는 심각한 오류,
    • 예외(Exception) : 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류, 처리 가능(프로그램 종료를 막을 수 있음)

  • 예외처리의 정의와 목적


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







  • Exception은 다시 RuntimeException과 그 외의 그룹으로 나눌 수 있음






  • IOException : 입출력 에러
  • ClassNotFoundException : 클래스를 찾을 수 없을 때
  • ArithmeticException : 산술 에러, 5/0
  • ClassCastException : 형변환 에러
  • NullPointException: nullpoint 에러
  • IndexOutOfBoundsException : index 범위를 벗어나는 에러
  • ...

class ExceptionTest{
  public static void main(String[] args){
    system.out.println("에러!!"); // complie error
    System.out.println(args[0]); // Runtime error, args가 없는데 사용하려고 해서

  }
}


예외처리하기 try-catch문


  • try블럭 내에서 예외가 발생할 경우

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

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

1. try-catch문의 기본적 구조

try{
  // 예외가 발생할 가능성이 있는 문장을 넣음
} catch (Exception e1){
  // Exception e1가 발생했을 경우 처리할 문장
} catch (Exception e2){
  // Exception e2가 발생했을 경우 처리할 문장
} catch (Exception eN){
  // Exception eN가 발생했을 경우 처리할 문장
}

-----------------------------------------

2. try-catch문의 예시 1

class Ex{
  public static void main(String[] args){
    System.out.println(1);
    try{
      System.out.println(2);
      System.out.println(3);
    } catch (Exception e){
      System.out.println(4); // 예외
    } // try-catch문 종료
    System.out.println(5); 
  }
}



예외가 발생하지 않은 경우

> 1
> 2
> 3
> 5


예외가 발생한 경우

> 1
> 2
> 3
> 4
> 5

-----------------------------------------

3. try-catch문의 예시 2

class Ex2{
  public static void main(String[] args){
    System.out.println(1);
    try{

      System.out.println(0/0); // 예외발생
      System.out.println(2);
    } catch (Exception e){
      System.out.println(3);
    }
    System.out.println(4);
  }
}


> 1
> 3
> 4

-----------------------------------------

4. try-catch문의 예시 3

class Ex3{
  public static void main(String[] args){
    System.out.println(1);
    System.out.println(2);
    try{
      System.out.println(3);
      System.out.println(0/0); // error
      System.out.println(4);
    } catch(ArithmeticException e){
      if (e instanceof ArithmeticException){
        System.out.println("true");
      }
      System.out.println("ArithmeticException");
    } catch(Exception e){  // 모든 Exception의 부모격이기 때문에 가장 마지막에 Exception을 사용함
      System.out.println("Exception");
    }
    System.out.println(6);
  }
}


> 1
> 2
> 3
> true
> ArithmeticException
> 6


printStackTrace()와 getMessage()


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

1. printStackTrace()와 getMessage() 기본적 예시

try{
  ...
  System.out.println(0/0);
  ...
} catch(ArithmeticException ae){ // ae는 참조변수, 해당하는 에러에 예외정보가 담겨 있는데 만약 catch()괄호 안에 일치하는 에러가 있을 때 참조하여 printStackTrace와 getMessage를 사용할 수 있음
  ae.printStackTrace();
  System.out.println(aa.getMessage());
} catch(Exception e){
  ...
}


> java.lang.ArithmeticException: / by zero
    at MyClass.main(MyClass.java:5)
> / by zero

---------------------------------------------

2. 멀티 try-catch 문 예시
- 멀티 try-catch문은 내용이 같은 catch블럭을 하나로 만들어 주는 것

try {
  ...
} catch(ExceptionA ae){
  ae.printStackTrace();
} catch(ExceptionB be){
  be.printStackTrace();
}


try{
  ...
} catch (ExceptionA | ExceptionB e){
  e.printStackTrace();
}

--------------------------

// 부모자식관계의 경우 부모만 잡아도 ok

try{
  ...
// } catch (ParentException pe | ChildException ce)
} catch (ParentException pe){
  pe.printStackTrace();
}

--------------------------

// 멀티 케치문을 사용할 때 특정 에러의 메서드를 사용하려면 instanceof로 확인하여 형변환해서 사용




try{
  ...
} catch (ExceptionA | ExceptionB e){
  e.methodA(); // error, ExceptionA, ExceptionB 둘 중 하나에 의해 에러가 잡힌 것이기 때문에 특정 에러의 메서드 호출 불가

  if (e instanceof ExceptionA){
    ExceptionA e1 = (ExceptionA) e;
    e.methodA(); // 이건 가능
  } else {
    ...
  }
}


예외 발생시키기

  • 연산자 new를 이용하여 발생시키려는 예외 클래스의 객체를 생성

    • Exception e = new Exception("예외발생");
  • 키워드 throw를 이용해서 예외를 발생시킴

    • throw e;
1. 예외 발생시키기 예시

class Ex{
  public static void main(String[] args){
    try{
      Exception e = new Exception("고의로 예외 발생시킴");
      throw e; // 예외를 발생시킴, 예외를 던짐
    }catch(Exception e){ // 예외를 잡음, 잡아서 처리

      System.out.println("에러 메시지 : " + e.getMessage());
      e.printStaceTrace();
    }
    System.out.println("프로그램이 종료되었습니다.!!");
  }

}

> 에러 메시지 : 고의로 예외 발생시킴
> 프로그램이 종료되었습니다.!!

> java.lang.Exception: 고의로 예외 발생시킴
    at MyClass.main(MyClass.java:5)


checked예외, uncheckede예외


  • checked예외 : 컴파일러가 예외 처리 여부를 체크(예외 처리 필수)

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

    • RuntimeException과 그 자손
  • 이유:

    • 만약 RuntimeException을 필수로 처리해주어야 한다면, 거의 모든 구문에 try-catch문을 사용해야 하기 때문에
1. checked 예외 발생 예시 ( 필수적 )

// 예외를 발생시켰는데 try-catch문으로 처리해주지 않으면 컴파일 에러
class Ex{
  public static void main(String[] args){
    throw new Exception("고의로 예외발생");
  }
}

> MyClass.java:4: error: unreported exception Exception; must be caught or declared to be thrown
    throw new Exception("고의로 예외발생");
    ^
  1 error


-------------------------------------------

2. unchecked 예외 발생 예시 ( 선택적 )

class Ex2{
  public static void main(String[] args){
    throw new RuntimeException("고의로 예외발생");
  }
}

> Exception in thread "main" java.lang.RuntimeException: 고의로 예외발생
    at MyClass.main(MyClass.java:4)


메서드에 예외 선언하기

  • 예외 처리하는 방법 : try-catch문(직접처리), 예외 선언하기(예외 떠넘기기)

  • 메서드가 호출 시 발생가능한 예외를 호출하는 쪽에 알리는 것

  • 오버라이딩 조건

    • 선언부일치
    • 접근제어자가 조상보다 좁으면 x
    • 조상보다 예외선언이 많으면 x (Exception은 모든 예외의 조상이기 때문에 가장 큰 범위이자 많은 선언이라고 할 수 있음)
  • throw로 던져진 Exception은 누군가는 처리해야 함

1. 메서드에 예외 선언하기 예시

void method() throws Exception1, Exception2, ... , ExceptionN{// 필수 처리 예외를 우선으로 적음, 선택예외는 안적는 걸 권장
  // 메서드 내용
}

void method2() throws Exception{// 모든 종류의 예외 발생 가능

}

static void startInstall() throws SpaceException, MemoryException{
  // 호출한 메서드에 Exception을 알려주기
  if (!enoughSpace()){
    throw new SpaceException("설치할 공간이 부족합니다.");
  } else if (!enoughMemory()){
    throw new MemoryException("충분한 메모리가 없습니다.");
  }

}

----------------------------------------------

2. 메서드에 예외 선언하기 예시 2

class Ex{
  public static void main(String[] args) throws Exception{
    method1();
  }

  static void method1() throws Exception{
    method2();
  }

  static void method2() throws Exception{
    throw new Exception("예외발생 - method2()");
  }
}


> Exception in thread "main" java.lang.Exception
    at MyClass.method2(MyClass.java:11)
    at MyClass.method1(MyClass.java:7)
    at MyClass.main(MyClass.java:3)


------------------------------------------------

3. 메서드에 예외 선언하기 예시 3

import java.io.*;

class Ex3{
  public static void main(String[] args){
    try{
      File f = createFile(args[0]);
      System.out.println(f.getName() + "파일이 성공적으로 생성되었습니다.");
    } catch( Exception e){
      System.out.println(e.getMessage() + " 다시 입력해주시기 바랍니다.");
    }
  }

  static File createFile(String fileName) throws Exception{
    if (fileName == null || fileName.equals("")){
      throw new Exception("파일이름이 유효하지 않습니다.");
    }
    File f = new File(fileName);
    f.createNewFile();
    return f;
  }

}

> cmd args : testFileName
> testFileName파일이 성공적으로 생성되었습니다.

> cmd args : 
> Index 0 out of bounds for length 0 다시 입력해주시기 바랍니다.


finally 블럭

  • 예외 발생 여부와 상관없이 수행되어야 하는 코드를 넣는 블럭
1. finally 구문의 기본 구조

try{
  // 예외가 발생할 가능성이 있는 코드
}catch(Exception e){
  // 예외가 발생했을 때 처리할 코드
}finally{
  // 예외 발생 여부와 상관없이 마지막에 실행되는 코드
}

참고 : try 블럭 안에 return문이 있어서 try블럭을 벗어나는 경우에도 finally 블럭은 실행된다.

-----------------------------------------

2. finally 구문의 예시

try{
  startInstall();
  copyFile();
  deleteTempFiles(); // 예외가 발생하지 않아도 실행
} catch(Exception e){
  e.printStackTrace();
  deleteTempFiles(); // 예외가 발생해도 실행
}

try{
  startInstall();
  copyFile();
} catch (Exception e){
  e.printStackTrace();
} finally {
  deleteTempFiles(); // 예외 발생 여부와 상관없이 실행되어야 하는 코드는 finally구문으로 처리
}


사용자 정의 예외 만들기

  • 사용자가 직접 예외를 만들 수 있음
  • 조상은 Exception과 RuntimeException중에서 선택
    • 만약 Exception으로 처리하면 필수 예외처리를 함
    • 만약 RuntimeException으로 처리하면 선택 예외처리를 함

1. 사용자 정의 예외 만들기 예시 1

class MyExceptionClass extends Exception{
  MyException(String msg){ // 매개변수로 message를 받는다.
    super(msg); // 조상인 Exception클래스의 생성자를 호출
  }
}

-------------------------------------

2. 사용자 정의 예외 만들기 예시 2

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);
  }

  public int getErrCode(){
    return ERR_CODE;
  }
}


예외 되던지기 (Exception re-throwing)

  • 예외를 처리한 후에 다시 예외를 발생시키는 것
  • 호출한 메서드와 호출된 메서드 양쪽 모두에서 예외처리를 하는 것
  • 분담처리를 하기 위해서 사용, 상황에 맞게
1. 예외 되던지기 예시, 예외를 method1에서 받고 처리한 후 다시 던져서 main에서 또 처리

class Ex1{
  public static void main(String[] args){
    try{
      method1();
    } catch(Exception e){
      System.out.println("main메서드에서 예외를 처리했습니다.");
    }
  }

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


> method1메서드에서 예외가 처리되었습니다.
> main메서드에서 예외를 처리했습니다.


연결된 예외(chained exception)

  • 한 예외가 다른 예외를 발생시키는 것

  • 예외 A가 예외 B를 발생시키면, 예외 A는 원인예외(cause exception)이라고 함

  • 이유:

    • 여러 예외를 하나로 묶어서 다룰 때
    • checked예외를 unchecked 예외로 변경할 떄
      • Exception을 RuntimeException으로

1. 연결된 예외 기본 구조

Throwable initCause(Throwable cause) 지정한 예외를 원인 예외로 등록
Throwable getCause() 원인 예외를 반환

public class Throwable implements Serializable{
  ...
  private Throwable cause = this; // 객체 자신을 원인 예외로 등록
  ...
  public synchronized Throwable initCause(Throwable cause){
    ...
    this.cause = cause; // 다른 예외를 등록할 수 있음
    return this;
  }
  ...
}


-----------------------------------------------

2. 연결된 예외 예시 1

void install() throws InstallException{
  try{
    startInstall();
    copyFiles();
  } catch (SpaceException se){
    InstallException ie = new InstallException("설치중 예외발생"); // 예외 생성 
    ie.initCause(se); // InstallException의 원인은 SpaceException이기 때문에 InstallException의 원인 예외로 SpaceException을 등록
    throw ie;
  } catch (MemoryException me){
    ...
  }
}

----------------------------------------------

3. 여러 예외를 하나로 묶어서 다루기 위한 예시

try{
  install();
} catch(SpaceException se){
  se.printStackTrace();
} catch(MemoryException me){
  me.printStackTrace();
} catch(Exception e){
  e.printStackTrace();
}

try{
  install();
} catch(InstallException ie){
  ie.printStackTrace();
} catch(Exception e){
  e.printStackTrace();
}

--------------------------------------------

4. checked 예외를 unchecked 예외로 변경할 때

static void startInstall() throws SpaceException,  MemoryException{ // 필수 예외 처리 선언 -> RuntimeException으로 바꾸면 선택 예외 처리 가능
  if (!enoughSpace()){
    throw new SpaceException("설치할 공간이 부족합니다.");
  }

  if (!enoughMemory()){
    throw new MemoryException("메모리가 부족합니다.");
  }
}

static void startInstall() throws MemoryException{ // 필수 예외 처리 선언 -> RuntimeException으로 바꾸면 선택 예외 처리 가능
  if (!enoughSpace()){
    throw new RuntimeException(SpaceException("설치할 공간이 부족합니다."));
  }

  if (!enoughMemory()){
    throw new MemoryException("메모리가 부족합니다.");
  }
}





  • 자바의 정석 8 챕터에서는 오류와 예외의 자세한 이론을 배웠습니다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함