본문 바로가기

테크 노트/소소한 개발 팁

java, stream api에서 NPE 발생 주의

java stream api를 많이 사용하실텐데요.
예상치 못하게 NullPointerException 발생을 맞이하는 경우가 있어서 정리해보고자 합니다.

 

예시

SimpleEntry<String, String> keyValue = new SimpleEntry("test", null);
System.out.println(keyValue.getValue());

SimpleEntry는 java.util의 key - value를 담을 수 있는 클래스입니다.
(HashMap에서 사용하는 그것)

위를 실행하면 어떤 결과가 나올까요?
네. 예상하신것 처럼 "null"입니다.

SimpleEntry<String, String> keyValue = new SimpleEntry<>("test", null);
List<SimpleEntry<String, String>> list = Arrays.asList(keyValue);
Object aNull = list.stream()
		.map(e -> e.getValue())
		.findAny()
		.orElse("널이에요");
        
System.out.println(aNull);

그렇다면 위의 예시의 결과는 뭘까요?

훗..
list는 SimpleEntry 1개로 이루어진 리스트이고
그 list에서 stream api를 이용하는데
거기서 e.getValue()를 호출했고, 그게 null이니
orElse를 타게되므로 "널이에요"가 출력되겠지?

하지만 결과는 그렇지 않습니다.

Exception in thread "main" java.lang.NullPointerException
	at java.util.Objects.requireNonNull(Objects.java:203)
	at java.util.Optional.<init>(Optional.java:96)
	at java.util.Optional.of(Optional.java:108)
    ...

???

 

Stream.java를 읽어봅시다.

Stream.java의 findAny 선언 부분인데요. 위와같은 설명이 써있습니다.
findFirst도 동일하게 NPE를 발생시킵니다.

그럼 아래와 같은 상황은 어떨까요?

List<SimpleEntry<String, String>> list = Arrays.asList(
	new SimpleEntry<>("test2", "notnull"), new SimpleEntry<>("test", null));
    
Object aNull = list.stream()
		.map(e -> e.getValue())
		.findAny()
		.orElse("널이에요");
System.out.println(aNull);

이 상황에도 NPE가 발생될까요?
아닙니다. null을 취하지 않으면 발생하지 않습니다.
(위를 findFirst()로 변경해도 동일합니다.)

그럼 아래처럼 filter를 추가하면 어떻게 될까요?

List<SimpleEntry<String, String>> list = Arrays.asList(
	new SimpleEntry<>("test2", "notnull"), new SimpleEntry<>("test", null));
    
Object aNull = list.stream()
		// 필터추가
		.filter(e -> "test".equalsIgnoreCase(e.getKey()))
		.map(e -> e.getValue())
		.findAny()
		.orElse("널이에요");
System.out.println(aNull);

위의 경우 null을 취하는 상황이 되므로 역시 NPE가 발생됩니다.

 

마치며

이 역시 별거 아닌것 같지만
버그는 항상 사소한것 부터 오는것이므로 조심합시다.