6

In my code I usually use this approach to avoid NullPointerExceptions in for statements when a List is null:

if (myList != null && myList.size() > 0) {
    for ( MyObj obj : myList ) {
        System.out.println("MyObjStr: "+obj);
    }
}

Is there another way to do the same without write the "if" statement, but using the same "for" statement?

Harmlezz
  • 7,972
  • 27
  • 35
fl4l
  • 1,580
  • 4
  • 21
  • 27
  • If you have initialized `myList`, there is no reason to check if it's `null` unless in some point you explicitly assign `null` to it. Regarding the size, you don't have to check it. – Maroun Apr 08 '14 at 09:09
  • 2
    you can easily avoid collection to be null by calling it's constructor. In such a case you'll have non-null, but empty collection. If so, you don't even need size check – nikis Apr 08 '14 at 09:11
  • Duplicate of http://stackoverflow.com/questions/6077909/is-there-a-way-to-avoid-null-check-before-the-for-each-loop-iteration-starts – Jaka Apr 08 '14 at 09:21
  • I was wondering that if you are checking that myList is not null then where you need to check whether myList size is greater than 0? What I mean here is that if your list is not null, then it must have size and lists can't have negative sizes, so I think myList.size() > 0 is not necessary in your case, unless it is initialized. – Amir Apr 08 '14 at 09:23
  • @AmirAl The size check was to prevent the size from being 0, not from being negative. Even if a list is initialized, it could have a size of 0 (actually it does if you don't add any item). **Anyway, this check is not needed since the `for` loop does not do anything on an empty list**. – Joffrey Apr 08 '14 at 11:12
  • @Joffrey you are correct, but still my aim was that check is not required as you said :) – Amir Apr 09 '14 at 09:22

6 Answers6

12

The check for the size is not needed. Your for-loop will not execute if is there are no objects in the list.

The check for null is only needed, when you are not sure about the object's state. But when using your own objects (nothing given from outside via arguements e.g.) then there is no need for the null check.

See Avoiding “!= null” statements in Java? for a brilliant explanation why unexperienced developers often exaggregate with null checks.

Community
  • 1
  • 1
ifloop
  • 8,079
  • 2
  • 26
  • 35
5

An elegant way to do this, can be found in a similar post. using

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

public static List safe( List other ) {
    return other == null ? Collections.EMPTY_LIST : other;
}

That beeing said, it's a good practice to have your methods returning empty Arrays instead of null. For example you can return

return Collections.EMPTY_LIST;

in every catch block.

This way you will loop in them safely, and when you get a NPE, you'll know that something is wrong with your code, not your data. In this context, as @Joffrey said, the NPE will be really welcome

Community
  • 1
  • 1
yannicuLar
  • 3,083
  • 3
  • 32
  • 50
4

First of all, the size check is not needed. The for loop is skipped if the size is 0.

The null check is a bit more contextual. In general you don't want to just "avoid NPE". NPE is a good way to notice programming mistakes, so you have to be careful about what needs to be null-checked. Many programmers put null-checks everywhere defensively, because they don't trust the API contracts anymore.

  • If you have an NPE with something that has no reason to be null, then you have done something wrong earlier (here it would be because your collection variable is not initialized). You don't want to hide that, you want it to explode at your face, so you can fix it right away (Fail fast principle).

  • If null is a possible (and meaningful) value for a variable (or if the value comes from an external source), then it needs to be null-checked. However, you have to handle that case, do not just skip the code that produces NPE. If you just skip it, then later code is no more safe than the current piece, and null-checks will be needed again for the same variable.

@ifLoop provided a very good link to another post about this topic, so I copy it here since my answer is accepted: Avoiding “!= null” statements in Java?

Joffrey
  • 32,348
  • 6
  • 68
  • 100
  • 5
    Lot of debates about this... I don't think it should by applied anywhere. For example you don't want your app to go down if an external service you depend on starts returning null collections... – Michael Técourt Apr 08 '14 at 09:19
  • Of course, I totally agree with you. I don't say you don't want null checks. I said you don't want to just "avoid NPEs". If `null` is apossible value for an external input (and several other cases), then the check has to be done and handled properly. However, if something has no reason to be null at one point, then don't put a null check, it hides errors. – Joffrey Apr 08 '14 at 09:22
  • In our specific case, the null check is not used to handle a special case, but just to skip the error and hide it, which IMHO is bad. – Joffrey Apr 08 '14 at 09:24
  • 1
    i think the inventor admits that null is a billion dollar mistake - https://medium.com/.../null-pointer-references-the-billion-dollar-mistake-1e616534d485 – Matt Jul 12 '19 at 01:20
1

Well you can do it one line but with a readability loss :

for ( MyObj obj : (myList == null ? new ArrayList<MyObj>() : myList) ) {
    System.out.println("MyObjStr: "+obj);
}
Michael Técourt
  • 3,457
  • 1
  • 28
  • 45
0

There is another possibility to avoid passing NULL into our for (forEach) loop - we can use isNotEmpty(Collection coll) method from CollectionUtils library before.

Example:

if (CollectionUtils.isNotEmpty(someCollection)) {
    for (Item item: someCollection) {
    ...
    }
}

OR:

if (CollectionUtils.isNotEmpty(someCollection)) {
    someCollection.forEach(...);
}
apajak
  • 21
  • 4
0

There are a lot of cases when you are supposed to do a mapping exercise for incoming DTO into another Object. Sending empty collections instead of null can be a waste of traffic, and even nulls are excluded by using mapper.setSerializationInclusion(Include.NON_NULL); or even mapper.setSerializationInclusion(Include.NON_EMPTY);

That said, if you need to do something like:

Collection<Dto> dtos = null;
for(Dto dto: dtos) {
   //doSomething
} 

You have to protect with if(ok, but I prefer another way) or stick to NullObject idiom(good):

Collection<Dto> safeDtos = Optional.ofNullable(dtos).orElse(Collections.emptyList());
for(Dto dto: safeDtos) {
   //doSomething
} 

Or the same but for streams:

Optional.ofNullable(dtos).orElse(Collections.emptyList()).stream()
    .map(this::doSomething)
    .collect(Collectors.toList());

Also, try not to leak DTOs in any downstream code except that mapping exercise. You should have a border of protection between DTO and the rest of your code.

DTO -> Mapping -> Domain Object(or another intermediate object which is NPE save and maybe has enums instead of strings, etc) -> Rest of your code.

Vadim Kirilchuk
  • 3,532
  • 4
  • 32
  • 49