[JAVA] JAVA 에러(Error)와 예외(Exception)

D A S H B O A R D
D E V E L O P
S E C U R I T Y
 프로그래밍 에러 종류  논리적 에러  컴파일 에러  런타임 에러  Java 에러 & 예외  Checked / Unchecked Exception
주요내용
Reference

 프로그래밍의 에러 종류

컴파일 에러 (compile-time error) : 컴파일 시에 발생하는 에러
런타임 에러 (runtime error) : 실행 시에 발생하는 에러
논리적 에러 (logical error) : 실행은 되지만 의도와 다르게 동작

 논리적 에러

프로그램은 정상적으로 동작하는 것처럼 보이지만, 실행 결과가 개발자의 의도와 다르게 하고자 했던 로직이 정상적으로 실행되지 않는 에러를 말한다.
해당 에러는 프로그램은 정상적인 동작으로 인식하기 때문에 별 다른 에러를 뱉지 않는다. 하지만 해당 에러는 어떠한 오류도 내지 않기 때문에, 그 어떠한 에러보다 개발자들이 싫어하는 오류이다.
주의점!!
논리적 에러는 향후 취약점으로 연결될 수 있다.
의도와 다르게 동작하기 때문에 서비스 가용성에 문제가 생길 가능성이 크다.
해당 에러를 잡기 위해서는 모든 코드를 디버깅 해봐야 하는 불상사가 생길 수 있다…..

 컴파일 에러

컴파일 에러는 프로그램 코드를 컴파일할 때 발생되는 에러로 심각하게 볼 필요 없이 흔하게 볼 수 있는 에러이다.
Syntax error와 같은 이유로 IDE 상에 나타나는 빨간 줄 역시 컴파일 에러에 해당한다.
정확히는 Java로 따지자면, Javac를 통해 컴파일하는 과정에서 생기는 에러를 뱉는 것이지만 IDE 상에서는 문법 오류를 빠르게 알려주기 때문에 수정하면 된다!!

 런타임 에러

컴파일 에러를 꼼꼼하게 잡아 컴파일에는 문제가 없더라도, 프로그램 실행 중에 에러가 발생해서 잘못된 결과를 얻거나, 혹은 외부적인 요인으로 기계적 결함으로 프로그램이 비정상적으로 종료될 수 있다.
대체로 개발 시 설계 미숙(논리적)으로 발생하는 에러가 대부분이며, 런타임 에러 발생 시 프로그래머가 역추적해서 원인 확인해야 한다.
스프링이 제공하는 선언적 트랜잭션(@Transactional)안에서 예외 발생 시 체크 예외는 롤백이 되지 않고, 언체크 예외는 롤백된다.
Java에서는 런타임 에러를 Error와 Exception으로 구분해 두었다.
에러(error) : 프로그램 코드에 의해서 수습될 수 없는 심각한 오류 → 메모리 부족(OutOfMemoryError)이나 스택오버플로우(StackOverflowError)와 같이 일단 발생하면 복구할 수 없는 심각한 오류이고 예측이 불가능한 녀석이다. 즉, 에러는 JVM 실행에 문제가 생긴 것이므로 개발자가 대처할 방법이 없다.
예외(exception) : 프로그램 코드에 의해서 수습될 수 있는 미약한 오류 → 즉 알고리즘 오류로 Exception 예외가 계속 발생한다고 해도 Error 처럼 프로그램이 죽거나 그럴경우는 적기 때문

 Java 에러 & 예외

TODO
위에서 말한 것과 같이 에러는 심각한 오류, 예외는 미약한 오류이지만, 예외를 가볍게 보고 넘어가면 안된다. → 비정상적 종료, 비정상 동작 등이 발생할 수 있기 때문
Java의 Exception을 Handling하기 위해 try catch 구문을 통해 Exception을 받고, 예외상황을 처리해야만 한다.
아래는 자바의 에러와 예외의 상관관계이다.
각종 Error와 Exception은 Java의 Throwable Class를 상속받아 만들어지며 실제로 많은 Error와 Exception이 Throwable 객체의 Subclass로 존재한다.
Throwable 클래스에는 getMessage()printStackTrace() 함수가 구현되어 있다.
getMessage()
해당 throwable 객체에 대한 자세한 내용을 문자열로 반환
printStackTrace()
해당 throwable 객체와 표준 오류 스트림(standard error stream)에서 해당 객체의 스택 트레이스(Stack Trace)를 출력한다.
Stack Trace
프로그램의 실행 과정에서 호출된 메서드들의 순서와 위치 정보를 나타낸 것
Error Class는 외부 요인으로 발생하는 것으로 개발자가 대처할 수 없기 때문에 우리와 같은 개발자가 집중해야할 곳은 Exception이다.

Exception 클래스

Exception Class 안에도 컴파일 에러와 런타임 에러가 모두 존재한다.
Exception Class 안에 있는 Exception 중 RunTimeException을 제외하고는 모두가 CompileException로 나뉜다.

대표적 예외 클래스 종류

예외 타입
설명
ArithmeticException
어떠한 수를 0으로 나누는것과 같이 비정상 계산 중발생
NullPointException
Null 객체 참조시 발생
IllegalArgumentException
메소드의 전달 인자값이 잘못된 경우 발생
IllegalStateException
객체의 상태가 메소드 호출에는 부적합할 경우 발생
IndexOutOfBoundsException
index 값이 범위를 넘어갈 경우 발생
UnsupportedOperationException
객체가 메소드를 지원하지 않는 경우 발생
SecurityException
보안 위반 발생 시 보안 관리 프로그램에서 발생
ProviderException
구성 공급자 오류시 발생
NoSuchElementException
구성 공급자 그 이상 없는 경우 발생
ArrayStoreException
객체 배열에 잘못된 객체 유형 저장시 발생
ClassCastException
클래스 간의 형 변환 오류시 발생
EmptyStackException
스택이 비어있는데 요소를 제거하려고 할 시 발생

 Checked / Unchecked Exception

간단하게 Checked Exception == Compile Exception, Unchecked Exception == RunTime Exception 이라고 생각하면 된다.
하지만, 코드적 관점에서 예외처리 동작을 필수로 지정해야 하는 지, 말아도 되는지의 유무에 따라 나뉜다.

Checked Exception Handling 방법

1.
try - catch 구문
public String makeTokenString(User user) { JwtToken jwtToken = makeToken(user); try { return gsonUtil.deserialize(jwtToken); } catch (Exception e) { log.warn("Fail to makeTokenString. ({}) ({})", e.getCause(), e.getMessage()); return null; } }
Java
복사
2.
throws 이용
@Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { }
Java
복사
3.
Checked. Exception → Unchecked Exception 변환
chained exception을 이용해 IOException과 같은 Checked Exception을 RuntimeException으로 감싸줘 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 예외로 변신 시킨다 } }
Java
복사
4.
try-with-resources
try 블록에서 사용할 resource를 선언
finally 블록에서 자원 반환 코드를 작성하지 않아도 자원(Resource)을 자동으로 반환하기 위해 사용
자원(Resource)
java.lang.AutoClosable 또는 java.io.Closable을 구현한 객체
public static void main(String args[]) { try ( FileInputStream fis = new FileInputStream("file.txt"); BufferedInputStream bis = new BufferedInputStream(fis) ) { //do something } catch (IOException e) { // 에러처리 } }
Java
복사