Iterating over a collection in Java (for a C++ programmer) - java

I am attempting to write code to traverse a collection of type InstallationComponentSetup:
java.util.Collection<InstallationComponentSetup> components= context.getInstallationComponents();
Iterator it = components.iterator();
while (it.hasNext())
{
if (((InstallationComponentSetup)it).getName() == "ACQ")
{
return true;
}
}
The cast in the if-statement fails, but I don't really know why (I am a C++ programmer!).
If someone could give me some pointers as to what I am doing wrong I would be grateful.

it is an Iterator, whereas it.next() is an InstallationComponentSetup.
The error results from the fact that an Iterator cannot be cast as an InstallationComponentSetup.
Also, you shouldn't even need to cast if you parametrize the Iterator appropriately:
Iterator<InstallationComponentSetup> it = components.iterator();
Finally, don't compare strings with something like a == b, instead use a.equals(b). See "How do I compare strings in Java" for further details.
You might also want to look into the for-each loop if all you want to do is iterate over the collection. Your code can be rewritten as:
for (InstallationComponentSetup component : components)
if (component.getName().equals("ACQ"))
return true;

If you are comparing String , use equals() method .
Even your casting is wrong.You have to invoke next() on the iterator to get the next element . Hence it.next() gives you the next element which will be an object of InstallationComponentSetup, it is not of type InstallationComponentSetup hence the cast will fail.
Here you are casting the Iterator to your class type which will fail.
if (((InstallationComponentSetup)it).getName() == "ACQ")
{
return true;
}
I believe there is no need of cast here as you have defined the Collection to hold the specific type of element and also if you declare the Iterator of a specific type.
You can simply do :
// define Iterator of InstallationComponentSetup
Iterator<InstallationComponentSetup> it = components.iterator();
if("ACQ".equals(it.next().getName())) {
return true;
}
You can also consider using the enhanced for loop in Java , if your purpose is only to read the elements .
for(InstallationComponentSetup component: components) {
if("ACQ".equals(component.getName())) {
return true;
}
}

You have to retrieve the next element in the iteration before you compare:
InstallationComponentSetup next = it.next();
if (next.getName() == "ACQ")
{
return true;
}

Try to use the following code. It is more concise and easier to understand.
Collection<InstallationComponentSetup> components= context.getInstallationComponents();
for(InstallationComponentSetup comp : components){
if("ACQ".equals(comp.getName()){
return;
}
}
I think you had two problems in you code.
Cast the iterator to an object doesn't work like that. You need to use it.next() to get the object and move the iterator.
like already mentioned you need equals to compare Strings. == compares "memory locations" (in C++ terms).

Use it.next() to get the next element.
Also, use the .equals() method to compare strings in Java. Otherwise, the references are compared.
Finally, the cast should be unnecessary with a type-parameterized Iterator.
while (it.hasNext())
{
if ( it.next().getName().equals("ACQ") ) {
...
}
}

You have to retrieve the next element in the iteration before you compare:
java.util.Collection<InstallationComponentSetup> components= context.getInstallationComponents();
Iterator<InstallationComponentSetup> it = components.iterator();
while (it.hasNext()) {
if ("ACQ".equals(it.next().getName())) {
return true;
}
}

It would be easier to use foreach loop, make use of generic type, use equals for String and change string comparison order to be null secure.
Collection<InstallationComponentSetup> components= context.getInstallationComponents();
for (InstallationComponentSetup setup : components)
{
if ("ACQ".equals(setup.getName()))
{
return true;
}
}

The install4j API is still for Java 1.4, so there are no generics yet. This will work:
for (Object o : context.getInstallationComponents()) {
InstallationComponentSetup component = (InstallationComponentSetup)o;
if (component.getName().equals("ACQ")) {
return true;
}
}

Related

Can we add additional stopping condition in iterator for-loop?

In the conventional loop, we could have as below, making single nested layer.
for (int i=0; listObject != null && i < listObject.size(); i++) {
// Do whatever we want
}
However, using the below style for each loop, I'll need a double nested code: -
if (listObject != null) {
for (Object object: listObject) {
// Do whatever we want
}
}
Is it possible to embed the listObject != null condition into the for-loop statement to make it single nested code?
Your second example is clear, easily understood code. There is nothing wrong with nesting a for loop in an if block. It's even more clear than your first example.
But if you insist on combining them, you can use the ternary operator to supply an empty list if listObject is null. Using Collections.emptyList means no iterations will take place and no NullPointerException will be thrown.
for (Object object : listObject == null ? Collections.emptyList() : listObject)
I don't think I would use code like this when a clear example such as your second example already exists, but this code does provide a way to get two colons inside a for loop.
To make it concise on, while having a single nested loop, I decided to make it into function as below
void checkCondition(List<Object> listObject) {
if (listObject == null) return;
for (Object object: listObject) {
// Do whatever
}
}

How can i counter a ConcurrentModificationException?

if have the following problem:
I have a List which i am going through using the enhanced for loop. Every time i want to remove sth, out of the list, i get a ConcurrentModificationException. I already found out why this exception is thrown, but i don`t know how i can modify my code, so that its working. This is my code:
for(Subject s : SerData.schedule)
{
//Checking of the class is already existing
for(Classes c : s.classes)
{
if(c.day == day &c.which_class == which_class)
{
int index = getclassesindex(s.classes, new Classes(day, which_class));
synchronized (s) {
s.classes.remove(index);
}
}
}
//More code....
}
I also tried out this implementation.
for(Subject s : SerData.schedule)
{
//Checking of the class is already existing
Iterator<Classes> x = s.classes.iterator();
while(x.hasNext())
{
Classes c = x.next();
if(c.day == day &c.which_class == which_class)
{
int index = getclassesindex(s.classes, new Classes(day, which_class));
synchronized (s) {
s.classes.remove(index);
}
}
}
//More code....
}
not working either...
Is there a common used, standard solution? (Hopefully sth. that is not obvious :D )
The main reason this issue occurs is because of the semantic meaning of your for-each loop.
When you use for-each loops, the data structure that is being traversed cannot be modified.
Essentially anything of this form will throw this exception:
for( Object o : objCollection )
{
// ...
if ( satisfiesSomeProperty ( o ) )
objList.remove(o); // This is an error!!
// ...
}
As a side note, you can't add or replace elements in the collection either.
There are a few ways to perform this operation.
One way is to use an iterator and call the remove() method when the object is to be removed.
Iterator <Object> objItr = objCollection.iterator();
while(objItr.hasNext())
{
Object o = objItr.next();
// ...
if ( satifiesSomeProperty ( o ) )
objItr.remove(); // This is okay
// ...
}
This option has the property that removal of the object is done in time proportional to the iterator's remove method.
The next option is to store the objects you want to remove, and then remove them after traversing the list. This may be useful in situations where removal during iteration may produce inconsistent results.
Collection <Object> objsToRemove = // ...
for( Object o : objCollection )
{
// ...
if ( satisfiesSomeProperty ( o ) )
objsToRemove.add (o);
// ...
}
objCollection.removeAll ( objsToRemove );
These two methods work for general Collection types, but for lists, you could use a standard for loop and walk the list from the end of the list to the front, removing what you please.
for (int i = objList.size() - 1; i >= 0; i--)
{
Object o = objList.get(i);
// ...
if ( satisfiesSomeProperty(o) )
objList.remove(i);
// ...
}
Walking in the normal direction and removing could also be done, but you would have to take care of how incrementation occurs; specifically, you don't want to increment i when you remove, since the next element is shifted down to the same index.
for (int i = 0; i < objList.size(); i++)
{
Object o = objList.get(i);
// ...
if ( satisfiesSomeProperty(o) )
{
objList.remove(i);
i--;
}
//caveat: only works if you don't use `i` later here
// ...
}
Hope this provides a good overview of the concepts and helps!
Using Iterator.remove() should prevent the exception from being thrown.
Hm if I get it right you are iterating over a collection of classes and if a given class matches some criteria you are looking for the its index and try to remove it?
Why not just do:
Iterator<Classes> x = s.classes.iterator();
while(x.hasNext()){
Classes c = x.next();
if(c.day == day && c.which_class == which_class) {
x.remove();
}
}
Add synchronization if need be (but I would prefer a concurrent collection if I were you), preferably change the "==" to equals(), add getters/setters etc. Also the convention in java is to name variables and methods using camelCase (and not separating them with "_").
Actually this is one of the cases when you have to use an iterator.
From the javadoc on ConcurrentModificationException:
"if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception."
So within your
for (Classes c : s.classes)
you are executing
s.classes.remove(index)
and the iterator is doing just what its contract says. Declare the index(es) in a scope outside the loop and remove your target after the loop is done.
Iterator<Classes> classesIterator = s.classes.iterator();
while (classesIterator.hasNext()) {
Classes c = classesIterator.next();
if (c.day == day && c.which_class == which_class) {
classesIterator.remove();
}
}
There is no general solution for Collection subclasses in general - most iterators will become invalid if the collection is modified, unless the modification happens through the iterator itself via Iterator.remove().
There is a potential solution when it comes to List implementations: the List interface has index-based add/get/set/remove operations. Rather than use an Iterator instance, you can iterate through the list explicitly with a counter-based loop, much like with arrays. You should take care, however, to update the loop counter appropriately when inserting or deleting elements.
Your for-each iterator is fail-fast and this is why remove operation fails as it would change the collection while traversing it.
What implementation of List interface are you using?
Noticed synchronisation on Subject, are you using this code concurrently?
If concurrency is the case, then I would recommend using CopyOnWriteArrayList. It doesn't need synchronisation and its for-each iterator doesn't throw ConcurrentModificationException.

Need help stepping through a java iterator

Say I have already created an iterator called "iter" and an arraylist called "database". I want to be able to look through the arraylist and see if any element in the arraylist is equal to a String called "test". If it is, then I would like to add the element to another list.
while(iter.hasNext()) {
if(database.next() == test) {
database.next().add(another_list);
}
}
What am I doing wrong? I'm completely new to iterators in java. Do I need to write my own iterator class? Any code examples would be greatly appreciated. Thanks
The problem with your code is that every time you call .next(), it advances the iterator forward to the next position. This means that this code
if(database.next() == test) {
database.next().add(another_list);
}
Won't work as intended, because the first call to database.next() will not give back the same value as the second call to database.next(). To fix this, you'll want to make a temporary variable to hold on to the new value, as seen here:
while(iter.hasNext()) {
/* type */ curr = iter.next();
if(curr == test) {
curr.add(another_list);
}
}
(Filling in the real type of what's being iterated over in place of /* type */)
In many cases, though, you don't need to use iterators explicitly. Most of the Collections types implement the Iterable interface, in which case you can just write
/* container */ c;
for(/* type */ curr: c) {
if(curr == test) {
curr.add(another_list);
}
}
Hope this helps!
if(database.contains("test"))
{
another_list.add("test");
}
you can use the built in method contains(...)
you should use equals(...) for data comparisions
look at the javadoc to see if there is already a method present for your purpose

Null check in an enhanced for loop

What is the best way to guard against null in a for loop in Java?
This seems ugly :
if (someList != null) {
for (Object object : someList) {
// do whatever
}
}
Or
if (someList == null) {
return; // Or throw ex
}
for (Object object : someList) {
// do whatever
}
There might not be any other way. Should they have put it in the for construct itself, if it is null then don't run the loop?
You should better verify where you get that list from.
An empty list is all you need, because an empty list won't fail.
If you get this list from somewhere else and don't know if it is ok or not you could create a utility method and use it like this:
for( Object o : safe( list ) ) {
// do whatever
}
And of course safe would be:
public static List safe( List other ) {
return other == null ? Collections.EMPTY_LIST : other;
}
You could potentially write a helper method which returned an empty sequence if you passed in null:
public static <T> Iterable<T> emptyIfNull(Iterable<T> iterable) {
return iterable == null ? Collections.<T>emptyList() : iterable;
}
Then use:
for (Object object : emptyIfNull(someList)) {
}
I don't think I'd actually do that though - I'd usually use your second form. In particular, the "or throw ex" is important - if it really shouldn't be null, you should definitely throw an exception. You know that something has gone wrong, but you don't know the extent of the damage. Abort early.
It's already 2017, and you can now use Apache Commons Collections4
The usage:
for(Object obj : ListUtils.emptyIfNull(list1)){
// Do your stuff
}
You can do the same null-safe check to other Collection classes with CollectionUtils.emptyIfNull.
With Java 8 Optional:
for (Object object : Optional.ofNullable(someList).orElse(Collections.emptyList())) {
// do whatever
}
Use ArrayUtils.nullToEmpty from the commons-lang library for Arrays
for( Object o : ArrayUtils.nullToEmpty(list) ) {
// do whatever
}
This functionality exists in the commons-lang library, which is included in most Java projects.
// 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;
}
This is the same as the answer given by #OscarRyz, but for the sake of the DRY mantra, I believe it is worth noting. See the commons-lang project page. Here is the nullToEmpty API documentation and source
Maven entry to include commons-lang in your project if it is not already.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
Unfortunately, commons-lang doesn't provide this functionality for List types. In this case you would have to use a helper method as previously mentioned.
public static <E> List<E> nullToEmpty(List<E> list)
{
if(list == null || list.isEmpty())
{
return Collections.emptyList();
}
return list;
}
If you are getting that List from a method call that you implement, then don't return null, return an empty List.
If you can't change the implementation then you are stuck with the null check. If it should't be null, then throw an exception.
I would not go for the helper method that returns an empty list because it may be useful some times but then you would get used to call it in every loop you make possibly hiding some bugs.
I have modified the above answer, so you don't need to cast from Object
public static <T> List<T> safeClient( List<T> other ) {
return other == null ? Collections.EMPTY_LIST : other;
}
and then simply call the List by
for (MyOwnObject ownObject : safeClient(someList)) {
// do whatever
}
Explaination:
MyOwnObject: If List<Integer> then MyOwnObject will be Integer in this case.
For anyone uninterested in writing their own static null safety method you can use: commons-lang's org.apache.commons.lang.ObjectUtils.defaultIfNull(Object, Object). For example:
for (final String item :
(List<String>)ObjectUtils.defaultIfNull(items, Collections.emptyList())) { ... }
ObjectUtils.defaultIfNull JavaDoc
Another way to effectively guard against a null in a for loop is to wrap your collection with Google Guava's Optional<T> as this, one hopes, makes the possibility of an effectively empty collection clear since the client would be expected to check if the collection is present with Optional.isPresent().
Use, CollectionUtils.isEmpty(Collection coll) method which is Null-safe check if the specified collection is empty.
for this import org.apache.commons.collections.CollectionUtils.
Maven dependency
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
for (Object object : someList) {
// do whatever
} throws the null pointer exception.

Google Collections Suppliers and Find

I'm looking for a Google Collections method that returns the first result of a sequence of Suppliers that doesn't return null.
I was looking at using Iterables.find() but in my Predicate I would have to call my supplier to compare the result against null, and then have to call it again once the find method returned the supplier.
Given your comment to Calm Storm's answer (the desire not to call Supplier.get() twice), then what about:
private static final Function<Supplier<X>, X> SUPPLY = new Function<....>() {
public X apply(Supplier<X> in) {
// If you will never have a null Supplier, you can skip the test;
// otherwise, null Supplier will be treated same as one that returns null
// from get(), i.e. skipped
return (in == null) ? null : in.get();
}
}
then
Iterable<Supplier<X>> suppliers = ... wherever this comes from ...
Iterable<X> supplied = Iterables.transform(suppliers, SUPPLY);
X first = Iterables.find(supplied, Predicates.notNull());
note that the Iterable that comes out of Iterables.transform() is lazily-evaluated, therefore as Iterables.find() loops over it, you only evaluate as far as the first non-null-returning one, and that only once.
You asked for how to do this using Google Collections, but here's how you would do it without using Google Collections. Compare it to Cowan's answer (which is a good answer) -- which is easier to understand?
private static Thing findThing(List<Supplier<Thing>> thingSuppliers) {
for (Supplier<Thing> supplier : thingSuppliers) {
Thing thing = supplier.get();
if (thing != null) {
return thing;
}
}
// throw exception or return null
}
In place of the comment -- if this was the fault of the caller of your class, throw IllegalArgumentException or IllegalStateException as appropriate; if this shouldn't have ever happened, use AssertionError; if it's a normal occurrence your code that invokes this expects to have to check for, you might return null.
What is wrong with this?
List<Supplier> supplierList = //somehow get the list
Supplier s = Iterables.find(supplierList, new Predicate<Supplier>(){
boolean apply(Supplier supplier) {
return supplier.isSomeMethodCall() == null;
}
boolean equals(Object o) {
return false;
}
});
Are you trying to save some lines? The only optimisation I can think is to static import the find so you can get rid of "Iterables". Also the predicate is an anonymous inner class, if you need it in more than one place you can create a class and it would look as,
List<Supplier> supplierList = //somehow get the list
Supplier s = find(supplierList, new SupplierPredicateFinder());
Where SupplierPredicateFinder is another class.
UPDATE : In that case find is the wrong method. You actually need a custom function like this which can return two values. If you are using commons-collections then you can use a DefaultMapEntry or you can simply return an Object[2] or a Map.Entry.
public static DefaultMapEntry getSupplier(List<Supplier> list) {
for(Supplier s : list) {
Object heavyObject = s.invokeCostlyMethod();
if(heavyObject != null) {
return new DefaultMapEntry(s, heavyObject);
}
}
}
Replace the DefaultMapEntry with a List of size 2 or a hashmap of size 1 or an array of length 2 :)

Categories

Resources