자바 에러와 예외 처리

조용근·2024년 1월 22일

자바 정리

목록 보기
9/21

논리 에러(Logic Error) //버그

  • 프로그램이 실행하고 작동하는데는 아무런 문제가 없는 오류
  • 컴퓨터가 알려주지 않고 프로그램이 정상적으로 실행되므로 개발자가 코드를 체크할 필요가 있다.

컴파일 에러(Compillation Error) //문법 구문 오류

  • 빨간색으로 표시되는 것

런타임 에러(Runtime Error) //실행 오류

  • 프로그램 실행 중에 에러가 발생해서 잘못된 결과를 낳음 or 외부적인 요인으로 인한 프로그램의 종료

자바 프로그래밍 오류(에러(error), 예외(exception))


Throwable 클래스?
오류나 예외에 대한 메시지를 담는 것(getMessage(), printStackTrace())

  • 에러 : 프로그램 코드로는 고칠 수 없는 심각한 오류
  • 예외 : 프로그램 코드로 고칠 수 있는 오류

자바 예외 클래스


자바에서의 모든 예외 오류는 Exception 클래스에서 처리한다.
Exception 및 하위 클래스

  • FileNoutFoundException - 존재하지 않는 파일 이름을 입력
  • ClassNotFoundEception - 실수로 클래스의 이름을 잘못 기재
  • DataFormatException - 입력한 데이터 형식이 잘못된 경우

RuntimeException 클래스

  • IndexOutOfBoundsException - 배열의 범위를 벗어남
  • NullPointerException - 값이 null인 참조 변수의 멤버를 호출
  • ClassCastException - 클래스 간의 형 변환을 잘못함
  • ArithmeticException - 정수를 0으로 나누는 산술 오류

런타임 예외 클래스 종류
1. ArrayIndexOutOfBoundsException

2. ArithmeticException

3. NullPointException // 자바에서 가장 자주 발생하는 에러

  • null 객체에 접근해서 method를 호출하는 경우 발생하는 에러(객체가 없는 상태에서 개체를 사용)

4. NumberFormatException

  • 정수가 아닌 문자열을 정수로 변환할 때 발생

5. ClassCastException

  • 타입변환은 상속 관계, 인터페이스 간일 때만 가능한테, 이를 무시하고 억지로 타입을 변환시킬 경우 발생

6. InputMismatchException

  • 잘못 입력한 경우

컴파일 예외 클래스

1. IOException

  • write 메소드에서 발생할 수 있는 IOException에 대한 예외를 처리하지 않아서 오류 벌생
  • print(),println()을 입력하면 자체적으로 컴파일 예외처리를 미리 해주기 때문에 오류가 발생하지 않는다.

2. FileNotFoundException

  • 파일을 찾지 못해서 접근하지 못하는 경우 발생

Checked Exception(컴파일 예외클래스)/Unchecked Exception(런타임 예외클래스)

Checked Exception
반드시 예외 처리
Unchecked Exception
반드시 처리를 안해도 된다.

Checked Exception vs Unchecked Exception --> 반드시 예외 처리를 하냐 마냐?

  • Checked Exception --> 컴파일 단계이므로, 별도의 예외 처리를 하지 않으면 컴파일 자체가 불가능

  • Checked Exception이 발생 가능한 메소드는 try -catch감싸거나, throws로 던져서 처리해야 한다.

  • Unchecked Exception -->자바 컴파일러가 별도의 예외 처리를 하지 않도록 설계되어 있기 때문에, 예외 처리를 반드시 하지 않아도 된다.(try-cath문으로 감싸지 않아도 된다.)

예외 처리(try - catch)

// 프로그램 실행 시 발생할 수 있는 예외적인 일들을 대비해 코드를 작성하는 행위
미리 대응 코드를 작성함으로써 프로그램의 비정상적인 동작 or 종료를 막아서 프로그램의 정상적인 실행상태를 유지할 수 있도록 하는 것


//1.printStackTrace() : 가장 첫 줄에는 예외 메시지를 출력하고, 두 번째 줄부터는 예외가 발생하게 된 메서드들의 호출 관계를 출력한다.
//2.getMessage(): 예외 메시지를 String 형태로 저공 받는다. 예외가 출력되었을 때, 어떤 예외가 발생되었는지 확인할 때 상용한다.
//3.toString(): 예외 메시지를 String 형태로 제공받는다. getMessage() 보다 더 자세하게, 예외 클래스 이름을 함께 제공한다.

package javaplus.exception;

public class ExceptionEx1 {

    public static void generateException(){
        try{
            int result = 10 / 0; // 이 코드는 ArithmeticExceptoin을 발생시킨다.
        }catch(ArithmeticException e){
            System.out.println("ArithmeticException 발견");

            System.out.println("printStackTrace(): ");
            e.printStackTrace();

            //getMessage() 메서드 : 예외 메시지를 반환한다.
            System.out.println("\n getMessage(): ");
            System.out.println(e.getMessage());

            //toString() 메서드 : 예외의 간략한 설명(클래스 이름 + ":" + 메시지)을 반환한다.
            System.out.println("\n toString(): ");
            System.out.println(e.toString());
        }
    }
    public static void main(String[] args) {
        generateException();

    }
}
ArithmeticException 발견
printStackTrace(): 

 getMessage(): 
/ by zero

 toString(): 
java.lang.ArithmeticException: / by zero
java.lang.ArithmeticException: / by zero
	at javaplus.exception.ExceptionEx1.generateException(ExceptionEx1.java:7)
	at javaplus.exception.ExceptionEx1.main(ExceptionEx1.java:24)

Process finished with exit code 0

IOException의 경우, 컴파일 오류이기 때문에 실행 자체가 되지 않는다. 따라서 위와 같이 try catch문으로 넣어줘야 한다.

  • try 블록은 예외가 발생할 수 있는 영역을 감싼다.(예외 발생 가능성이 있는 코드)
    //try 블록에서 예외가 발생하면 그 뒤의 코드들은 수행하지 않고 catch 블록으로 점프한다.

  • cath 블록은 발생한 예외를 처리하는 코드를 작성한다.(예외가 발생했다면 ~을 해라)
    // 소괄호는 예외의 종류를 적어준다(IOException, NullPointException ,,,,,)

  • try 영역에서 발생하는 예외가 여러 개인 경우에는 다수의 catch문을 작성할 수 있다.
  • 예외 발생여부와 상관없이 항상 실행애야 하는 코드가 있다면 finally구문을 사용한다.

finally 구문

  • 예외가 발생하든, 발생하지 않든 반드시 실행되는 구문
  • catch 블록 다음에 적어준다.
    예외가 발생이 된다.
    try-catch-finally
    예외가 발생이 되지 않는다.
    try-finally

사용자 정의 예외 클래스

//예외가 발생하는 시점을 우리가 아는 것

//보통 문법적으로 문제가 되는 상황에서는 JVM(자바 가상 머신)이 적절한 예외를 발생시킨다.

  • Exception이라는 클래스를 상속해야 한다.
    //catch 블록의 소괄호에 들어간 클래스들은 Exception이라는 클래스들을 상속한 클래스들이다.


위 코드를 예외 처리를 해보면

여기서 throw라는 것은 예외가 발생하는 시점에 예외를 발생시키라는 의미이다.
//사용자가 일부러 에러를 throw해서 에러를 catch하는 개념

throws는 예외가 발생한 메소드에서 예외 처리를 하는 것이 아니라, 메소드를 호출한 곳에서 예외 처리하는 것이다.
//메소드 선언부 끝에 작성
//나를 호출한 곳으로 예외를 던져주는 개념
//가독성을 위함(throw를 해주게 되면, 메소드모다 try-catch문을 써줘야 한다.)

요약

// throw - 예외를 발생시키는 것 / throws - 예외를 메서드에 선언하는 것

//예문
public class Main {
    public static void main(String[] args) {
        try {
            method1();
            method2();
            method3();
        } catch (ClassNotFoundException | ArithmeticException | NullPointerException e) {
            System.out.println(e.getMessage());
        }
    }

    public static void method1() throws ClassNotFoundException {
        throw new ClassNotFoundException("에러이지롱");
    }

    public static void method2() throws ArithmeticException {
        throw new ArithmeticException("에러이지롱");
    }

    public static void method3() throws NullPointerException {
        throw new NullPointerException("에러이지롱");
    }
}

new 생성자로 예외 클래스를 초기화하고, 이 클래스 생성자에 입력값을 주게되면, catch문의 getMessage() 메서드에서 출력할 메세지를 지정하게 된다.


위와 같이 호출한 곳에서 try-catch문을 통해 예외를 처리하게 된다.

첫 try-catch문은 예외가 없기 때문에 정상적으로 출력이 된다.
두 번째 try-catch문은 예외가 존재하므로 OverdraftException이 발생하면서 '잔액이 부족합니다'를 출력한다.

연결된 예외

// 한 예외가 다른 예외를 발생시키는 것(다형성을 이용해서 자식 클래스가 부모 클래스를 상속해서 사용하는 것과 비슷한 개념--> 예외의 다형성)

원인 예외(cause exception)
ex) 예외 A가 발생하면 예외 B로 감싸서 throw하는 방식

예외를 다른 예외로 감싸서 던지기

Throwable 클래스에는 getMessage(),printStackTrace() + 연결된 예외를 가능하게 해주는 메서드가 있다.
1. Throwable initCause(Throwable cause) : 해당 예외를 원인 예외로 설정
2. Throwable getCause(): 원인 예외로 반환

//이는 Throwable 클래스에 정의되어 있는 것이기 떄문에 모든 예외 클래스에서 사용 가능하다.

class InstallException extends Exception { ... }
class SpaceException extends Exception { ... }
class MemoryException extends Exception { ... }

public class Main {
    public static void main(String[] args) {
        try {
            install();
        } catch (InstallException e) {
            System.out.println("원인 예외 : " + e.getCause()); // 원인 예외 출력
            e.printStackTrace();
        }
    }

    public static void install() throws InstallException {
        try {
            throw new SpaceException("설치할 공간이 부족합니다."); // SpaceException 발생

        } catch (SpaceException e) {
            InstallException ie = new InstallException("설치중 예외발생"); // 예외 생성
            ie.initCause(e); // InstallException의 원인 예외를 SpaceException으로 지정
            throw ie; // InstallException을 발생시켜 상위 메서드로 throws 된다.
        } catch (MemoryException e) {
            // ...
        }
    }
}
  1. install()메서드에서 SpaceException 예외가 발생한다.
  2. catch 문에 InstallException 예외 클래스를 새로 생성한다.
  3. InstallException 객체의 메서드 initCause()를 이용해서 InstallException 예외에 포함한다.(원인 예외)
  4. InstallException을 발생시켜 상위 메서드로 throws 된다.
  5. main 메서드에서 InstallException 예외를 catch해서 getCause를 통해 원인 예외 로그를 출력

사용하는 이유
1.여러가지 예외를 하의 예외로 묶어서 다루기 위함이다.
2.무슨 에러 때문에 이러한 에러가 났는지 확인하기 용이하기 때문에 사용한다.
3. checked 예외를 unchecked 예외로 바꿀 수 있도록 하기 위함

Checked exception을 Unchecked exception으로 변환

 class MyCheckedException extends Exception { ... } // checked excpetion

public class Main {
    public static void main(String[] args) {
            install();
    }

    public static void install() {
        throw new RuntimeException(new IOException("설치할 공간이 부족합니다."));
        // Checked 예외인 IOException을 Unchecked 예외인 RuntimeException으로 감싸 Unchecked 예외로 변신 시킨다
    }
}

IOException의 경우 Cehecked exception이기 때문에, 반드시 try-catch문으로 감싸줘야 한다.
이러한 번거로움을 없애기 위해 checked exception을 unchecked exception으로 감싸줘서 예외처리를 선택적으로 하게 바꿔준다.

정리

  • 핵심은 상속한다는 것이다.
profile
Today I Learn

0개의 댓글