Olá colegas desenvolvedores Java,
Eu sei que o assunto pode ser um pouco in advance
porque o JDK8 ainda não foi lançado (e não por agora, de qualquer maneira ..) mas eu estava lendo alguns artigos sobre as expressões Lambda e particularmente a parte relacionada à nova API de coleção conhecida como Stream.
Aqui está o exemplo fornecido no artigo da Java Magazine (é um algoritmo de população de lontras ..):
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());
Minha pergunta é o que acontecerá se no meio da iteração interna Set, uma das lontras for nula?
Eu esperaria que um NullPointerException fosse lançado, mas talvez eu ainda esteja preso no paradigma de desenvolvimento anterior (não funcional), alguém pode me esclarecer como isso deve ser tratado?
Se isso realmente gerar um NullPointerException, considero o recurso bastante perigoso e terá que ser usado apenas como abaixo:
- O desenvolvedor deve garantir que não haja nenhum valor nulo (talvez usando um filtro anterior (o -> o! = Nulo))
- O desenvolvedor deve garantir que o aplicativo nunca está gerando lontra nula ou um objeto NullOtter especial para lidar.
Qual é a melhor opção, ou alguma outra opção?
Obrigado!
fonte
filter(Objects::nonNull)
comObjects
dejava.utils
Respostas:
O pensamento atual parece ser "tolerar" os nulos, ou seja, permiti-los em geral, embora algumas operações sejam menos tolerantes e possam acabar gerando NPE. Veja a discussão sobre nulos na lista de discussão do grupo de especialistas em Bibliotecas Lambda, especificamente esta mensagem . Posteriormente, surgiu um consenso em torno da opção nº 3 (com uma objeção notável de Doug Lea). Então, sim, a preocupação do OP com a explosão de pipelines com a NPE é válida.
Não é à toa que Tony Hoare se refere aos valores nulos como o "Erro de um bilhão de dólares". Lidar com nulos é uma verdadeira dor. Mesmo com coleções clássicas (sem considerar lambdas ou fluxos), os nulos são problemáticos. Como fge mencionou em um comentário, algumas coleções permitem nulos e outras não. Com coleções que permitem nulos, isso introduz ambigüidades na API. Por exemplo, com Map.get () , um retorno nulo indica que a chave está presente e seu valor é nulo ou que a chave está ausente. É preciso fazer um trabalho extra para eliminar a ambigüidade desses casos.
O uso usual de nulo é denotar a ausência de um valor. A abordagem para lidar com isso proposto para Java SE 8 é introduzir um novo
java.util.Optional
tipo, que encapsula a presença / ausência de um valor, junto com comportamentos de fornecer um valor padrão, ou lançar uma exceção, ou chamar uma função, etc. se o valor está ausente.Optional
é usado apenas por novas APIs, entretanto, todo o resto no sistema ainda tem que suportar a possibilidade de nulos.Meu conselho é evitar referências nulas reais o máximo possível. É difícil ver pelo exemplo dado como pode haver uma lontra "nula". Mas, se necessário, as sugestões do OP de filtrar valores nulos ou mapeá-los para um objeto sentinela (o padrão de objeto nulo ) são boas abordagens.
fonte
null
é uma merda, é por isso. Acc. para uma pesquisa que vi (não consigo encontrar), NPE é a exceção número 1 em Java. SQL não é uma linguagem de programação de alto nível, certamente não funcional, que despreza null, então não se importa.Embora as respostas sejam 100% corretas, uma pequena sugestão para melhorar o
null
tratamento de casos da própria lista com Opcional :A parte
Optional.ofNullable(listOfStuff).orElseGet(Collections::emptyList)
permitirá que você trate bem o caso quandolistOfStuff
é nulo e retorne uma emptyList em vez de falhar com NullPointerException.fonte
A resposta de Stuart fornece uma ótima explicação, mas gostaria de fornecer outro exemplo.
Encontrei esse problema ao tentar executar um
reduce
em um fluxo contendo valores nulos (na verdade, eraLongStream.average()
, que é um tipo de redução). Como o Average () retornaOptionalDouble
, presumi que o Stream poderia conter nulos, mas em vez disso, foi lançada uma NullPointerException. Isso se deve à explicação de Stuart de nulo x vazio.Então, como o OP sugere, adicionei um filtro assim:
list.stream() .filter(o -> o != null) .reduce(..);
Ou como tangens apontado abaixo, use o predicado fornecido pela API Java:
Da discussão da lista de e-mails, Stuart linkou: Brian Goetz em nulos em Streams
fonte
Se você deseja apenas filtrar valores nulos de um fluxo, pode simplesmente usar uma referência de método para java.util.Objects.nonNull (Object) . De sua documentação:
Por exemplo:
List<String> list = Arrays.asList( null, "Foo", null, "Bar", null, null); list.stream() .filter( Objects::nonNull ) // <-- Filter out null values .forEach( System.out::println );
Isso irá imprimir:
fonte
Um exemplo de como evitar null, por exemplo, use o filtro antes de agrupar por
Filtre as instâncias nulas antes de agrupar por.
Aqui está um exemploMyObjectlist.stream() .filter(p -> p.getSomeInstance() != null) .collect(Collectors.groupingBy(MyObject::getSomeInstance));
fonte