IDE에서 "Method invocation may produce NullPointerException" 경고 메시지를 발견했다.
왜 이런 Warning이 표시되는가?
Method invocation '~~~' may produce NullPointerException 경고를 해석해 보면 메서드 호출 시 NullPointerException이 발생할 수 있다는 것을 의미한다.
저의 경우엔 getString() 메서드를 호출할 때 paramters 객체가 null일 수도 있다는 말인데.. 사실 위 코드는 Spring에서 제공하는 인터페이스를 활용하는 거라 JobParameters가 null일 수가 없는 코드이기는 했다. IDE가 이런 메시지를 나타내는게 이해가 안 되긴 하지만, 좀 생각해 보니 getString()를 호출했을때 특정 키에 해당하는 값이 없다면 null일 수도 있다는 것을 덕분에 인지하게 됐다.
결론적으로 해당 경고 메시지는 이번 경우처럼 객체 or 리턴 값이 null 상태일 가능성이 있기 때문인 것으로, 이 경고를 없앨 가장 기본적인 방법은 아래와 같이 명시적으로 체크하는 방법이 있겠다.
if (parameters != null)
String fileName = parameters.getString("fileName");
이처럼 null을 체크하는 다양한 방법이 있지만, 이 기회에 Java의 Optional을 사용하여 null 을 처리하는 방법을 정리해 봤다. 아래는 Optional 객체를 사용하는 코드로 수정한 건데, 주요 함수의 활용 방법을 알아보자.
@Override
public void validate(JobParameters parameters) throws JobParametersInvalidException {
String fileName =
Optional.ofNullable(parameters.getString("fileName"))
.orElseThrow(() -> new JobParametersInvalidException("fileName is missing or null"));
if ( !StringUtils.endsWithIgnoreCase(fileName, "xlsx") ) {
throw new JobParametersInvalidException("This is not Excel File");
}
}
Optional 객체의 메소드 활용법
Optional은 Java 8부터 추가된 유틸리티 클래스(java.util.Optional)로, null을 안전하게 처리하기 위한 객체이다. 다양한 메서드를 제공하기 때문에 이를 활용하면 실수를 방지하고 null 처리를 보다 유연하게 할 수 있다. 또한 메서드 체이닝이 가능하기에 잘 활용하면 가독성도 높일 수 있다. 다음은 Optional이 제공하는 주요 메서드들의 특징 및 예제이다.
1. Optional.of(T value)
파라미터인 value의 값이 존재하면 해당 값을 가진 Optional 객체를 반환한다. 만약 값이 null 이라면 NullPointerException이 발생한다.
String str = "Hello";
Optional<String> optionalStr = Optional.of(str); // 정상 동작
2. Optional.ofNullable(T value)
of()메소드와 비슷하지만, value 값이 null일 경우 예의를 발생시키는 것 아닌 Optional.empty()를 반환한다. Optional.empty()는 '비어 있는 Optional 객체'를 의미하는데, 이는 null을 대신하여 '값이 없음'을 표현하는 Optional의 방식이다.
Optional<String> firstOpt = Optional.ofNullable("Hello");
Optional<String> secondOpt = Optional.ofNullable(null);
System.out.println(firstOpt); // output: Optional[Hello]
System.out.println(secondOpt); // output: Optional.empty
즉, 변수 firstOpt은 값이 존재하기 때문에 해당 값을 포함하는 Optional 객체를 반환하며, 변수 secondOpt은 null이기 때문에 빈 Optional 객체인 Optional.empty를 반환한다. 다음은 Optional 객체의 실제 값을 확인하는 방법들 중 일부이다.
// 방법 1: get()을 사용하여 값 가져오기 (값이 없으면 예외 발생)
String value = firstOpt.get();
System.out.println("Value는 " + value); // output: Value는 Hello
// 방법 2: ifPresent()를 사용하여 값이 있을 때만 출력
firstOpt.ifPresent(value -> System.out.println("Value는" + value));
3. orElse(T other)
파라미터 값이 존재하면 그 값을 반환하고, 값이 없으면 설정한 값을 반환한다. 즉, 초기화할 디폴트 값을 지정할 수 있다.
Optional<String> optionalStr = Optional.ofNullable(null);
String result = optionalStr.orElse("Default Value");
System.out.println(result); // Output: Default Value
4. orElseThrow(Supplier<? extends X> exceptionSupplier)
orElse()와 마찬가지로 파라미터 값이 존재하면 그 값을 반환하지만, 값이 없을 경우 변수를 할당하지 않고 그 즉시 예외를 발생한다. 예외는 설정한 예외로 throw 한다.
Optional<String> optionalStr = Optional.ofNullable(null);
String result = optionalStr.orElseThrow(() -> new IllegalStateException("No value present"));
5. isPresent()
객체가 값이 존재하면 true 반환하고, null이면 false를 반환한다. 비슷한 기능의 함수로 isEmpty()도 존재한다.
Optional<String> optionalStr = Optional.ofNullable(null);
// isPresent()를 사용하여 값이 존재하지 않는지 확인 (모든 Java 버전에서 가능)
if (optionalStr.isPresent()) {
System.out.println("Value exists: " + optionalStr.get());
} else {
// 해당 코드가 실행된다.
System.out.println("Value is null");
}
// isEmpty()를 사용하여 Optional.empty()인지 확인 (Java 11 이상)
if ( optionalStr.isEmpty() ) {
System.out.println("The value is Optional.empty()");
}
6. ifPresent(Consumer<? super T> action)
파라미터 값이 있을 때 특정 동작(Consumer)을 수행시킬 수 있다. ifPresent()의 파라미터 값이 없다면 예외가 발생하기 때문에, null이 전달되지 않도록 주의해야 한다.
Optional<String> optionalStr = Optional.of("Hello");
optionalStr.ifPresent(value -> System.out.println("Value는 " + value));
※ Consumer: Java의 함수형 인터페이스 중 하나로, 하나의 인자를 받아서 아무것도 반환하지 않는 함수
7. ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
첫 번째 파라미터 자리인 action의 값으로는 Optional 객체 내의 값이 존재할 때 실행할 동작을 함수형 인터페이스를 정의하고, 두 번째 emptyAction에는 값이 없을 때 실행할 동작을 정의한 Runnable 함수형 인터페이스를 정의하면 된다.
Optional<String> optionalValue = Optional.ofNullable("Hello");
optionalValue.ifPresentOrElse(
value -> System.out.println("Value는 " + value), // 값이 있을 때 실행
() -> System.out.println("No value present") // 값이 없을 때 실행
);
'Java' 카테고리의 다른 글
[OOP] 왜 Class가 아니라 Object Oriented Programming 일까? (0) | 2024.08.26 |
---|---|
경로(Path) 설정시 *, ** 차이 (0) | 2023.04.13 |
break와 return, continue 차이 및 특징 정리 (0) | 2019.02.15 |
Java String과 String Pool 및 메모리에 대한 정리 (0) | 2019.01.29 |