티스토리 뷰
대부분의 언어는 값이 할당되지 않은 변수의 기본값으로 null을 할당한다. 자바에서는 참조변수들의 기본값이 NULL이며, 업무를 하다보면 널 포인터 예외(Null Pointer Exception)은 자주 마주치게 되는 Exception이다.
처음에는 NPE라는 용어도 낯설었는데, NPE를 null pointer exception의 줄임말로 입에 붙어 사용하는 지금은 업무중 발생하는 에러 중 "이 변수에는 값이 할당돼 있지 않을 수가 없는데" 하는 상황을 마주하게 된다.
변수가 널 값을 갖지 않았는지 검사하는 아래와 같은 코드들을 수없이 발견할 수 있다.(현재 작업중인 프로젝트에서)
if(Object != null)
jdk 1.7버전으로 jdk1.8부터 지원하기 시작한 Optional도 사용하지 않고 1.7환경에서 작업하다보니 그런게 있다는 것조차 잊고 있었다.
하지만 요즘 언어 추세가 null값 자체를 할당하지 않도록, 갖을 수 없도록 만들어가고 있다. Optional이란것을 통해 보완할 수 있다고 들었고, 요즘 배우기 시작한 Rust에서도 null값을 아예 방지한다.
우리는 이런 상황을 마주하게 된다면,
변수가 널값을 갖지 않았는지 검사하거나, 널 객체 패턴(null object pattern)이나 옵션타입(option type)등을 사용해서 널 포인터 예외를 방지할 수 있다.
실무에서 널 객체 패턴이 얼마나 사용되고 있는지 나의 매우 적은 실무 경험으로는 잘 모르겠다. 적어도 현재 업무에서는 아쉽게도 널 객체 패턴이란 찾아볼 수 없다는 점이다..
널 객체(오브젝트) 패턴 이란 무엇일까?
자바에서 변수가 선언되어있고 여기에 값이 할당되지 않은 상태에서 변수를 참조하면 우리가 잘 알고있는 NULL POINTER EXCEPTION이 발생된다. 의도하지 않았던 unchecked exception이 발생되기 때문에 시스템이 오류상황을 미리 알기 어렵게 된다. NULL OBJECT PATTERN은 이와같이 값이 NULL일 때 발생할 수 있는 문제를 최대한 방어하기 위한 패턴이다.
먼저 계정 정보를 반환하는 service 함수가 있다고 할 때, getById(String id) 메서드를 호출시 계정 정보가 없다면 null 을 반환 하는게 일반적인 함수 구현 방식인데 이때 null 을 반환 하는게 아니라 널 오브젝트를 반환하는게 이 패턴의 핵심 이다.
널 오브젝트는 내부에는 아무런 값이 들어있지 않은 상태이지만 getById() 메서드는 최소한 null을 반환하지는 않게 된다.
널 오브젝트를 이용하면 비즈니스 로직에서 null에 대한 신경을 쓰지 않고도 유효한 객체를 반환한다는 것을 보장해 줄 수 있다는 것을 의미한다. 이 때 반환된 널 오브젝트는 아무런 동작을 하지 않는다.
- 널오브젝트 패턴은 반환값이 항상 유효한 객체를 반환해 줌을 보장해 줄 수 있다.
- 널오브젝트는 대상 구현체와 같은 인터페이스를 구현 한다.
이렇게 널오브젝트 패턴을 적용해서 NPE를 방지할 수 있다.
하지만 자바8부터 지원하기 시작한 Optional을 이용하면 보다 쉽게 null 값에 대한 방어를 할 수 있다.
Optional 이란?
: 값이 존재 할 수도, 존재하지 않을 수도 있는 값을 포장한 객체
런타임에서 발생하는 NullPointException 방어를 위해 만들어둔 로직체크는 코드의 가독성과 유지 보수성이 떨어진다. 어떻게 null 을 다루면 좋을 지에 대한 해결책을 함수형 언어에서 찾았다. 함수형 언어는 존재하지 않을 수도 있는 값에 대한 별도의 타입을 가지고 있다. 개발자들은 여러가지 API 를 통해 간접적으로 값에 접근할 수 있다. 자바는 함수형 언어로부터 영감을 받아 자바 8에 처음 Optional 이 도입 되었다.
Optional은 Null 이 될 가능성을 가진 값을 객체로 감싸는 래퍼 클래스다. 즉, Optional 에 포장된 객체는 하나의 원소 혹은 Null 원소가 되는 것을 뜻한다. Null 을 직접 다루면 위험한 상황이 발생하거나 굉장히 까다롭다. 이를 Optional 객체에 포장함으로써 유연한 처리가 가능해 진다. Null 을 Optional 에 포장하게 되면 Null 을 값으로 보고 로직을 구현할 수 있다.
null 값에 대한 처리를 찾아보다 보니, Objects.isNull(), Objects.nonNull(), Objects.requireNonNull() 에 대한 메서드들을 마주하게 되었다.
- Objects.isNull() - isNull() 메서드는 매개값이 null인 경우 true를 return한다.
- Objects.nonNull() - nonNull() 메서드는 매개값이 not null일 경우 true를 return한다.
- Objects.requireNonNull() - requireNonNull() 메서드는 세가지로 오버라이딩을 할 수 있다.
requireNonNull 로 널 체크를 하고, 사용하는 이유는 무엇일까?
requireNonNull은 자바7에 추가된 Object 클래스에서 제공하는 널 체크를 위한 메소드이다. 파라미터 로 입력된 값이 null이라면 NPE가 발생하고, 그렇지 않다면 입력값을 그대로 반환하는 메소드이다.
사용법
첫번째 메소드는 null 을 전달하면 메세지가 비어있는 NPE 예외를 던진다.
Objects.requireNonNull(null);
// java.lang.NullPointerException
두번째 메소드는 null 을 전달하면, 두번째 파라미터로 전달한 문자열을 메세지로 갖는 NPE 예외를 던진다.
Objects.requireNonNull(null, "null은 전달될 수 없습니다!");
// java.lang.NullPointerException: null은 전달될 수 없습니다!
세번째 메소드는 null 을 전달하면, 두번째 파라미터로 전달한 Supplier 를 구현한 익명 함수의 반환값을 메세지로 갖는 NPE 예외를 던진다.
Objects.requireNonNull(null, () -> "null은 전달될 수 없습니다!");
// java.lang.NullPointerException: null은 전달될 수 없습니다!
requireNonNull 을 사용하는 이유
=> 빠른 null 감지, 명시성, 가독성
@NotNull
lombok에서 지원하는 @NotNull 어노테이션은 이름 그대로 Null만 허용하지 않는다. "" 이나 " " 은 허용한다.
이러한 방식을 사용하여 null값의 사용을 피해 장애에 대비하기 위한 방어적 프로그래밍을 하도록 해야한다.
'ALL' 카테고리의 다른 글
깃 소스트리 fatal: bad config line 1 in file C:/Users/.... (0) | 2023.10.17 |
---|---|
[Conda-Jupyter] 맥 Conda 가상환경 과 Jupyter Kernel (2) | 2023.10.04 |
[Linux] 리눅스 서버 설치, Linux 파일시스템 RIAD-1, RAID-5 (0) | 2023.07.04 |
[Rust] macOS / 리눅스에 설치 (0) | 2023.06.30 |
jsp내에서 JSTL과 스트립트의 실행 시점 (0) | 2023.04.25 |
- Total
- Today
- Yesterday
- Node.js
- spring
- 컨테이너
- 리액트
- 스프링
- 데브캠프
- @Configuration
- 객체지향
- MySQL
- 이정환
- 친절한SQL튜닝
- 데이터베이스
- 자바스크립트
- di
- 스프링의정석
- 한입크기로 잘라먹는 리액트
- React
- 인덱스
- 시큐리티
- 스프링 빈
- 스프링 프로젝트
- 남궁성
- 자바의정석
- JavaScript
- EC2
- node
- Spark
- security
- 코드로 배우는 스프링 웹 프로젝트
- AWS
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |