Programing

findFirst ()가 찾은 첫 번째 요소가 null 인 경우 NullPointerException이 발생하는 이유는 무엇입니까?

lottogame 2020. 10. 17. 08:59
반응형

findFirst ()가 찾은 첫 번째 요소가 null 인 경우 NullPointerException이 발생하는 이유는 무엇입니까?


이것은 왜 던지는가 java.lang.NullPointerException?

List<String> strings = new ArrayList<>();
        strings.add(null);
        strings.add("test");

        String firstString = strings.stream()
                .findFirst()      // Exception thrown here
                .orElse("StringWhenListIsEmpty");
                //.orElse(null);  // Changing the `orElse()` to avoid ambiguity

첫 번째 항목 stringsIS null완벽하게 허용되는 값이다. 또한 s 를 처리 할 수 있는 것이 훨씬 더 의미 findFirst()있는 Optional을 반환합니다 .findFirst()null

편집 : orElse()덜 모호하도록 업데이트했습니다 .


그 이유 Optional<T>는 반환에 사용하기 때문입니다 . 선택 사항은을 포함 할 수 없습니다 null. 기본적으로 "거기"와 "거기"로 설정되어있는 상황을 구분하는 방법을 제공하지 않습니다 null.

이것이 문서null 가에서 선택 될 때 상황을 명시 적으로 금지하는 이유 입니다 findFirst().

던졌습니다 :

NullPointerException -선택한 요소가 null


마찬가지로 이미 논의 의 API 디자이너는 개발자가 치료를 원하는 가정하지 않는 null값과없는 값 같은 방법으로.

그래도 그렇게하려면 시퀀스를 적용하여 명시 적으로 수행 할 수 있습니다.

.map(Optional::ofNullable).findFirst().flatMap(Function.identity())

스트림에. 첫 번째 요소가 없거나 첫 번째 요소가 인 경우 결과는 두 경우 모두 빈 선택 사항입니다 null. 따라서 귀하의 경우에는

String firstString = strings.stream()
    .map(Optional::ofNullable).findFirst().flatMap(Function.identity())
    .orElse(null);

의 GET에 null첫 번째 요소 중 하나 없거나 경우 값을 null.

이러한 경우를 구별하려면 다음 flatMap단계 를 생략하면됩니다 .

Optional<String> firstString = strings.stream()
    .map(Optional::ofNullable).findFirst().orElse(null);
System.out.println(firstString==null? "no such element":
                   firstString.orElse("first element is null"));

이것은 업데이트 된 질문과 크게 다르지 않습니다. 당신은 교체해야 "no such element""StringWhenListIsEmpty""first element is null"함께 null. 그러나 조건문이 마음에 들지 않으면 다음과 같이 수행 할 수도 있습니다.

String firstString = strings.stream().skip(0)
    .map(Optional::ofNullable).findFirst()
    .orElseGet(()->Optional.of("StringWhenListIsEmpty"))
    .orElse(null);

이제 firstString이 될 것이다 null요소가 존재하지만 경우 null그것이 될 것입니다 "StringWhenListIsEmpty"어떤 요소가 존재하지 않는 경우.


다음 코드을 대체 findFirst()limit(1)대체합니다 orElse()reduce():

String firstString = strings.
   stream().
   limit(1).
   reduce("StringWhenListIsEmpty", (first, second) -> second);

limit()하나의 요소 만에 도달 할 수 있습니다 reduce. BinaryOperator에 전달 reduce한 요소 또는 다른 그 반환 "StringWhenListIsEmpty"에 요소가 도달하지 않는 경우 reduce.

이 솔루션 OptionalBinaryOperator장점은 할당되지 않고 람다가 아무것도 할당하지 않는다는 것입니다.


java.util.Objects.nonNull찾기 전에 목록을 필터링하는 데 사용할 수 있습니다.

something like

list.stream().filter(Objects::nonNull).findFirst();

Optional is supposed to be a "value" type. (read the fine print in javadoc:) JVM could even replace all Optional<Foo> with just Foo, removing all boxing and unboxing costs. A null Foo means an empty Optional<Foo>.

It is a possible design to allow Optional with null value, without adding a boolean flag - just add a sentinel object. (could even use this as sentinel; see Throwable.cause)

The decision that Optional cannot wrap null is not based on runtime cost. This was a hugely contended issue and you need to dig the mailing lists. The decision is not convincing to everybody.

In any case, since Optional cannot wrap null value, it pushes us in a corner in cases like findFirst. They must have reasoned that null values are very rare (it was even considered that Stream should bar null values), therefore it is more convenient to throw exception on null values instead of on empty streams.

A workaround is to box null, e.g.

class Box<T>
    static Box<T> of(T value){ .. }

Optional<Box<String>> first = stream.map(Box::of).findFirst();

(They say the solution to every OOP problem is to introduce another type :)

참고URL : https://stackoverflow.com/questions/32466799/why-does-findfirst-throw-a-nullpointerexception-if-the-first-element-it-finds

반응형