목차

  1. 예시
  2. Stream.java를 읽어봅시다.
  3. 마치며

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

예시

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

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

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

1
2
3
4
5
6
7
8
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를 타게되므로 “널이에요”가 출력되겠지?

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

1
2
3
4
5
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를 발생시킵니다.

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

1
2
3
4
5
6
7
8
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를 추가하면 어떻게 될까요?

1
2
3
4
5
6
7
8
9
10
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가 발생됩니다.

마치며

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