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


88

안녕하세요, 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 개체를 생성하지 않도록합니다.

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

감사!


3
여기서 옳은 일을하는 것은 프로그래머에게 달려 있다고 말하고 싶습니다. JVM과 컴파일러는 많은 일을 할 수 있습니다. 그러나 일부 컬렉션 구현에서는 null 값을 허용하지 않습니다.
fge

18
당신은 사용할 수 있습니다 filter(Objects::nonNull)Objects에서java.utils
Benj

답변:


45

현재의 생각은 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 )에 매핑하는 것이 좋은 방법입니다.


3
널을 피하는 이유는 무엇입니까? 그들은 데이터베이스에서 광범위하게 사용됩니다.
Raffi Khatchadourian 2015-08-25

5
@RaffiKhatchadourian 예, 데이터베이스에서 null이 사용되지만 똑같이 문제가 있습니다. 참조 읽기 모든 답변과 의견을. 또한 부울 표현식에 대한 SQL null의 영향을 고려하십시오. en.wikipedia.org/wiki/… ... 이것은 쿼리 오류의 풍부한 소스입니다.
Stuart Marks

1
@RaffiKhatchadourian 짜증나니까 null, 그 이유입니다. Acc. 내가 본 설문 조사 (찾을 수 없음)에서 NPE는 Java에서 최고의 예외입니다. SQL은 높은 수준의 프로그래밍 언어가 아니며 확실히 작동하지 않으며 null을 경멸하므로 신경 쓰지 않습니다.
Abhijit Sarkar

91

답변은 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를 반환 할 수 있습니다.


2
나는 이것을 좋아하고 명시 적으로 null을 확인하지 않습니다.
Chris

1
이 모양 가장 명확 .. 좋은 정확히 내가 필요
압둘라 알 Noman에게

다른 방식으로 만 명시 적으로 null을 확인합니다. null이 될 수 있다면 선택 사항이어야합니다. 그게 아이디어 죠? 선택 사항으로 모든 null 값을 금지하십시오. 또한 빈 목록 대신 null을 반환하는 것은 좋지 않으므로 이것을 보면 두 가지 코드 냄새가 나타납니다. 옵션이 사용되지 않고 빈 스트림이 반환되지 않습니다. 그리고 후자는 20 년 넘게 사용 가능하므로 성숙했습니다 ...
Koos Gadellaa

빈 목록 대신 null을 반환하려면 어떻게해야합니까?
Ashburn RK

@AshburnRK 그것은 나쁜 습관입니다. 빈 목록을 반환해야합니다.
Johnny

69

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


19

스트림에서 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

7

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

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

다음은 예입니다.

MyObjectlist.stream()
            .filter(p -> p.getSomeInstance() != null)
            .collect(Collectors.groupingBy(MyObject::getSomeInstance));
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.