210320 토 TIL

bongf·2021년 3월 20일
0

TIL

목록 보기
23/40

✔ Done

  • 미션3 pr

📂 Feeling

  • Custom 예외를 작성할 때에 대해서 학습했지만 실제 미션에서 여전히 그 경계가 애매하다
    • 코드 중복을 피하기 위해서 @ControllerAdvice를 사용했고 그러다보니 예외의 종류가 같으면 같은 예외 처리가 된다. 그래서 각기 다른 예외를 만들어주기 위해 Custom예외를 만들었다. 이것이 Custom예외를 만드는 이유가 되는가?
  • 몸이 안좋아서 어제 아예 휴식을 취했는데 아플 때는 애매하게 하는 것 보다 쉬는 것이 더 나은 것 같다.

Good

Bad

✔ TODO


🗒 Learned

  • 지난 번 예외 정리했던 것에서 몇 가지를 추가했다.

예외

1) CustomException

1-1) custom exception을 언제 써야 할까 블로그의 글

  • 아래 내용은 해당 블로그의 내용을 이해한 수준에서 정리

1. 표준 예외를 재사용해야하는 이유

  • 예외 메세지만 구체화 시켜서 전달해도 예외에 대한 정보를 구체적으로 전달할 수 있다. 별도 예외를 만들지 않고 사용할 수 있다.
  • 다른 개발자들과 소통이 쉽고 가독성이 높다.
  • 예외 클래스 수가 많아지면 메모리를 잡아먹고 클래스 로딩 시간도 길어진다. 유지보수도 쉽지 않다.
  • 만약 custom 예외에서 아래의 경우에 모두 해당한다면 표준 예외를 사용하자
    • 1) 메세지 재정의만 해 준 custom 예외
    • 2) 해당 custom 예외가 발생시키는 지점이나 catch하는 지점에서 exception을 구분해서 어떤 것을 처리해준 것이 없다면

2. custom 예외를 언제 사용해야 할까?

  • 0) docs 가이드

    You should write your own exception classes if you answer yes to any of the following questions; otherwise, you can probably use someone else's.
    1.Do you need an exception type that isn't represented by those in the Java platform?
    2.Would it help users if they could differentiate your exceptions from those thrown by classes written by other vendors?
    3.Does your code throw more than one related exception?
    4.If you use someone else's exceptions, will users have access to those exceptions? A similar question is, should your package be independent and self-contained?
    https://docs.oracle.com/javase/tutorial/essential/exceptions/creating.html

  • 1) 여러 타입의 exception이 발생할 수 있는 코드에서 한가지 Exception으로 묶어 처리 할 때

    • 예를 들어, IndexOutOfBoundsException, NullPointerException 둘 중 어떤 것이 발생했을 때 controller에서 똑같이 특정 string을 반환한다면 각각의 exception을 catch해주는 것을 작성하는 것 보다 customExcption을 작성하는 것이 낫다.
  • 2) 상세한 예외 정보 제공해야 할 때

    • IndexOutOfBoundsException에서 index의 범위가 어디까지 인지, 내가 얼마큼을 초과했는지 등에 대한 상세한 예외 정보를 제공할 수 있다.
    • 다른 말로 하면 해당 예외에 대한 구체적인 처리를 해줄 수 있다는 말 같다. 같은 내용이 baeldung에도 나온다.

To catch and provide specific treatment to a subset of existing Java exceptions

  • 2.2) 비즈니스 로직상의 익셉션일 때
    • 비즈니스 로직상에서 발생하는 예외에 custom exception을 적용하면 사용자나 개발자들이 정확한 문제를 알 수 있다.
    • 출처_baeldung

3. custom 예외 장점

  • 1) 예외에 대한 응집도 향상
    • 예외에 관련된 메시지, 데이터 등을 별도의 익셉션 클래스에서 관리 할 수 있으므로
  • 2) 의도된 예외와 그 외 발생한 예외를 구분할 수 있다.
    • 예를 들어 IllegalArgument가 발생했을 때, 내가 의도한 IllegalArgument부분 말고도 의도하지 않은 곳에서 같은 예외가 발생해도 exceptionHandler가 잡아내서 똑같이 처리. 내 입장에서는 그를 구분할 수 없다. 의도한 예외에 대해 CustomException을 발생시킨다면 이를 구분할 수 있게 된다.

1-2) CustomException 작성할 때 Exception 상속 or RuntimeException 상속?

1-2-1) api 클라이언트가 그 exception을 복구할 수 있다면 checked(Exception), 어차피 client가 할수 있는 부분이 없다면 uncehcked(RuntimeException)

  • docs 가이드라인 https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html

    If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.

  • Runtime exception은 프로그래밍 문제를 의미
    • 출처

      Runtime exceptions represent problems that are the result of a programming problem, and as such, the API client code cannot reasonably be expected to recover from them or to handle them in any way.

  • API 사용자 쪽에서 예외 상황을 복구할 수 있다면 checked 예외(예외처리강제) : API 사용자에게 문제를 해결할 기회를 주는 것
  • API 사용자가 API 사용법을 어겨 발생할 때는 uncheckd예외, 어차피 API 사용자가 그 예외 발생되도 처리할 수 있는 부분이 없다. 그 상항에서는 애플리케이션 종료하는 것이 더 낫다 하면 unchecked
    • ex. ArithmethicException 은 산술적인 오류가 나면 그 뒤에 다른 곳에 많은 영향. 프로그램 종료가 더 낫겠다.
    • 사용자가 메소드를 잘못 호출했을 때의 예

      One case where it is common practice to throw a RuntimeException is when the user calls a method incorrectly. For example, a method can check if one of its arguments is incorrectly null. If an argument is null, the method might throw a NullPointerException, which is an unchecked exception.

1-2-2) 그래도 뭔가 애매하다..

1-3) Custom 예외 작성시 규칙들

  • 네이밍 컨벤션을 따르자

    • 자바에서 제공하는 예외의 클래스 이름을 보고 비슷하게 만들어보자. 그 예로 모두 ~Exception으로 끝난다
    • 출처
  • 예외에는 주석을 달아주자

  • 예외 만드는 방법

  • 주의 : error.html 로 인한 삽질

    • 특정 exception 처리를 error.html로 연결 해줄 때 model에 담은 errorMessage가 담기지 않아 model 관련 문제인지 알고 삽질 을 했다.
    • 알고보니 error.html 을 만들면 에러처리 상관 없이 에러가 나면 그 페이지로 가는 것 같다.

      At start-up, Spring Boot tries to find a mapping for /error. By convention, a URL ending in /error maps to a logical view of the same name: error. In the demo application this view maps in turn to the error.html Thymeleaf template. (If using JSP, it would map to error.jsp according to the setup of your InternalResourceViewResolver). The actual mapping will depend on what ViewResolver (if any) that you or Spring Boot has setup.
      출처 https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc

    • 심지어 내가 만든 custom예외 이름으로 페이지를 설정해 주었을 때도 해당 페이지로 return 을 작성했지만 연결되지 않고 whitelabel error page 로 연결되었다.
    • 전혀 다른 이름으로 설정했을 때, errorMessage도 잘 전달되었다.

2. 프로젝트 할 때 했던 고민

2-1) 언제 예외를 발생 시켜야 하나

  • 특정 상황에 대해 예외를 발생시킬지 분기처리로 대응 로직을 짜줄지 고민했다.
  • 브라이언 리뷰어님의 의견 : 예외 발생 기준을 몰라 생기는 문제다.

    프로그램을 작성한다는 건 한편의 플로우 차트를 짜는 것과 같습니다.
    제 생각입니다만 내가 머릿속에 그린 플로우 차트의 가지에 담긴 상황이라면, 예외는 아닙니다.

    가위바위보를 할 때, 가위-바위-보 가 나오는 경우에 대해서는 예외처리를 안 하는 것처럼

  • 고민했던 부분이 예를 들어 접근 권한이 없는 부분에 접근 하려고 한 경우 예외처리를 할 것인가였다. 지금 이에 대해선 아래와 같이 정리했다.
      1. 일단 해당 접근을 막아야한다.
      1. 다 차단했음에도 비정상적 루트로 접근한다면 예외 처리

2-2) 어떻게 예외 사이의 관계를 만들까

  • 모든 상황마다 예외를 새로 만든다는 것은 말이 안된다.
  • 예외를 증류탑을 만들어라 - 브라이언 님의 테크톡
    • 예를 들어 같은 예외 처리 로직이 적용되는 서로 다른 예외의 경우 하나의 부모 예외를 상속하게 만들어서, 예외가 발생 부모 클래스 예외로 catch하여 같은 처리를 해준다.

3. 스프링에서 예외처리

프로젝트

  • 프로젝트에서는 @ContorllerAdvice와 @ExceptionHandler 를 사용했다.
package com.team19.airbnb.exception;

import com.team19.airbnb.ResponseBody;
import com.team19.airbnb.exception.notauthorized.NotAuthorizedException;
import com.team19.airbnb.exception.notfound.NotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;

@ControllerAdvice
public class AirbnbExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(AirbnbExceptionHandler.class);

    @ExceptionHandler(NotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ResponseBody<String> handleNotFoundException(NotFoundException e) {
        logger.error(e.getMessage());
        return ResponseBody.notFound(e.getMessage());
    }

    @ExceptionHandler(NotAuthorizedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public ResponseBody<String> handleNotAuthorizedException(NotAuthorizedException e) {
        logger.error(e.getMessage());
        return ResponseBody.notFound(e.getMessage());
    }
}

상태코드

  • 정의 및 각 상태코드 설명
  • 기본적인 상태코드

    100-level (Informational) — Server acknowledges a request
    200-level (Success) — Server completed the request as expected
    300-level (Redirection) — Client needs to perform further actions to complete the request
    400-level (Client error) — Client sent an invalid request
    500-level (Server error) — Server failed to fulfill a valid request due to an error with server

  • @ResponseStatus annotation을 사용
  • 파이로가 설명해준 응답객체에 '왜 상태코드를 넣어줘야 하나'
    • 예외처리를 할 때 http 상태코드를 왜 넣어줄까 했는데
    • 협업을 위한 것이었다. 해당 http 상태코드를 넣어두면
    • 이런 상태코드가 뜨게 되고 이에 따라 프론트 단에서 다른 처리 (if-else문으로 처리) 를 하게 되므로 이런 에러페이지 구성 등도 프로트에서 하게 된다. 와 !!!!

기타

많이 사용되는 예외

1. IllegalArgumentException
  • 메서드의 파라미터로 null 값이 들어오면 관례상 IllegalArgumentException보다는 NullPointerException을 던진다.
  • 시퀀스의 허용 범위를 넘는 값을 건넬 때도 IllegalArgumentException보다는 IndexOutOfBoundsException을 던진다.
2. IllegalStateException
  • 대상 객체의 상태가 호출된 메서드를 수행하기에 적합하지 않을 때 주로 던진다.
3. NullPointerException
  • 매개 변수의 값이 null일 때
4. IndexOutOfBoundsException
  • 인덱스 매개 변수 값이 범위를 벗어날 때
5. ArithmeticException
  • 산술적인 연산에 오류가 있을 때

  • 위 링크된 블로그에서는 많이 사용되는 5가지 예외에 ConcurrentModificationException, UnsupportedOperationException, NumberFormatException 가 작성되어있다.

에러메세지 그대로의 노출은 위험할 수 있다.

4. 예외 관련 작성글

profile
spring, java학습

0개의 댓글