[Java] Error & Exception

dayeon·2023년 7월 30일
0

Java

목록 보기
1/1

🍎 프로그래밍 오류 종류 🍎

1. 컴파일 에러
2. 런타임 에러
3. 논리 에러

🔹 논리적 에러(logical error) : 실행은 되지만 의도와 다르게 동작하는것

논리적 에러는 이른바 '버그'
프로그램이 실행되고 작동하는데 아무런 문제가 없는 오류이나, 결과가 예상과 달라 사용자가 의도한 작업을 수행하지 못하게 되어 서비스 이용에 지장이 생길 수 있는 것
논리적 오류는 컴퓨터 입장에서는 프로그램이 멀쩡히 돌아가는 것이니 에러 메시지 X
따라서 개발자는 프로그램의 전반적인 코드와 알고리즘을 체크 해야 함

예시로 재고량이 음수가 나오면 안되는데 음수가 나와버리는 경우, 게임 캐릭터가 피가 0이어도 죽지 않는 경우가 있음

🔹 컴파일 에러(compile-time error) : 컴파일시에 발생하는 에러

컴파일 에러는 컴파일 단계에서 오류를 발견하면 컴파일러가 에러 메시지 출력해주는 것
컴파일 에러 발생의 대표적인 원인으로 문법 구문 오류(syntax error)를 들 수 있음
예를 들어 에디터에서 코딩을 할 때 맞춤법, 문장부호(;), 선언되지 않은 변수 사용을 하면 빨간줄로 컴파일 에러 표시 됨
컴파일 에러가 있다는 것은, 곧 컴파일이 안된다는 의미
이는 즉 프로그램이 만들어지지 않아 프로그램 실행 자체가 불가하기 때문이다.
💡Point

컴파일 에러는 소스 코드를 javac.exe로 컴파일 하는 과정에서 컴파일러가 전반적인 코드를 체크해서 에러 메세지를 보여주는 형태
IDE에서는 일정 주기로 계속 자동으로 컴파일을 해주기 때문에 바로바로 문제를 알 수 있음

🔹 런타임 에러(runtime error) : 실행시에 발생하는 에러

컴파일 에러를 꼼꼼하게 잡아 컴파일에는 문제가 없더라도, 프로그램 실행 중에 에러가 발생해서 잘못된 결과를 얻거나, 혹은 외부적인 요인으로 기계적 결함으로 프로그램이 비정상적으로 종료될 수 있음
즉, 프로그램을 실행하는 과정에서 생기는 오류
이는 개발자가 직접 오류를 확인하여 처리해야 함

🍎 Error & Exception 🍎

자바 프로그래밍에서는 실행 시(runtime) 발생할 수 있는 오류를 '에러(error)'와 '예외(exception)' 두 가지로 구분
🔹에러(error) : 프로그램 코드에 의해서 수습 될 수 없는 심각한 오류
🔹예외(exception) : 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류
Error은 메모리 부족(OutOfMemoryError)이나 스택 오버 플로우(StackOverflowError)와 같이 발생하면 복구할 수 없는 심각한 오류로써 JVM 실행에 문제가 생긴 것이므로 개발자가 대처할 방법이 없음
Exception은 발생하더라도 수습 될 수 있는 비교적 덜 심각한 오류로, 개발자가 구현한 로직에서 발생한 실수나 사용자의 영향에 의해 발생함
이는 개발자가 미리 예측하여 방지할 수 있기 때문에 상황에 맞는 예외 처리(Exception Handling)를 해줘야 함
💡예외 처리란?

프로그램 실행 시 발생할 수 있는 예기치 못한 예외의 발생에 대비한 코드를 작성하는 행위
프로그램 실행 도중에 발생하는 에러는 어쩔 수 없지만, 예외는 프로그래머의 실력에 따라 충분히 포괄적으로 방지할 수 있음
따라서 예외 처리의 목적은 예외의 발생으로 인한 실행 중인 프로그램의 갑작스런 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것

🍎 예외 클래스의 계층 구조 🍎

JVM은 프로그램을 실행하는 도중에 예외가 발생하면 해당 예외 클래스로 객체를 생성하고서 예외 처리 코드에서 예외 객체를 이용할 수 있도록 해줌

Error&Exception

🔹Throwable 클래스란 ?
오류와 예외 모두 자바의 최상위 클래스인 Object를 상속받음
그 사이에는 Throwable 클래스와 상속관계가 있는데, Throwable 클래스의 역할은 오류나 예외에 대한 메시지를 담는 것

➡️ Exception 및 하위 클래스 : 사용자의 실수와 같은 외적인 요인에 의해 발생하는 컴파일시 발생하는 예외

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

➡️ RuntimeException 클래스 : 프로그래머의 실수로 발생하는 예외

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

🍎 Checked Exception / Unchecked Exception 🍎

🔹Checked Exception은 컴파일 예외클래스들을 가리키는 것
🔹Unchecked Exception은 런타임 예외클래스들을 가리키는 것
Checked ExceptionUnchecked Exception
확인
시점
컴파일 단계런타임 단계
처리
여부
반드시 예외를 처리해야 함명시적인 처리를 안해도 됨
트랜잭션 처리예외 발생 시 롤백(rollback) X예외 발생 시 롤백(rollback) O
예외
종류
RuntimeException을 제외한 Exception 클래스와
그를 상속받는 하위 예외
(IOException, FileNotFoundException, SQLException 등)
RuntimeException 과 그 하위 예외
(NullPointerException, IllegalArgumentException, IndexOutOfBoundException, SystemException 등)
두 Checked / Unchecked Exception의 가장 핵심적인 차이는 '반드시 예외 처리를 해야 하는가?'
Checked Exception은 체크 하는 시점이 컴파일 단계이기 때문에, 별도의 예외 처리를 하지 않는다면 컴파일 자체가 되지 않음
따라서 Checked Exception이 발생할 가능성이 있는 메소드라면 반드시 로직을 try - catch로 감싸거나 throws로 던져서 처리해야 함
// try - catch 로 예외처리
public static void fileOpen() {
    // 파일을 열고 쓰고 닫는 아주 단순한 로직이어도 이에 대한 예외는 checked exception으로 분류 되기 때문에 반드시 try - catch로 감싸주어야 한다.
    try {
        FileWriter file = new FileWriter("data.txt");
    	file.write("Hello World");
    	file.close();
    } catch(IOException e) {
    	e.printStackTrace();
    }
}

// -------------------------------------------------------------------------

// throws 로 예외처리
public static void fileOpen() throws IOException {
    // 파일을 열고 쓰고 닫는 아주 단순한 로직이어도 이에 대한 예외는 checked exception으로 분류 되기 때문에 반드시 try - catch로 감싸주어야 한다.
    FileWriter file = new FileWriter("data.txt");
    file.write("Hello World");
    file.close();
}

🍎 예외 처리 방법 🍎

1. 예외 복구
2. 예외 회피
3. 예외 전환

➡️ 예외 복구

예외 상황을 파악하고 문제를 해결하여 정상 상태로 돌려 놓는 방법
핵심은 예외가 발생해도 어플리케이션은 정상적인 흐름으로 진행된다는 것
try~catch~finally
//재시도를 통해 예외를 복구하는 코드 
int maxretry = MAX_RETRY;
while(maxretry-- > 0) {
	try{
      //예외가 발생할 가능성이 있는 시도
      return; //작업 성공 시 리턴
    } catch (SomeException e) {
    	//로그 출력
      	//정해진 시간만큼 대기
    } finally {
    	//리소스 반납 및 정리 작업
    }
}
throw new RetryFailedException(); //최대 재시도 횟수를 넘기면 직접 예외 발생

➡️ 예외 회피

예외 처리를 직접 담당하지 않고 호출한 메서드로 위임해 회피하는 방법
예외가 발생하면 throws를 통해 호출한 쪽으로 예외를 던지고 그 처리를 회피하는 것
무책임하게 던지는 것은 위험하기 때문에, 호출한 쪽에서 다시 예외를 받아 처리하도록 하거나 해당 메소드에서 이 예외를 던지는 것이 최선의 방법이라는 확신이 있을 때만 사용해야 함
public void add() throws SQLException {
	//구현 로직
}

➡️ 예외 전환

예외 회피와 비슷하게 메서드 밖으로 예외를 위임하지만, 그냥 위임하지 않고 적절한 예외로 전환해서 넘기는 방법
조금 더 명확한 의미를 전달하기 위해 적합한 의미를 가지는 예외로 변경
예외 처리를 단순하게 만들기 위해 포장(wrap)할 수도 있음
//조금 더 명확한 예외로 던짐
public void add(User user) throws DuplicateUserIdException, SQLException {
	try{
    	//
    } catch(SQLException e) {
    	if(e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY) {
        	throw DuplicateUserIdException();
        }
      	else throw e;
    }
}

//예외를 단순하게 포장
public void someMethod() {
	try{
    	//
    }
  	catch(NamingExceptin ne) {
    	throw new EJBException(ne);
    }
  	catch(SQLExceptin se) {
    	throw new EJBException(se);
    }
  	catch(RemoteExceptin re) {
    	throw new EJBException(re);
    }
}
profile
I'm happy...

0개의 댓글