Verificação nula em um loop for aprimorado

172

Qual é a melhor maneira de se proteger contra nulo em um loop for em Java?

Isso parece feio:

if (someList != null) {
    for (Object object : someList) {
        // do whatever
    }
}

Ou

if (someList == null) {
    return; // Or throw ex
}
for (Object object : someList) {
    // do whatever
}

Pode não haver outra maneira. Eles deveriam colocá-lo na forprópria construção, se for nulo, não execute o loop?

fastcodejava
fonte
2
Você provavelmente está melhor jogando um NPE. nullnão é o mesmo que uma coleção vazia.
Tom Hawtin - defina
6
@GregMattes Como a pergunta de fevereiro é uma duplicata da pergunta de outubro?
Val
1
Só preciso usar Collections.nonNullElementsIn (...): stackoverflow.com/a/34913556/5637185
Jeffrey Dilley

Respostas:

227

Você deve verificar melhor de onde você obtém essa lista.

Uma lista vazia é tudo que você precisa, porque uma lista vazia não falhará.

Se você obtiver essa lista de outro lugar e não souber se está tudo bem ou não, você poderá criar um método utilitário e usá-lo desta forma:

for( Object o : safe( list ) ) {
   // do whatever 
 }

E, claro, safeseria:

public static List safe( List other ) {
    return other == null ? Collections.EMPTY_LIST : other;
}
OscarRyz
fonte
57
Observe que Collections.emptyList () evitará alocar um objeto extra (IIRC).
Jon Skeet
7
@ Jon: Eu sempre me perguntei qual era o uso desse emptyList java.sun.com/j2se/1.5.0/docs/api/java/util/… O que é o IIRC?
OscarRyz 12/02/10
11
IIRC = "Se bem me lembro". E sim, há uma instância singleton retornada para todas as chamadas para Collections.emptyList ().
ColinD
Isso ... na verdade não responde à pergunta. Por que a resposta é aceita?
Christopher Wirt
1
@ChristopherWirt porque responde à pergunta: D
Tarik
100

Você poderia escrever um método auxiliar que retornasse uma sequência vazia se passasse nulo:

public static <T> Iterable<T> emptyIfNull(Iterable<T> iterable) {
    return iterable == null ? Collections.<T>emptyList() : iterable;
}

Então use:

for (Object object : emptyIfNull(someList)) {
}

Eu acho que realmente não faria isso - normalmente usaria seu segundo formulário. Em particular, o "or throw ex" é importante - se realmente não deve ser nulo, você definitivamente deve lançar uma exceção. Você sabe que algo deu errado, mas você não sabe a extensão do dano. Abortar cedo.

Jon Skeet
fonte
3
Eu mudaria o parâmetro de lista Iterable <T> para Iterable <T> iterável, pois nem todos os iteráveis ​​são uma lista.
Lombo
Tenha cuidado ao usar este método: por causa do uso de classe Collections, o uso deste método envolve a sua lista de te ser imutável
Tanorix
@tanorix: De que maneira?
26617 Jon Skeet
@JonSkeet, você pode ver que emptyList () da classe Collections retorna uma lista imutável: docs.oracle.com/javase/8/docs/api/java/util/…, portanto, se o usuário não quiser imutá- la, pode ser problemático
Tanorix
@tanorix: Mas o objetivo desta pergunta é sobre a iteração sobre o valor retornado. Isso não modifica. É por isso que o tipo de retorno emptyIfNullé Iterable<T>: existe o removemétodo infeliz Iterator<T>, mas esse é o único aspecto mutável (e se você tem uma coleção vazia, por que está tentando remover algo dela?) Não está claro o que você ' está objetando aqui.
Jon Skeet
29

Já é 2017, e agora você pode usar Apache Commons Collections4

O uso:

for(Object obj : ListUtils.emptyIfNull(list1)){
    // Do your stuff
}

Você pode fazer a mesma verificação de segurança nula para outras classes de coleção com CollectionUtils.emptyIfNull.

Fred Pym
fonte
2
Funcionará, porém, cria um objeto de lista desnecessário. Um CollectionUtils.ifNotEmpty pode ser mais detalhado, mas mais eficiente e mais rápido. Não que isso importa muito ...
Lawrence
2
Em 2017, eu esperaria List.emptyIfNull (list1)
Dima
3
@ Lawrence, o método não cria novos objetos de lista, ele usa Collections.emptyList()internamente, que por sua vez sempre retorna a mesma lista não modificável vazia pré-alocada.
Yoory N.
E se você chamar myobject.getCompanies (). GetAddresses () e ambos retornarem uma Lista e ambos puderem ser nulos?
powder366
9

Com o Java 8 Optional:

for (Object object : Optional.ofNullable(someList).orElse(Collections.emptyList())) {
    // do whatever
}
holmis83
fonte
1
É mais detalhado do que o simples operador ternário someList != null ? someList : Collections.emptyList()e também cria e imediatamente joga fora uma instância de Optionalobjeto.
Yoory N.
2
como essas linhas de monstro são mais elegantes que uma simples declaração if (someList == null). Vamos escrever um aplicativo bancário em uma linha ...
Andreas Panagiotidis
8

Use ArrayUtils.nullToEmptyda commons-langbiblioteca para matrizes

for( Object o : ArrayUtils.nullToEmpty(list) ) {
   // do whatever 
}

Essa funcionalidade existe na commons-langbiblioteca, incluída na maioria dos projetos Java.

// ArrayUtils.nullToEmpty source code 
public static Object[] nullToEmpty(final Object[] array) {
    if (isEmpty(array)) {
        return EMPTY_OBJECT_ARRAY;
    }
    return array;
}

// ArrayUtils.isEmpty source code
public static boolean isEmpty(final Object[] array) {
    return array == null || array.length == 0;
}

É o mesmo que a resposta dada por @OscarRyz, mas, pelo bem do mantra DRY , acredito que vale a pena notar. Veja a página do projeto commons-lang . Aqui está a documentação e a fonte da nullToEmptyAPI

Entrada do Maven para incluir commons-langno seu projeto, se ainda não estiver.

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
</dependency>

Infelizmente, commons-langnão fornece essa funcionalidade para Listtipos. Nesse caso, você precisaria usar um método auxiliar, como mencionado anteriormente.

public static <E> List<E> nullToEmpty(List<E> list)
{
    if(list == null || list.isEmpty())
    {
        return Collections.emptyList();
    }
    return list;
}
sdc
fonte
7

Se você está obtendo isso Listde uma chamada de método implementada, não retorne null, retorne uma mensagem vazia.List .

Se você não puder alterar a implementação, ficará com a nullverificação. Se não for null, lance uma exceção.

Eu não usaria o método helper que retorna uma lista vazia porque pode ser útil algumas vezes, mas você se acostumaria a chamá-lo em todos os ciclos que você possivelmente ocultar alguns erros.

Lombo
fonte
4

Modifiquei a resposta acima, para que você não precise transmitir do Object

public static <T> List<T> safeClient( List<T> other ) {
            return other == null ? Collections.EMPTY_LIST : other;
}

e, em seguida, basta chamar a lista

for (MyOwnObject ownObject : safeClient(someList)) {
    // do whatever
}

Explicação: MyOwnObject: Se, List<Integer>então, MyOwnObject será Inteiro neste caso.

Haris Iltifat
fonte
1

Outra maneira de se proteger efetivamente contra um nulo em um loop for é agrupar sua coleção com o Google Guava, Optional<T>pois isso, espera-se, torna clara a possibilidade de uma coleção efetivamente vazia, pois é esperado que o cliente verifique se a coleção está presente Optional.isPresent().

Nico de Wet
fonte
1

Para quem não estiver interessado em escrever seu próprio método estático de segurança nula, você pode usar: commons-lang's org.apache.commons.lang.ObjectUtils.defaultIfNull(Object, Object). Por exemplo:

    for (final String item : 
    (List<String>)ObjectUtils.defaultIfNull(items, Collections.emptyList())) { ... }

ObjectUtils.defaultIfNull JavaDoc

Jacob Briscoe
fonte
Para mim, esta resposta é a mais elegante
Truong Nguyen
0

Use, CollectionUtils.isEmpty(Collection coll)método que é Null-safe verifique se a coleção especificada está vazia.

por isso import org.apache.commons.collections.CollectionUtils.

Dependência do Maven

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.0</version>
</dependency>
Swadeshi
fonte
-4
for (Object object : someList) {

   // do whatever
}  throws the null pointer exception.
user6315386
fonte