- 네이버 커넥츠 재단 "부스트코스 - 웹 프로그래밍 👈" 최종 프로젝트
- 본 서비스를 이용하여 뮤지컬/콘서트/공연을 조회, 예약하기, 예약확인, 리뷰등록을 할 수 있다.
- Mobile에 최적화된 Web Service
❗ HTML, CSS was supported by [boostcourse](https://www.edwith.org/boostcourse-web/joinLectures/12943)
- Spring (4.3)
- MySQL (5.6)
- Tomcat (8.5)
- Java 8
- HTML
- CSS
- JavaScript
- 2021.07 ~ 08
- ofPattern은 전역변수로 빼보세요 (스레드세이프라면 빼서 관리하는게 메모리상 이득일 수 있어요)
- static final로 선언한 변수는 대문자 스네이크 명명 규칙을 따릅니다
- 의미 없는 생성자가 있다면 제거해도 좋습니다.
- 변수명 out은 정확하지 않습니다. 너무 장황해지지 않는 선에서 정확한 의미를 가지도록 지어주세요
- 지금은 타입이 3개지만 타입이 더 늘어나면 어떻게 관리해야할까요? → enum에 대해 찾아보세요
- 요청이 올 때마다 dao 객체를 생성하는 것은 메모리 낭비 같습니다. → 싱글톤에 대해 찾아보세요
- todo.getType().equals("문자열")일 때 만약 getType의 결과가 null이면 nullPointerException이 뜰 수 있습니다. "문자열".equals(~)가 기본입니다!
- 상태값이 추가되면 classifyStates()함수에 인자값이 점점 늘어나게 됩니다. 다른 방법은 없을까요? -> Map 이용
- except()가 발생하면 콘솔에 에러가 찍히고 끝입니다. 유저의 입장에서는 최소한의 알림을 주는 화면이 있는게 좋습니다. 로그가 직접 보이는 것은 위험 등급이 가장 높은 에러입니다.
- ObjectMapper도 전역으로 빼도 될 것 같습니다.
- indById에서 아이디로 타입을 가져오는데, 애초에 타입을 화면 단에서 넘기면 db에 접근을 줄일 수 있습니다. db접근은 아주 비용이 비쌉니다.
- Enum은 참고 블로그를 읽어 보세요. (https://techblog.woowahan.com/2527/)
- 업데이트 할 때 필요한 부분만 업데이트 하는게 좋을까요 전체를 업데이트 하는게 좋을까요? → 정답은 없습니다. 전체를 수정하는 코드는 어떤 필드를 업데이트해도 쓸 수 있고, 필요한 부분만 수정하는 코드는 sql 쿼리를 여러개 짜야합니다. 반면 전체를 수정하는 코드는 전체에 대한 정보를 select를 가져와야 할 수도 있습니다.
- findById보다 selectById가 더 어울리는 것 같습니다. JPA를 염두에 둔 것이 아니라면 혼용이 되어있는 것입니다.
- 서버에서 시간을 정하고 db에 넣게되면 서버와 db의 시간이 다를 수도 있습니다. 일반적으로 db의 now함수를 씁니다.
- 데이터에 대한 검증은 프론트에서도 하지만 백엔드에서도 필수입니다. 보통은 로직 진입부에서 합니다.
- 현재는 controller, dto, dao 아래에 도메인 별로 나눠져있는데 도메인 별로 나누고 그 아래에 controller, dao, dto..로 나누는 것이 더 좋습니다. 지금은 규모가 작지만 나중에 클래스들이 추가되면 찾기 어려워질 수 있습니다.
- Spring에서 bean 주입 방식이 3가지 정도가 있습니다. 지금 사용한 것은 필드 주입인데, 단점이 뭔지 찾아보세요.
- requestMapping에서 path가 디폴트 이므로 path는 지워도 됩니다.
- 지금 Dto를 클래스이름에 다 붙였는데 붙인 이유가 있나요? 붙일거면 메서드 명 변경이 필요해 보입니다. → DB에 promotion이 있고, 자바에서 json으로 리턴해줘야하는 promotion이 있는데, 이름은 같지만 다른 필드들을 가지고 있어 구분할 필요가 있어서 사용했습니다.
- RestController와 Controller의 차이점은 응답 값을 responsebody에 넣어주는 것입니다.
- 일반적으로 service 같은 경우는 인터페이스를 만들어서 사용합니다. 이번 기회에 인터페이스와 추상 클래스까지 공부하면 많은 도움이 될 것 같습니다.
- SQL 쿼리를 짤 때는 스키마 관계를 충분히 먼저 파악해야 합니다. 조인순서, 드라이빙 테이블 같은 것들까지 고려하여 성능을 신경 쓰면 더 좋습니다. 워크 벤치에서 쿼리 돋보기 모양 누르면 쿼리 plan이 뜨는데 그것을 보고 해석할 줄 알아야 합니다.
- 인터페이스에 상수를 두기보다 구현체에 두는 것이 더 맞아 보입니다. 인터페이스에 상수를 두면 그렇게 강제화하는 것처럼 보입니다.
- AwithB 같은 네이밍은 좋지 않습니다. 속성들이 추가될 때마다 with를 추가할 수는 없습니다.
- categoryId에 따라 dao의 어떤 함수를 호출할지 if문으로 분기하고 있는데, 컨트롤러에서 분기를하고, Service에서 메서드를 나누는 것이 더 깔끔해 보입니다.
- 생성자에 각 속성들을 다 넣으면 나중에는 코드가 지저분해집니다. 빌더패턴에 대해 공부해보세요.
- Controller에서 param의 디폴트는 true입니다. 애노테이션을 쓸 때는 들어가서 속성을 읽어보세요.
- SQL에서 count도 예약어이니 대문자로 표시하는게 컨벤션입니다.
- ProductController 분기하는 곳에서 if 하나만 쓰니 예외처리의 느낌이 납니다. if-else를 하면 더 분기의 느낌이 날 것 같습니다.
- 클래스나 함수의 바로 첫 줄은 공백이 없는 것이 컨벤션입니다.
- 의미 단위로 개행을 해주세요
- 빈 리스트를 반환할 때, null이나 new ArrayList()말고 다른 방법이 있을 수도 있습니다.
- ProductServiceImpl내의 메서드에서, ProductListDto를 우선 선언한뒤, 조건문들의 흐름을 타고, 마지막에 리턴을 해주면 좋을 것 같습니다.
- (DisplayServiceImpl) 어짜피 null 일때 디폴트로 null을 넣어준다면, if문으로 null일 때를 체크 안해도 될 것 같습니다.
- 만약 코드가 너무 길어지면 중간에 변수를 한번 할당 받아서 넣어줘도 되지만, 그게 아니라면 인라인으로 한번에 해도 됩니다.
- (Controller) 만약 PathVariable이 안들어오면 어떻게 되는지 처리해보셨나요? 404 커스텀 페이지를 줘도 될 것 같습니다. 실무에서는 팀의 약속에 따라, 악의적이다라고 판단하면 로그를 남기기도 합니다. Spring controller에서 예외 처리를 하는 방법이 2~3가지가 있는데 찾아보세요.
- (exception) NumberFormatException과 Not Found는 다른거입니다. 검색했을 때 결과 값이 없는 것이랑 잘못된 검색을 하는 것은 차이가 있습니다.
- 보통 처리할 수 있는 예외들에 대해서는 가능한 처리를 해주고, 그래도 예상하지 못한 경우에는 Exception으로 일괄적으로 받되, 로그를 남기고 후에 대응을 합니다.
- 예외를 받았으면 최소한의 처리(로그 남기기)를 해주는 것이 좋습니다.
- NOT FOUND는 검색한 데이터가 없을 때, 그리고 URL 자체가 없을 때 둘 다 사용할 수 있습니다. 줄 데이터가 없는 것인지, api에서 리소스가 없는 것인지 분리를 하는게 맞는 것 같습니다.
- 로깅 라이브러리는 log4j2, logback, log4j 등등 다양하게 있는데 차이점에 대해 공부해보면 좋습니다. 로깅 레벨을 제어해서 어떤 레벨까지 노출시킬지 정할 수 있습니다. 지금은 에러를 처리하는 것이니 error를 찍는 것이 맞습니다.
- dao랑 controller랑 함수명이 달라야합니다. 실제로 하는 일이 다릅니다.
- addDao의 경우 하나의 dao에서 update를 두번하고 있습니다. 서비스에서 각각 호출하게 하는게 맞습니다. 하나의 dao에서는 하나의 쿼리만 날리는게 좋습니다.
- 컨트롤러에서 reservationEmailCount를 더 추상화해서 존재하는지 안하는지로 변수명 수정하는게 나을 것 같습니다. db에서의 데이터는 점점 추상화되어야 합니다.
- 로그인 처리하는데 쿠키랑 세션 다 쓸 필요가 없습니다. 세션을 사용해보세요 JSP에서 세션값을 참조할 수 있는 방법이 있습니다
- setCancel 네이밍 대신 cancel만 써도 될 것 같습니다. transaction처리도 고민해보세요.
- cancelReservation에 modifyDate는 쿼리문에 하는게 좋을 것 같습니다. 서버 시간과 db 시간 차이가 날 수 있습니다. now와 currentTimeStamp 대신 now를 써야하는데, 한 쿼리문에 now가 여러 개 있어도 일관성을 보입니다.
- Validator에서 service의 직접적인 파라미터를 검증하는 것은 service에 놔두고, 나머지 범용적인 이름, 이메일, 핸드폰 번호를 체크하는 것은 common으로 빼서 다른 곳에서도 쓸 수 있게 하면 좋을 것 같습니다.
→ validator를 static클래스로 관리하는게 좋을까요 또는 componentscan을 붙여서 빈으로 관리하는게 좋을까요? 예전에는 static으로 썼지만, 사실 실무에서 애초에 Validator를 잘 안만들고 라이브러리를 씁니다. 이 경우 스프링 컨테이너가 관리해도 좋을 것 같습니다.
-
IOException을 던지고 있는데, IOException은 checked 로직으로 다른 곳에 던지지 않고 처리를 해야합니다. 또한 IO 관련 객체들은 꼭 close를 해줘야합니다. 이것 관련해서 예외에 대해서도 공부해보시고, 스트림, 그리고 데코레이터 패턴에 대해서도 공부를 해보세요.
-
NotValid보다는 Invalid가 낫습니다.
-
이미지를 넣고, db insert를 하고 있는데 중간에 실패할 경우를 고려하면 db를 먼저 넣고 이미지를 넣으면 삭제 로직을 넣지 않아도 되어 나을 것 같습니다.
-
service의 valid 함수들 로직은 컨트롤러에 있는게 맞을 것 같습니다. request, response에 대한 처리를 컨트롤러에서 하는 추세입니다. 컨트롤러에서 어노테이션만 달아서 처리해주는 라이브러리도 많습니다.
-
예외를 던지면, 그 안에 왜 발생했고, 파라미터 값은 무엇인지 등등 자세한 상황 설명을 남겨야 로그로서 가치가 있습니다.
- .jsp에서 java.util.list import 빼는 것이 좋습니다 → import 했다는 것은 java를 쓰겠다는 것인데 관심 영역을 분리하는 것이 좋습니다. 나중에 규모가 커지면 분명 자바 코드에는 없는데 jsp에서 로직이 생겨서 찾기 어려운 경우도 생깁니다.
- remove()함수가 remove만 하는 것이 아니고 오히려 move에 가깝습니다. 네이밍을 다시 해보세요
- jsp에서 script 로드해주는 부분이 가장 아래에 있는데, 위치에 따라 동작이 달라질 수 있습니다. 어떻게 다른지 찾아보세요. 일반적으로 가장 밑에 두지만, 이런 싱글 페이지에서는 위에 둬도 상관 없기는 합니다.
- 객체.children[].children[] 이런 접근은 돔 객체가 바뀌면 코드가 동작을 안하게 됩니다.
- POST 방식 대신 PUT/PATCH 찾아보고 고민해보세요
- 글자가 길 때 화면상에서 처리하는 여러가지 방법이 있지만 특정 사이즈를 넘어가면 말줄임표로 나타내거나 마우스를 올리면 보여주는 방식, 길이 자체에 제약을 주는 방법들이 있습니다.
- httpRequest.open(, true) - true가 뭘 뜻하는 것인지 찾아보세요
- categoryId가 0인 것을 하드코딩 했는데, 이런 것을 매직넘버라고 합니다. 변수에 의미를 담아서 변수를 노출시켜주면 가독성이 더 좋아질 것입니다.
- querySelector에서 더 명확하게 접근할 수 있게 클래스를 붙이는게 좋아보입니다.
- arrow function은 익스플로러에서 지원이 안됩니다. 참고로 알아두세요
- event를 계속 넘기는 건 지양해주세요. 이벤트는 호출한 주체를 가리키는데, 이것은 언제든지 바뀔 수 있습니다. 그냥 호출한 부분에서 처리하는게 낫습니다.
- delete라는 변수명은 실제로 서버에서 삭제하는 것처럼 보입니다 초기화나 비운다를 나타내는 네이밍이 더 좋아보입니다.
- while문으로 자식 노드를 지울 수도 있지만, 한번에 지우는 방법도 있을 것입니다. while문은 무한루프를 돌 수 있으니 항상 조심하는 것이 좋습니다.
- 카멜 케이스롤 쓰서 상수를 나타내는 경우라면 const가 어울립니다.
- 만약 ProductImage를 가져올 때, 다른 곳에서 쓰지 않는다면 애초에 DB에서 필요한만큼만 가져오면 프론트에서 슬라이싱을 안해줘도 됩니다.
- 인터페이스에 public은 없어도 되는데 왜 그런지 찾아보세요.
- (detailpage.js) this 키워드를 많이 쓰셨는데, Js에서 this는 가변적인 값입니다. this를 쓸 때는 방어적으로 써야하고 확인을 해보고 사용하면 좋습니다.
- '=='를 쓸지 '==='를 쓸지 고민을 해보셔야하는데, 가능하면 정확하게 쓰는게 좋습니다.
- 날짜 포맷 관련해서는 프론트 단에서 가공을 하는게 맞습니다. api는 제공자의 입장에서 범용적으로 제공하는 것입니다.
- (reservation.js) priceTypeNameMapper는 js에서 관리하기 보다, DB에서 setup하던지 java에서 enum으로 하는게 좋을 거 같습니다. 만약 db의 내용이 바뀌어서 프론트의 코드도 바뀌어야하는 것은 좋지 않습니다.
- 좌우 스크롤이 생겼는데, 유저 입장에서는 안생기는게 나을 것 같습니다
- 푸터의 위치가 고정이어야합니다. 가운데 엘리먼트는 스크롤을 주면 푸터는 고정할 수 있습니다.
- 헤더와 푸터가 반복되고 있는데, 중복 코드를 생성하고 있는 것입니다. 별도로 빼서 include하는 형식으로 수정 가능합니다.
- button으로 했는데 앵커태그로 하는 것이 의미가 더 명확합니다 (다른 곳으로 이동하는 기능이기 때문에). 앵커태그로 하고, 손가락 모양으로 바뀌는 css를 적용할 수 있습니다.
- 이미지 태그에서 접근성에 대해 찾아보세요. 대체 텍스트는 적절하게 지어주세요. 시각 장애인 분들은 소리로 alt 내용을 듣습니다.
- css 파일 참조에 호스트나 포트를 포함하면 변경시 코드도 변경해야 합니다. 파일 경로로 참조하는 것이 바람직합니다.
- cdn보다는 라이브러리를 직접 다운받아 정적리소스를 관리하는 것이 유지 보수 측면에서 좋습니다. → Content Delivery Network의 경우 CDN 제공 서버에 문제가 생기면 서비스 제공 서비스까지 문제가 생길 수 있다.
- form안에 label의 역할에 대해 잘 알아보세요. input id와 같아야 label을 클릭하면 커서가 생깁니다. → input의 id와 label의 for를 일치시키면 input 자체에 포커스를 맞출 수 있다. 모바일 유저들에게 이점이 특히 더 커진다.
- 이전 버튼을 누르면 이전으로 가야합니다. 메인이 아닐 수도 있습니다.
- 내용 지우기를 할 때 페이지를 새로 로딩하는 것은 비용이 매우 비쌉니다. 다른 방법을 찾아보세요
-
PUT / PATCH 차이점 → PUT: 리소스의 모든 것을 업데이트한다. 따라서 기존 리소스가 name, age라는 속성을 가지고 있는데 age만 보내면 name은 없어진다. 그리고 리소스가 없는 경우 신규 리소스를 생성해서 넣어준 다. → PATCH: 리소스를 부분 변경한다. 지금 상황에서는 type만 바꾸는 것이므로 patch가 더 적절하다. 하지만 서블릿 3.1에 patch가 구현이 안되어있으니 (구현하고자하면 service() 함수를 응용하여구현할 수 있다) 우선은 post를 쓰고 다음 프로젝트부터 적절하게 사용하자.
-
/x-www-form-urlencoded → 데이터를 인코딩하는 방식의 일종이다. '&'으로 분리하고 "=" 기호로 값과 키를 연결하는, key-value tuple로 인코딩하는 방식이다. name=ted&age=40 이런 형식의 데이터로 들어오는 방식이 다. 'x-www-form-urlencoded'는 디폴트로 사용되고, 대량의 데이터나 바이너리 데이터를 전송할 때는 'multiplart/form-data' 인코딩 방식이 사용된다.
-
의존성 주입을 받는 방법들과 각각 장단점들 → 1. 필드 주입. 필드에 단순히 @Autowired를 붙이는 것이다. 코드가 간결하지만, DI 프레임워크에 매우 의존적이어서 좋지 않다. 따라서 테스트하기도 힘들다. 스프링 설정을 목적으로 하는 Configuration에서 제한적으로 사용하자. → 2. Setter 주입. setter 메서드를 통해서 의존관계를 주입하는 방식이다. Setter를 이용하게되면 불필요하게 수정의 가능성을 열어 놓게 되고, 세터 메서를 사용해서 필요한 의존 객체를 전달하지 않아도 빈 객체가 생성되기 때문에 객체를 사용하는 시점에 NullPointerException이 발생할 수 있다. → 3. 생성자 주입 객체를 생성하는 시점에 필요한 의존 관계가 주입되도록 생성자에서 주입 받는 것이다. 필드 객체에 final 키워드를 사용하면, 컴파일 시점에 누락된 의존성을 확인할 수 있고, 불변성을 가 제기 된다. 또한 순환 참조 에러가 있으면 애플리케이션 구동 시점에서 에러를 알 수 있는 장점이 있다. 가장 권장되는 방식이다.
-
httpRequest.open(, true) - true가 뭘 뜻하는 것인지 → open() 메소드의 세 번째 파라미터는 요구가 비동기식으로 처리될지를 결정하는데, true는 기본값으로 생략이 가능하다. (https://developer.mozilla.org/ko/docs/Web/Guide/AJAX /Getting_Started)
-
DBMS 다양한 Join 방식과, 그 방식에 따른 드라이빙 테이블 선택, 워크벤치에서 EXPLAIN 해석 방법 → 1. DBMS는 Optimizer를 통해서 쿼리문을 최적화하고, Workbench에서는 그 실행 계획을 쉽게 도식화 된 것으로 확인할 수 있다 (https://engineering.linecorp.com/ko/blog/mysqlworkbench- visual-explain-index/). 일반적으로 도식화 되었을 때 색깔이 초록색이 가장 효율이 좋은 것이고, 빨간색과 검은색이 안좋은 것이다. 이번 프로젝트에서 Product를 조회하는 SQL을 짰는 데, 테이블들의 순서를 바꿔봐도 EXPLAIN의 도식화는 바뀌지 않았다. 특히, Full Index Scan은 바뀌지 않았는데, product의 id에 인덱스를 설정하지 않아서 아이디 하나하나를 스캔하고, DBMS가 알 아서 최적화를 진행했기 때문이라고 생각한다.
→ 2. Nested-Loop Join은 선행테이블(Driving Table)의 행을 하나씩 접근하여, 그것을 안의 Inner Loop과 결합하는 방식이다. Driving Table와 인덱스 유무에 성능에서 많은 차이가 난다. 코드로 비유하자면 테이블 하나당 for문이 생성되는 것과 같다. 처리할 양이 적은 경우에는 오히려 다른 Join보다 나은 성능을 보이기도 한다.
Block Nested-Loop Join은 Nested-Loop Join이 한 행씩 접근하는 것의 단점을 보안한 방식인데, Buffer에 여러개의 행을 가져와서 Inner Loop과 조인을 하게된다. 그만큼 Inner Loop에서는 바깥 루프에 적게 접근해도 된다는 장점이 생긴다.
이 외에도 MySQL 8부터 Hash Join, MySQL 7부터 Index Merge Join등이 도입되었다.
- 인터페이스와 추상 클래스 → 인터페이스와 추상 클래스 둘 다 추상화를 도와주는 개념이다. 원래는 인터페이스에는 추상 메서드만 선언할 수 있었는데, JDK 1.8부터 인터페이스에 디폴트 메서드와 static 메서드가 추가 가능하게 되었다. "implements"를 사용하는지 "extends"를 사용하는지, 디폴트가 "final"인지 아닌지 등등 문법적 차이가 있다 (https://www.geeksforgeeks.org/difference-between-abstract-class- and-interface-in-java/).
하지만 가장 큰 차이점은 사용 목적에 있다. 추상 클래스는 말 그대로 확장, 상속을 의미함으로서 물려주는 개념이 된다. 그렇게 부모-자식 관계를 가지게 된다. 반면 인터페이스는 원래 뜻인 '서로 다른 두 개의 시스템을 이어주는 경계면'을 따른다. 즉 서로 다른 시스템을 연결하기 위해, 동일한 동작을 위한 구현을 강제화하는 목적을 가진다.
-
트랜잭션 -> 참고: https://goddaehee.tistory.com/167
-
빌더 패턴 → 빌더 패턴은 복잡한 객체를 생성하는 방법을 정의하는 클래스와 표현하는 방법을 정의하는 클래스를 별도로 분리하여, 서로 다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공하는 패턴이 다. 만약 빌더 패턴을 사용하지 않으면 클래스의 필드가 여러개 있을 때, 생성자의 파라미터가 점점 늘어나게 된다. 또한 어떤 값이 null로 들어간다면 그 경우마다 생성자를 정의해줘야하고, 생성자에 null이 들어가면 뭐가 null인지 가독성이 떨어진다.
빌더 패턴의 구현은 아래의 링크에 정리되어있다. https://johngrib.github.io/wiki/builder-pattern/
빌더 패턴의 단점은, 빌더라는 다른 클래스를 생성해야하기 때문에 부가적인 메모리가 필요하고 코드양이 늘어난다. 또한 객체를 수정해야하는 상황이 생기면 결국 setter도 사용하게되어 비효율적이다.
- Collections.EMPTY_LIST, Collection.emptyList() → 쿼리 조회 후 결과 값이 없을 때 반환할 수 있는 것들이 몇 개 있다. 그 중 처음 사용했던 방식은 null값 반환이었다. 하지만 null 값 반환은 결국 다른 쪽에서 null check를 해주지 않으면 NullPointerException이 발생하게되는 단점이 있다. 그 다음 찾은 방법은 new ArrayList를 반환해주는 방식이었다. 이 방식은 결국 값이 없는 것을 나타내는 것인데 메모리를 차지하므로 성능상 손해를 본다.
Collections.EMPTY_LIST는 immutable이기에 변경하려하면 예외를 던지며, 싱글톤으로 관리되기에 메모리 낭비를 막을 수 있다.
Collections.EMPTY_LIST보다 Collections.emptyList()가 나은데, Collections.EMPTY_LIST는 type-safe하지 않다. 반면, Collections.emptyList()는 List를 반환한다.
- 스프링에서 예외처리하는 방법 (2~3가지) → 스프링에서 예외 발생은 크게 두 곳에서 발생한다. 하나는 Dispatcher Servlet 내(Controller, Service, Repository..)에서 발생하는 것이고, 하나는 DispatcherServlet 전에 발생한다. 스프링 MVC에서 에러의 대다수는 DispatcherServlet 내에서 발생한다. DispatcherServlet 내에서 발생하는 에러의 예외처리를 알아봤다. 예외 처리 방법
1 @ExceptionHandler 컨트롤러에서 발생한 익셉션을 직접 처리하는 방법이다. 컨트롤러와 마찬가지로 뷰 일므을 리턴할 수 있다. 기본으로 제공하는 ExceptionResolver 중 우선 순위가 가장 높다. 다만 하나의 컨트롤러에 정상 코드와 예외 처리코드가 같이 존재하게 된다는 단점이 있다.
-
@ControllerAdvice, @RestControllerAdvice 대상을 지정하지 않으면 모든 컨트롤러에 적용된다.
-
try-catch 각 메서드마다 try-catch를 적용하면 되지만, 코드의 양이 엄청 늘어날 뿐만 아니라 성공 로직과 실패 로직이 뒤섞여 있어 가독성과 유지보수에 좋지 않다.
-
NullPointerException 처리 방법들 (try-catch, Optional..) 1 Try-Catch 위에서 나온 것처럼 try-catch를 변수 사용 때마다 붙인다면 코드의 양이 많아지고, 성공 로직과 실패 로직이 섞여있어서 좋지 않다. 2 if (variable != null) 객체 안에 객체가 겹겹이 있는 구조라면 이 방법 역시 수 많은 if 문들을 적어야 한다.
-
Optional 자바8부터 사용할 수 있는데, null이 될 수도 있는 객체를 감싸고 있는 일종의 래퍼 클래스이다. Optional을 사용함으로서 얻는 장점은 null을 직접 다루지 않아도 되고, 명시적으로 해당 변수가 null일 수 도 있음을 나타낼 수 있다는 점이다.