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?
java.util.Optional
vez 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 ..Option
(ouMaybe
mônada) :)Respostas:
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 umnull
na 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
NonPE
classe, terá sérios problemas de depuração. Eu acho que é melhor saber onde exatamente a cadeia está quebrada do que obter silenciosamente umnull
que 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
NonPE
qualquer lugar). Caso contrário, você pode ter erros que serão difíceis de detectar.fonte
Option
mô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, comoEither
.?.
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. .settings.a.b.c
. Então, novamente, este é um único exemplo isolado.A ideia é boa, muito boa de fato. Como os
Optional
tipos existem no Java 8 , uma explicação detalhada pode ser encontrada no tipo Java Opcional . Um exemplo com o que você postou éE mais adiante.
fonte
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!Seu método funciona bem o suficiente para a finalidade a que se destina, embora retorne
null
s quando você obtém umNullPointerException
som como um design ruim.Tente evitar
null
s 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 aNullPointerException
. Isso evita bugs e confusão. Se umObject
não deveria sernull
, umNullPointer
deveria ser lançado. Se um objeto puder sernull
, nada dará errado quando um for passado. Caso contrário, seu método acima funcionará.fonte
Sinto sua dor, mas a solução proposta é uma má ideia.
NoNPE.get
.Optional.map
é o que você está procurando.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):
fonte