Andres Stadelmann
Andres Stadelmann

Reputation: 143

How do I access the first non null term of a List in Java?

So I have a method (of which I can't change the parameters, or else this could have been made easier through HashMaps...more on this later), that passes an item as a parameter. Now I have a list of instances from this other class, of which one of its attributes is of the same type of this item, and I want to find the instances in the list which correspond to this item (of which there should be only one). This is what I did to find this:

List<Instance> instances = ...

public static void checkItems(Item i) {

    List<Instance> n = new ArrayList<>();
    instances.forEach(p -> n.add(p.i == i ? p : null));

    Instance currentInstance = n.get(0); 
    //Instance currentInstance = instances.stream().filter(p -> p.i == i).collect(Collectors.toList()).get(0);

}

You'll probably notice two things straight up:

  1. I used a conditional operator which adds a null value to the list when the condition isn't passed
  2. My commented code which was another attempt to solve this issue

So in the first case, I put null because it requires you to put something, and a null value is probably easier to work with, which is why the question arises: How do I access the first non-null value in a list (without resorting to iterating over the entire list to find it...)?

You may notice that I just assign the first value of the list with n.get(0) to currentInstance, because I know that only one value will have passed the test. However, due to some other code that I apply to currentInstance, this value cannot be null.

Just a note on the second point: the way I tried to solve it with streams actually works exactly as planned, except that for some reason the list of instances recovered is not a direct copy of the original instances. This resulted in the values of some of the attributed to have been reset to default values, therefore rendering this method useless.

EDIT: I just wanted to mention that the streams method wasn't working because of some silly mistake that I made in another class, there was nothing wrong with the code so I'll be using that bit to solve my problem :D

Upvotes: 4

Views: 2348

Answers (4)

Dimitrios Begnis
Dimitrios Begnis

Reputation: 813

You can do it like

instances.forEach(p -> {
   if (p.i == i) n.add(p);
});

Upvotes: 2

Paul Boddington
Paul Boddington

Reputation: 37645

If you know that only one p passes the test, I don't know what the point of creating a list with a load of null values plus p is.

Your problem seems to stem from wanting to use forEach. In my opinion, you should almost always use a for loop in preference to forEach. With a simple for loop you can just use break when the item is found.

In detail:

Instance p = null;
for (Instance q : instances) {
    if (q.i == i) {
        p = q;
        break;
    }
}
if (p == null)
    throw new IllegalStateException();   // It wasn't there.
// Do something with p.

Upvotes: 5

Radiodef
Radiodef

Reputation: 37845

As described, this would normally be solved with streams in the following way:

Optional<Instance> first =
    instances.stream().filter(p -> p.i == i).findFirst();

(of which there should be only one)

Of which there definitely is only one, or of which there might be more than one. (And if there's more than one, then what? Is that an error?) It sounds like it might be that you should have a Set<Instance>, not a List<Instance>. Just an observation.

Upvotes: 3

fps
fps

Reputation: 34460

You could do it this way:

Instance currentInstance = instances.stream()
    .filter(p -> p.i == i)
    .findFirst()
    .get(); // you can use get if you are sure there's one instance

The predicate p -> p.i == i seems suspicious. Why not using equals() instead?

Upvotes: 3

Related Questions