Buscando um valor sem precisar fazer nulo no Java

15

Muitas vezes me vejo checando nulo ao buscar um valor de alguma hierarquia de dados para evitar NullPointerExceptions, que considero propenso a erros e que precisa de muita informação.

Eu escrevi uma rotina muito simples que permite ignorar a verificação nula ao buscar um objeto ...

public final class NoNPE {

    public static <T> T get(NoNPEInterface<T> in) {
        try {
            return in.get();
        } catch (NullPointerException e) {
            return null;
        }
    }

    public interface NoNPEInterface<T> {
        T get();
    }
}

Eu uso um pouco assim ...

Room room = NoNPE.get(() -> country.getTown().getHouses().get(0).getLivingRoom());

O resultado acima resultou na obtenção de um objeto Room ou um nulo, sem a necessidade de nulo verificar todos os níveis pai.

O que você acha do exposto? Estou criando um padrão problemático? Existe uma maneira melhor de fazer isso na sua opinião?

Eurig Jones
fonte
1
Como você aparentemente usa o Java 8, posso sugerir que você considere reprojetar seu aplicativo para usar em java.util.Optionalvez de nulos para representar dados ausentes? Isto fornece utilitários tanto para o caso de você descrever e casos em que você gostaria de continuar com os dados padrão ao invés de apenas retornando uma condição de falha no final da cadeia ..
Periata Breatta
Eu acho que você essencialmente redescobriu o Option(ou Maybemônada) :)
Andres F.
Pode ser possível retornar Opcional em vez de T ou nulo: dessa forma, você pode usar o método orElse () diretamente. 18 meses depois, mas poderia ajudar alguém.
214 Benj
Outra abordagens são mencionados neste post illegalargumentexception.blogspot.com/2015/03/... , um deles está usando uma biblioteca kludje chamado que tem uma sintaxe muito interessante
Benj

Respostas:

13

Sua solução é muito inteligente. O problema que vejo é o fato de você não saber por que recebeu um null? Foi porque a casa não tinha quartos? Foi porque a cidade não tinha casas? Foi porque o país não tinha cidades? Foi porque houve um nullna posição 0 da coleção devido a um erro, mesmo quando há casas nas posições 1 e superiores?

Se você usar extensivamente a NonPEclasse, terá sérios problemas de depuração. Eu acho que é melhor saber onde exatamente a cadeia está quebrada do que obter silenciosamente um nullque poderia estar escondendo um erro mais profundo.

Isso também viola a Lei de Deméter : country.getTown().getHouses().get(0).getLivingRoom(). Freqüentemente, violar algum bom princípio faz com que você implemente soluções não-ortodoxas para resolver o problema causado pela violação de tal princípio.

Minha recomendação é que você o use com cautela e tente solucionar a falha de design que faz com que seja necessário incorrer no antipadrão de naufrágio do trem (para que você não precise usá-lo em NonPEqualquer lugar). Caso contrário, você pode ter erros que serão difíceis de detectar.

Tulains Córdova
fonte
Ótima resposta. Sim, eu não saberei onde consegui o nulo na cadeia. Em muitos casos, embora eu não me importe e não precise verificar nulo significa que o código é mais legível e menos propenso a erros de clichê. Mas sim, você está certo em alguns casos em que preciso tomar uma decisão lógica diferente se um objeto pai for nulo; isso causaria um problema. O método convencional ou a classe Opcional pode ser uma solução mais segura lá.
Eurig Jones 15/01
Em geral, ao usar a Optionmônada, você não se importa em que parte da cadeia está o valor ausente. Quando você se importa com isso, provavelmente usa um tipo diferente, como Either.
Andres F.Fev
A abordagem do OP é semelhante ao C # 6 ?.e aos ?[]operadores. Um exemplo de quando você pode querer usar isso é configurações hierárquicas do lado do servidor. var shouldDoThing = settings?.a?.b?.c ?? defaultSetting;Quem se importa por que alguma parte disso foi nula? Talvez você não possa buscar as configurações. Talvez você tenha decidido remover uma seção das configurações. Em qualquer caso, você nunca pode realmente contar com as configurações do servidor, portanto, um padrão geralmente é uma boa ideia, e é improvável que você se importe com o fato de não conseguir obter a configuração real, a menos que ocorra com muita frequência quando não deveria. .
Chris
Agora não estou dizendo que isso seja estritamente melhor ou pior do que localizar os padrões e simplesmente recuperar o valor desejado por meio de acessos normais settings.a.b.c. Então, novamente, este é um único exemplo isolado.
Chris
10

A ideia é boa, muito boa de fato. Como os Optionaltipos existem no Java 8 , uma explicação detalhada pode ser encontrada no tipo Java Opcional . Um exemplo com o que você postou é

Optional.ofNullable(country)
    .map(Country::getTown)
    .map(Town::Houses);

E mais adiante.

J. Pichardo
fonte
1
Sim, eu conhecia a classe Opcional, do Java 8 e do Guava, e eles são realmente úteis. Mas você não pode simplesmente buscar um objeto, pois normalmente tornaria o código um pouco mais difícil de ler e um pouco menos eficiente também. Mas o lado positivo é que existem muitos operadores muito úteis que a classe Opcional fornece.
precisa saber é o seguinte
3
@EurigJones Eu não acho que o código se torne menos eficiente. Legibilidade aos olhos de quem vê, mas eu argumentaria que Optionalé a solução mais legível das duas, apenas porque - ao contrário da sua proposta - é uma linguagem muito comum . É ainda mais conciso que o seu!
Andres F.
0

Seu método funciona bem o suficiente para a finalidade a que se destina, embora retorne nulls quando você obtém um NullPointerExceptionsom como um design ruim.

Tente evitar nulls quando puder e só passá-los quando eles representam algo ou têm um significado especial e apenas os devolve quando eles representam / significam algo - caso contrário, você deve lançar a NullPointerException. Isso evita bugs e confusão. Se um Objectnão deveria ser null, um NullPointerdeveria ser lançado. Se um objeto puder ser null, nada dará errado quando um for passado. Caso contrário, seu método acima funcionará.

Luke Melaia
fonte
0

Sinto sua dor, mas a solução proposta é uma má ideia.

  • Se um dos getters lançar um NPE por algum outro motivo, você o ignorará.
  • Há um risco de que esse lambda interno se transforme em código horrível. Por exemplo, se houver um novo requisito para retornar uma constante especial quando não houver casas na cidade, um programador preguiçoso poderá estender a lamda, deixando tudo embrulhado NoNPE.get.
  • Como já mencionado, Optional.map é o que você está procurando.
  • A penalidade de criar uma nova instância de NullPointerException é frequentemente significativa. São muitos microssegundos, principalmente porque a pilha de chamadas está aumentando. É difícil prever onde seu utilitário será usado.

Como observação lateral, NoNPEInterfaceé uma duplicata dejava.util.function.Supplier .

Em alguns casos, você pode considerar o uso de utilitários de avaliação de expressão que estão presentes em muitas estruturas (por exemplo: EL, SpEL):

evaluateProperty(country, "town.houses[0].livingRoom")
Mateusz Stefek
fonte
Aprovado para modelos de páginas da Web, mas geralmente lento para desenvolver (sem verificação do tempo de compilação) e lento para executar.
Kevin cline #