오늘의하루

[JAVA] 예외처리 본문

JAVA

[JAVA] 예외처리

오늘의하루_master 2022. 8. 3. 23:04
반응형

1. 에러의 종류와 정의

  1. 컴파일 에러(compile-time error) : 컴파일할 때 발생하는 에러 (고치기 전까지는 실행 불가)
    • 컴파일러가 하는 일
      • 구문 체크
      • 번역
      • 최적화
      • 생략된 코드 추가 (예시 : 생성자 super)
  2. 런타임 에러 : 실행 시 발생하는 에러 (런타임 에러 발생 시 프로그램 비정상 종료)
    • 에러(Error) : 실행 중 발생할 수 있는 심각한 오류
    • 예외(Exception) : 실행 중 발생할 수 있는 미약한 오류
      • 예외처리(try - catch)가 가능하다.
        • 프로그램의 비정상 종료를 막고 정상적인 실행상태를 유지하는 것
      • 예외(Exception)의 종류와 구분
        • Exception과 Exception의 자식 클래스들 (예외 처리 필수)
          • 프로그램 외적인 요인으로 발생하는 예외 
            • IOException : 입출력 예외
            • ClassNotFoundException : 클래스가 존재하지 않았을 때 발생하는 예외(*. class)
            • ... 등등
        • RuntimeException과 RuntimeException의 자식 클래스들 (예외 처리 선택)
          • 프로그래머의 실수로 발생하는 예외
            • ArithmeticException : 산술 계산 예외(예시 : 5/0)
            • ClassCastException : 형 변환 예외
            • NullPointerException : null포인트(예시 : String str = null; str.length;)
            • ArrayIndexOutOfBoundsException : 배열 범위 벗어났을 때 발생하는 예외
            • ... 등등
  3. 논리적 에러 : 작성 의도와 다르게 작동

2. 예외처리 구문 (try - catch)

try{
    // 예외가 발생할 가능성이 있는 문장
}catch(Exception1 e1){
    // Exception1이 발생하는 경우, 이를 처리하기 위한 문장
}catch(Exception2 e2){
    // Exception2이 발생하는 경우, 이를 처리하기 위한 문장
}
...
}catch(ExceptionN eN){
    // ExceptionN이 발생하는 경우, 이를 처리하기 위한 문장
}
  • try블록 내에서 예외가 발생한 경우
    • 발생한 예외와 일치하는 catch블록이 있는지 확인한다.
      • 일치하는 catch블록을 찾게 되면 try문은 종료가 되고 해당 catch블록 내의 문장을 수행하고 전체 try-catch문을 빠져나옵니다.
      • 일치하는 catch블록이 없다면 예외처리가 되지 못해서 프로그램이 강제 종료된다.
  • try블록 내에서 예외가 발생하지 않은 경우
    • catch블록을 거치지 않고 전체 try-catch문을 빠져나옵니다.
class T{
    System.out.println(1);
    System.out.println(2);
    try{
        System.out.println(3);
        System.out.println(5/0); // 💥ArithmeticException 예외발생💥
        System.out.println(4);
    }catch(ArithmeticException ae){
        System.out.println(5);
    }catch(Exception e){
        System.out.println(6);
    }
    System.out.println(7);
}
// ⭐결과 : 1 2 3 5 7

2-1. 멀티 catch블록

catch블록 내용이 같은 catch블록을 하나로 합쳐서 코드를 간결하게 만든다.

  • 부모 자식 관계는 사용할 수 없다.
    • 이유는 부모만 있어도 자식의 예외까지 처리가 가능하기 때문이다.
  • 어떤 객체가 들어올지 모르기 때문에 공통된 멤버만 사용이 가능하다.
class T{
    System.out.println(1);
    try{
        System.out.println(5/0); // 💥예외발생
    }catch(ArithmeticException | ClassCastException e){ // 멀티 catch블럭
        System.out.println("내용이 같아요");
    }
}

 

2-2. 예외 발생시키기

  1. 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만든다.
    • Exception e = new Exception("예외 발생시키는 객체 생성");
  2. 키워드 throw를 이용해서 예외를 발생시킨다.
    • throw e;
class T{
    try{
        Exception e = new Exception("예외 객체 생성");
        throw e; // 강제로 예외 발생
        // throw new Exception("예외 객체 생성") >> 위에 두줄을 한줄로 줄여쓸 수 있다.
    }catch(Exception e){
        System.out.println("에러페시지 : " + e.getMessage());
        e.printStackTrace();
    }
    System.out.println("프로그램이 정상적으로 종료되었습니다.");
}
  • printStackTrace()
    • 예외 발생 당시의 호출 스택에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다.
    • 참조 변수명. printStackTrace()
  • getMessage()
    • 발생한 예외 클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.
    • 참조 변수명. getMessage()

코드 실행 중 예외가 발생하면 예외 객체가 자동 생성되며 예외 객체에는 예외에 대한 정보들이 들어있다.

2-2-1. checked 예외, unchecked 예외

  • checked 예외 : 컴파일러가 예외 처리 여부를 체크하기 때문에 예외처리 필수
    • Exception과 Exception 자식 클래스들
class T{
    try{
        throw new Exception("checked 예외");
    }catch(Exception e){
        System.out.println("Exception이 발생하였습니다.");
    }
}
  • unchecked 예외 : 컴파일러가 예외 처리 여부를 체크하지 않기 때문에 예외처리 선택
    • RuntimeException과 RuntimeException 자식 클래스들
class T{
    throw new RuntimeException("unchecked 예외");
    // 컴파일 성공
    // 실행시 런타임에러 발생하여 프로그램 비정상 종료
    // ⭐ 비정상 종료를 막기 위해서는 try-catch문을 작성하면 된다.
}

3. 예외 선언하기 (메서드)

  • 예외 선언은 메서드가 호출 시 발생 가능한 예외를 호출하는 쪽에 전달하는 것이다.
  • 호출하는 쪽은 예외 발생을 대비해서 try-catch문을 작성해줘야 한다.
public class MyClass {
    public static void main(String args[]) {
        method1(); // 1번 method1 호출 6번 💥예외전달 받음💥
        // 예외처리 안되어 있기 때문에 비정상 종료
    }
    static void method1() throws Exception{
        method2(); // 2번 method2 호출 5번 💥예외전달 받음💥 호출한 곳으로 💥예외전달💥
    }
    static void method2() throws Exception{
        throw new Exception(); // 💥3번 예외발생💥 4번 호출한 곳으로 💥예외전달💥
    }
}
  • 메서드 예외 선언하는 방법
    • void method() throws Exception1, Exception2... {메서드 내용}
  • 예외 선언은 checked 예외만 적는 게 정석적인 방법이다.
public static void main(String args[]) {
    try{
        String s = "";
        method(s); // 💥Exception 예외 발생!
        System.out.println(s);
    }catch(Exception e){
        System.out.println(e.getMessage());
    }
}
    static String method(String name) throws Exception{ // 예외 선언
        if (name == ""){
            throw new Exception("예외 선언하기"); // 예외 발생 
        }
        String str = name;
        return str;
    }
}

3-1. 예외 되던지기 (Re throwing)

  • 예외를 처리한 후에 다시 예외를 생성해서 호출한 메서드로 전달하는 것
  • 예외가 발생한 메서드와 호출한 메서드 양쪽에서 예외를 처리해야 하는 경우에 사용
public class MyClass {
    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; // Re throwing
        }
    }
}

4. finally 블록

  • 예외의 발생 여부와 관계없이 실행되어야 하는 코드를 작성한다.
  • 선택적으로 사용이 가능하며 try - catch - finally의 순서로 구성된다.
  • 예외 발생 시 : try - catch - finally 순서로 실행된다.
  • 예외 미발생시 : try - finally 순서로 실행된다.
  • try 또는 catch블록에서 return문을 만나도 finally블록은 무조건 수행된다.
class T{
    try{
        System.out.println(1);
        System.out.println(5/0);
    }catch(ArithmeticException ae){
        ae.printStackTrace();
    }finally{
        System.out.println("hi~ im finally");
    }
    System.out.println(2);
}
// 결과 : 1 hi~ im finally 2

5. 사용자 정의 예외 만들기

  • 기존의 예외 클래스를 상속받아서 새로운 예외 클래스를 정의할 수 있다.
public static void main(String args[]) {
    MyException me = new MyException("에러지롱");
    try{
        throw me;
    }catch(Exception e){
        System.out.println(e.getMessage()); // 에러지롱
    }
}

class MyException extends Exception{
    MyException(String msg){
        super(msg);
    }
}
  • 원래는 없는 에러코드를 추가한 예외 클래스를 정의할 수 있다.
public static void main(String args[]) {
    MyException me1 = new MyException("에러1",100);
    MyException me2 = new MyException("에러2");
    MyException me3 = new MyException();
    System.out.println(me1.getErr());
    System.out.println(me2.getErr());
    System.out.println(me3.getErr());
}

class MyException extends Exception{
    private final int ERR_CODE;
    
    MyException(){
        this("에러이름 미지정",500);
    }
    MyException(String msg){
        this(msg,404);
    }
    MyException(String msg, int ERR_CODE){
        super(msg);
        this.ERR_CODE = ERR_CODE;
    }
    
    public String getErr(){
        return "Error = " + this.getMessage() + " Error_code = " + ERR_CODE;
    }
}

 

6. 연결된 예외

  • 한 예외가 다른 예외를 발생시킬 수 있다.
  • 예외 A가 예외 B를 발생시키면 A는 B의 원인 예외이다.
Throwable initCause(Throwable cause) 지정한 예외를 원인 예외로 등록
Throwable getCause() 원인 예외를 반환
// 메서드들이 다 정의 되있다는 가정하에 예제 진행

void install() throws InstallException{ // install() 호출
    try{
        startInstall(); // SpaceException 발생
    }catch (SpaceException se){ // 예외처리
        InstallException ie = new InstallException("연결된 예외를 만들기 위해 생성");
        ie.initCause(se); // InstallException의 원인으로 SpaceException 등록
        throw ie; // 호출한곳으로 ie 전달
    }
}
  • 여러 예외를 하나로 묶어서 다루기 위해 사용된다.
  • checked 예외를 unchecked 예외로 변경하려 할 때 사용된다.
static void T() throws SpaceException, MemoryException{
    if (!enoughSpace()){
        throw new SpaceException("checked 예외");
    }
    if (!enoughMemory()){
        throw new MemoryException("checked 예외");
    }
}

static void T(){
    if (!enoughSpace()){
        RuntimeException re = new RuntimeException();
        SpaceException se = new SpaceException("checked 예외");
        re.init(se);
        throw re;
        
    }
    if (!enoughMemory()){
        throw new RuntimeException(new MemoryException("checked 예외"));
        // RuntimeException의 원인으로 MemoryException을 지정했다. (생성자 사용)
        
        // 아래도 RuntimeException의 원인으로 MemoryException을 지정한 것이다.
        // RuntimeException re = new RuntimeException();
        // MemoryException me = new MemoryException();
        
        // re.initCause(new MemoryException("cheked 예외"));
        // throw re;
        
        // re.initCause(me);
        // throw re;
    }
}
반응형
Comments