[java] null 값에 대한 jdk8 스트림을 관리하는 방법

안녕하세요, Java 개발자 여러분,

in advanceJDK8이 아직 출시되지 않았기 때문에 주제가 약간 다를 수 있다는 것을 알고 있지만 (지금은 아닙니다.) Lambda 표현식에 대한 기사, 특히 Stream으로 알려진 새로운 컬렉션 API와 관련된 부분을 읽고있었습니다.

다음은 Java Magazine 기사에 제공된 예입니다 (수달 개체 수 알고리즘입니다 ..).

Set<Otter> otters = getOtters();
System.out.println(otters.stream()
    .filter(o -> !o.isWild())
    .map(o -> o.getKeeper())
    .filter(k -> k.isFemale())
    .into(new ArrayList<>())
    .size());

내 질문은 Set 내부 반복 중간에 수달 중 하나가 null이면 어떻게됩니까?

NullPointerException이 발생할 것으로 예상하지만 이전 개발 패러다임 (비 기능적)에 여전히 갇혀있을 수 있습니다. 누군가이 문제를 어떻게 처리해야하는지 알려줄 수 있습니까?

이것이 정말로 NullPointerException을 던진다면,이 기능이 매우 위험하다고 생각하고 아래와 같이 만 사용해야합니다.

  • 개발자가 null 값이 없는지 확인합니다 (이전 .filter (o-> o! = null) 사용).
  • 개발자는 응용 프로그램이 처리 할 NullOtter 또는 특수 NullOtter 개체를 생성하지 않도록합니다.

가장 좋은 옵션 또는 다른 옵션은 무엇입니까?

감사!



답변

현재의 생각은 null을 “허용”하는 것으로 보입니다. 즉, 일부 작업은 덜 관대하고 결국 NPE를 던질 수 있지만 일반적으로이를 허용하는 것입니다. Lambda Libraries 전문가 그룹 메일 링리스트에서 null 에 대한 논의, 특히이 메시지를 참조하십시오 . 이후 옵션 # 3에 대한 합의가 나타났습니다 (Doug Lea의 주목할만한 반대). 네, NPE로 폭파되는 파이프 라인에 대한 OP의 우려는 유효합니다.

Tony Hoare가 null을 “Billion Dollar Mistake” 라고 언급 한 것은 아무것도 아닙니다 . null을 다루는 것은 진짜 고통입니다. 클래식 컬렉션 (람다 또는 스트림을 고려하지 않음)에서도 null은 문제가됩니다. 으로 FGE이 코멘트에 언급, 일부 컬렉션은 널 (null)와 다른 사람들이하지 않습니다 수 있습니다. null을 허용하는 컬렉션을 사용하면 API가 모호합니다. 예를 들어 Map.get () 에서 null 반환은 키가 있고 해당 값이 null이거나 키가 없음을 나타냅니다. 이러한 경우를 명확히하기 위해 추가 작업을해야합니다.

null의 일반적인 용도는 값이 없음을 나타내는 것입니다. Java SE 8에 대해 제안 된이를 처리하기위한 접근 방식 java.util.Optional은 기본값을 제공하거나 예외를 던지거나 함수를 호출하는 동작 등과 함께 값의 존재 / 부재를 캡슐화 하는 새로운 유형 을 도입하는 것입니다. 값이 없습니다. Optional새 API에서만 사용되지만 시스템의 다른 모든 것은 여전히 ​​null 가능성을 감안해야합니다.

내 조언은 가능한 한 실제 null 참조를 피하는 것입니다. “null”수달이 어떻게 존재할 수 있는지 예에서보기는 어렵습니다. 그러나 필요한 경우 OP의 null 값을 필터링하거나 센티넬 객체 ( Null Object Pattern )에 매핑하는 것이 좋은 방법입니다.


답변

답변은 100 % 정확하지만 Optionalnull 을 사용하여 목록 자체의 케이스 처리 를 개선하기위한 작은 제안입니다 .

 List<String> listOfStuffFiltered = Optional.ofNullable(listOfStuff)
                .orElseGet(Collections::emptyList)
                .stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

이 부분 Optional.ofNullable(listOfStuff).orElseGet(Collections::emptyList)을 사용하면 listOfStuffnull 인 경우를 멋지게 처리 하고 NullPointerException으로 실패하는 대신 emptyList를 반환 할 수 있습니다.


답변

Stuart의 답변은 훌륭한 설명을 제공하지만 다른 예를 제공하고 싶습니다.

reducenull 값을 포함하는 Stream에서을 수행하려고 할 때이 문제가 발생했습니다 (실제로 LongStream.average()는 축소 유형입니다). average ()이 반환하기 때문에 OptionalDoubleStream에 null이 포함될 수 있다고 가정했지만 대신 NullPointerException이 throw되었습니다. 이것은 Stuart 가 null v. empty에 대한 설명 때문 입니다.

따라서 OP에서 알 수 있듯이 다음과 같은 필터를 추가했습니다.

list.stream()
    .filter(o -> o != null)
    .reduce(..);

또는 아래에서 지적한 tangens처럼 Java API에서 제공하는 술어를 사용하십시오.

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

메일 링리스트 토론에서 스튜어트 링크 :
Brian Goetz on nulls in Streams


답변

스트림에서 null 값을 필터링하려는 경우 java.util.Objects.nonNull (Object)에 대한 메서드 참조를 사용하면 됩니다. 문서에서 :

이 메소드는 술어 로 사용하기 위해 존재합니다 .filter(Objects::nonNull)

예를 들면 :

List<String> list = Arrays.asList( null, "Foo", null, "Bar", null, null);

list.stream()
    .filter( Objects::nonNull )  // <-- Filter out null values
    .forEach( System.out::println );

다음과 같이 인쇄됩니다.

Foo
Bar


답변

null을 피하는 방법 예. groupingBy 전에 필터 사용

groupingBy 전에 null 인스턴스를 필터링합니다.

다음은 예입니다.

MyObjectlist.stream()
            .filter(p -> p.getSomeInstance() != null)
            .collect(Collectors.groupingBy(MyObject::getSomeInstance));


답변