반응형
가독성 높이는 습관 - null 핸들링
null check - 단정문 (Assertion)
assert expression;
assert expression1; expression2;
- JDK 1.4+
- expression1이 거짓이면, java.lang.AssertionError 발생
- espression2는 위 에러에 포함될 정보
- 단정문을 활성화하려면, jaca -ea 옵션을 주어야함
- 사용하지 말 것 !
null check - Objects (JDK 1.8+)
Boolean Check
- boolean isNull(Object obj);
- boolean nonNull(Object obj);
Fail Fast
- T requireNonNull(T obj)
- T requireNonNull(T obj, String message)
- T requireNonNull(T obj, Supplier<String> messageSupplier)
public static boolean isNull(Object obj) {
return obj == null;
}
public static boolean NonNull(Object obj) {
return obj != null;
}
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
null 표현하기 - 타입
Primitive type
- boolean
- char
- int
- long
- float
- double
Reference type
- 기본 타입의 Wrapper class
두 가지 모두 null이 될 수 없다는 특징이 있지만, 메모리 위치가 다름
- 기본 타입은 메모리의 스택 영역에 위치
- 레퍼런스 타입은 스택 영역에는 참조값만 존재하고 데이터는 힙 영역에 위치
Primitive, Reference type으로 표현해보기
- A가 B에게 포인트를 선물하는 API의 Request 객체 만들기
public class GiftPointRequest {
// primitive type -> !null
private long userId;
private long point;
// class type
private String memo;
private Object type;
}
null 표현하기 - 다른 언어 사례 (Kotlin)
var str: String = "null 불가능한 타입"
var nullableStr: String? = "nullable 타입"
str = null // 컴파일 에러
nullableStr = null // ok
println(str.length)
println(nullableStr?.length) // safe call
// elvis operator
println(nullableStr?.length ?: 0)
println(nullableStr?.length ?: throw RuntimeException("문자열이 비었습니다."))
그 밖의 null 핸들링 방법들
- 1. 선언과 동시에 초기화
- 2. 다양한 유틸클래스 활용 (스프링, 구아바, 아파치 커먼즈, ...)
- 3. null 파라미터가 존재한다면, 오버로딩으로 교체
- 4. List<T> 일 때는 빈 리스트 활용
- 5. 상황에 따른 Null Object Pattern 활용
- 최대한 직접적인 핸들링은 지양
선언과 동시에 초기화
// C style
Long getCalcAmount(long pid, long cid) {
Product product = null;
Coupon coupon = null;
long amount = 0;
product = findProduct(pid);
coupon = findCoupon(cid);
amount = coupon.discount(product);
return amount;
}
// 선언과 동시에 초기화
Long getCalcAmount(long pid, long cid) {
Product product = findProduct(pid);
Coupon coupon = findCoupon(cid);
long amount = coupon.discount(product);
return amount;
}
null 파라미터 대신 오버로딩
// 잘못된 코드
Product findProduct(Long refId, String somethingStr, Long otherId ...) {
if (refId != null)
return repository.findByRefId(refId);
else if (somethingStr != null && otherId != null)
return repository.findBySomethingStrAndOtherId(somethingSter, otherId);
// ... 생략
}
Product findProduct(Long refId) {
return repository.findByRefId(refId);
}
Product findProduct(String somethingStr, Long otherId) {
return repository.findBySomethingStrAndOtherId(refId);
}
비어있는 리스트 활용
List<Coffee> getCoffeeList(/* something parameter */) {
if (invalid())
return null;
// 비지니스 로직 수행
return coffeeList; // 로직 결과
}
// 위 메서드를 사용하는 곳에서
List<Coffee> coffeeList = getCoffeeList();
if (coffeeList != null)
// 비지니스 로직 수행
List<Coffee> getCoffeeList(/* something parameter */) {
if (invalid())
return Collections.emptyList();
// 비지니스 로직 수행
return coffeeList; // 로직 결과
}
// 위 메서드를 사용하는 곳에서
getCoffeeList()
.stream()
// 비지니스 로직 수행
Null Object Pattern
정리
- 선언과 동시에 초기화가 최고 (null 발생하지 않도록)
- Assertion 문은 사용하지 말자
- Null은 되도록 직접 핸들링 하지말자
- JDK 1.8+ 에서 제공하는 유틸을 적극 활용 (Objects)
- Primitive type, Reference type 으로 nullable 여부 나타내기
- List 는 null 대신 emptyList() 사용
- null 을 대체할 static 객체 리턴 (null object pattern)
반응형
'cs > java-spring-boot' 카테고리의 다른 글
[Zero-base] 9-11. Optional 제대로 사용하기 (0) | 2022.03.17 |
---|---|
[Zero-base] 9-10. Optional 살펴보기 + Java 8 : functional interface (0) | 2022.03.16 |
[Zero-base] 9-8. null (0) | 2022.03.16 |
[Zero-base] 9-7. enum (0) | 2022.03.16 |
[Zero-base] 9-6. 캡슐화 (0) | 2022.03.16 |