예외 처리, 재귀, 반복문, 좋은 예외 처리
2024. 2. 7. 00:20ㆍBackend 취업준비/Java
에러 : 프로그램 코드에 의해서 수습될 수 없는 심각한 오류
예외 : 프로그램 코드에 의해서 발생하거나 수습될 수 있는 다소 미약한 오류
예외 처리의 정의, 목적
정의 : 프로그램 실행 시 발생할수 있는 예외에 대비한 코드를 작성하는것
목적 : 프로그램의 비정상 종료를 막고, 정상적이고 의도한 실행 상태를 만드는 것
클래스 계층 구조
- 최상위 클래스 Object, 그 하위 클래스 Throwable 클래스
- Exception과 Error모두 Throwable 클래스의 하위 클래스 이다
- Exception클래스는 Checked Exception, UnChecked Exception으로 구분 될 수 있다.
- RuntimeException역시 Exception을 상속받지만, JVM은 RuntimeException 상속 여부를 보고 실행 예외를 판단
- 예외가 발생하면 예외 객체가 생성된다. try-catch로 예외처리를 하게 된다면, catch 블록에서 예외 객체 참조변수가 유효하다
Throwable클래스의 주요 메서드
- printStackTrace() : 예외 발생 당시의 호출 스택에 있었던 메서드의 정보와 예외 메세지를 화면에 출력한다
- getMessage() : 발생한 예외 클래스의 인스턴스에 저장된 메세지를 얻는다
Checked Exception, UnChecked Exception
- 컴파일러가 예외 처리를 체크하는 지 여부에 따라 둘을 나눈다.
- Checked Exception (Exception) : 예외처리를 하지 않는다면 컴파일 조차 되지 않는다.
- IOException : 입출력 작업 중에 발생하는 예외. 파일에서 데이터를 읽거나 쓸 때, 네트워크 통신 중 데이터를 주고받을 때 등에 발생할 수 있다
- ClassNotFountException : 자바에서 클래스를 로드하려고 할 때 해당 클래스를 찾을 수 없는 경우 발생하는 예외.이 예외는 주로 클래스 이름을 잘못 입력하거나 클래스 파일이 존재하지 않는 경우
- UnChecked Exception (Runtime Exception) : 예외 처리를 하지 않더라도 컴파일이 되고, 실행이 된다. 하지만 프로그램이 비정상 종료된다.
- NullPointerException : 객체 참조가 없는상태, 객체가 없는 상태에서 객체를 사용하려 했을 때 예외가 발생.
- NumberFormatException : 숫자로 변환될 수 없는 문자가 포함되어있을때 발생.-
- IllegalArgumentException : 적합하지 않거나 적절하지 못한 인자를 메소드에 넘겨주었을 때 발생.
- ClassCastException : 타입변환은 상위 클래스와 하위 클래스 간에 발생하고 구현 클래스와 인터페이스 간에도 발생한다. 이러한 관계가 아니라면 클래스는 다른 클래스로 타입 변환할 수 없다. 억지로 타입 변환을 시도할 경우 발생.
- ArrayIndexOutOfBoundsException : 배열에서 인덱스 범위를 초과하였을때 발생.
예외 처리
- try - catch - finally
- try 블록 : 예외 발생 가능 코드
- catch 블록 : 예외 처리 코드 (예외가 발생하지 않으면 실행되지 않는다)
- 다중 catch :
- 멀티 catch :
- fianlly 블록 : 예외 발생 여부와 상관없이 항상 실행할 내용이 있을 경우에만 작성 (옵션, 생략가능) try, catch 블록에서 return문을 사용하더라도 항상 실행된다.
- throws로 떠넘기기
- 예외가 발생하는 메서드 선언부에 throws 키워드를 붙이면 예외 처리를 메서드가 호출할 곳에서 하도록 한다.
- throws를 쓰다가 조금 의문이 들었다 어짜피 예외가 발생하는 메서드를 호출할 때, try-catch로 예외처리를 하면 되는데 굳이 떠넘긴다고 표현할 필요가 있을까?
- 컴파일러 체크 예외는 throws를 안 해주면 오류가 발생한다.
- llegalArgumentException등 자바 표준 라이브러리의 RuntimeException으로 이미 정의되어 있는 예외 클래스나, RuntimeException으로 상속받는 사용자 정의 예외 클래스는 메서드에서 이 예외를 발생 시킬 때 별도의 throws 선언을 하지 않더라도 컴파일 오류가 발생하지 않는다. (그래도 명시적으로 적어주는 것이 좋다고 생각한다. 더 고민해보자)
사용자 입력과 예외 처리
- 사용자에게 이메일을 입력 받는다고 가정하자. 만약 이메일 정규식에 부합하지 않거나, 중복 이메일이 있거나 한다면 예외를 발생 시키고 재 입력 받을 수 있다.
- 이때 함수를 재 호출하는 재귀를 활용하거나 while문을 활용할 수 있다.
- 각각의 방법은 장단점을 가진다.
재귀
- 장점
- 특별한 로직 없이 단순하게 구현할 때 유리하다
- 코드가 간결하고 이해하기 쉽다
- 단점
- 재귀 함수는 기본적으로 스택 메모리를 사용하는데, 재귀의 깊이가 깊어졌을 때, stack overflow가 발생하면서 프로그램이 비정상적으로 종료 될 수 있다.
- 언제나 안전한 프로그램을 개발해야 하는 입장에서, 충분히 에러가 발생할 수 있는 여지를 남겨놓는 것은 바람직하지 않다.
- 또한 함수가 호출되고 종료될 때 스택 프레임을 구성하고 해제하는 과정에서 반복문보다 오버헤드가 들기 때문에 속도도 훨씬 느려지게 된다.
- 단점을 어느 정도 상쇄 시켜줄 수 있는 꼬리 재귀 가 있다고 한다. 하지만 자바에선 불가능 하다고 한다.. 가볍게 알아 보는 것도 좋을 것 같다.
while 루프
- 장점
- 스택 오버 플로우에 대한 위험이 없다. 재귀보다 메모리 사용량이 더 적을 수 있다.
- 단점
- 코드가 다소 번잡할 수 있다. 특히 복잡한 로직을 처리할 때 while 루프 내에 많은 코드가 들어갈 수 있고, 한눈에 어떻게 작동하는지 파악이 힘들다.
- 종료 조건을 제대로 설정하지 않으면 무한 루프에 빠질 수 있다.
결론
- 성능이 중요했던 과거에는 반복문으로 구현 하는게 당연했겠지만, 하드웨어의 발전으로 소프트웨어의 자체 성능에 대한 중요도가 낮아졌기 때문에 오히려 협업이 강조되고 있는 요즘에는 코드의 가독성도 충분히 고려할 필요가 있다
- 재귀 깊이가 예측 가능한 경우 위주로 사용하자
좋은 예외 처리
복구 가능한 오류 : 시스템 외적인 요소로 발생하는 치명적이지 않은 오류
- 사용자의 오입력
- 네트워크 오류
- 서비스적으로 중요하지 않은 작업의 오류
- 처리
- 상시로 발생할 수 있다고 가정하고 사용자에게 문제 원인 고지
- 너무 잦은 복구 가능한 오류는 복구 불가능한 오류 (개발자의 잘못 구현된 코드)일 수 있으니 이를 주의
복구 불가능한 오류 : 별도의 조치 없이 시스템이 자동으로 복구할 수 있는 방법이 없는 경우. 대부분 프로그램 중단
- 메모리 부족 (Out of Memory)
- 시스템이 필요한 메모리를 할당 받지 못할 때 발생한다.
- 스택오버플로우 (StackOverflow)
- 재귀 함수가 너무 깊게 호출되어 스택 메모리가 고갈 될 때 발생한다.
- 시스템 레벨의 오류
- 하드웨어 문제나 운영 체제의 중대한 버그로 인해 발생한다.
- 개발자의 잘못 구현된 코드
- 처리
- 빠르게 개발자에게 알린다
null, -1, 빈 문자열 등 특수 값을 예외 대신 반환하지 않는다
- 예외 상황엔 꼭 throw new exception으로 예외를 발생 시키자
추적 가능하도록 예외 메세지를 작성한다
- 다음과 같은 형태로 예외를 생성하면 입력값에 대한 오류인것은 알겠지만, 어떻게 입력했길래 검증 로직에서 실패한 것인지 알 수가 없다.
throw new IllegalArgumentException('잘못된 입력입니다.');
- 반면 다음과 같이 예외를 남기면, 어떤 이유로 잘못된 것인지 빠르게 파악할 수 있다.
throw new IllegalArgumentException("사용자 " + userId + "의 입력(" + inputData + ")가 잘못되었습니다.");
Layer에 맞는 예외
- 여러 계층(layer)로 구성된 소프트웨어 아키텍처에서 각 계층에 맞게 적절한 예외를 정의하고 던지는 방법을 의미한다.
- 이러한 방식은 오류를 더 쉽게 추적하고, 각 계층에서 발생하는 오류의 본질에 따라 적절한 처리를 할 수 있도록 한다.
- 일반적인 3계층 웹 애플리케이션에서는 다음과 같은 계층이 있다.
- 데이터 액세스 계층 (Data Access Layer)
- 비즈니스 로직 계층 (Business Logic Layer)
- 프레젠테이션 계층 (Presentation Layer)
- 각 계층에서 발생할 수 있는 오류의 성격은 다르기 때문에, 해당 계층에 맞는 예외를 던지는 것이 유용하다
예외 계층 구조를 만든다
- 수많은 사용자 정의 예외를 계층 없이 만들 지 않는다. 용도에 맞게 분류할 필요가 있으며, 기준에 맞게 분류한 Exception들은 그에 맞게 일관된 처리 방법을 적용할 수 있다.
예외의 이름에 원인과 내용을 반영한 네이밍으로 선정한다.
catch한 후 아무런 작업 없이 throw하는 로직을 만들지 않는다.
예외 상황이 아닌데, 단지 프로그램을 정상적으로 진행 시키기 위해 예외를 사용하지 않는다
- 프로그램은 정상적으로 작동하지만, 원하는 데이터가 안 들어 온다고 해서 예외를 발생시키지 않는다.
출처
(도서) 이것이 자바다
자바의 정석 유튜브 강의
https://tecoble.techcourse.co.kr/post/2020-04-30-iteration_vs_recursion/
'Backend 취업준비 > Java' 카테고리의 다른 글
자바 함수형 프로그래밍 특징 (0) | 2024.02.18 |
---|---|
제네릭, 와일드카드 (0) | 2024.02.11 |
객체 지향 프로그래밍 OOP - 다형성 (0) | 2024.02.03 |
객체 지향 프로그래밍 OOP - intro (0) | 2024.02.03 |
불변 클래스, 불변 객체, String, 래퍼 클래스 (2) | 2024.02.01 |