52

Given the following code, how can I iterate over an object of type ProfileCollection?

public class ProfileCollection implements Iterable {    
    private ArrayList<Profile> m_Profiles;

    public Iterator<Profile> iterator() {        
        Iterator<Profile> iprof = m_Profiles.iterator();
        return iprof; 
    }

    ...

    public Profile GetActiveProfile() {
        return (Profile)m_Profiles.get(m_ActiveProfile);
    }
}

public static void main(String[] args) {
     m_PC = new ProfileCollection("profiles.xml");

     // properly outputs a profile:
     System.out.println(m_PC.GetActiveProfile()); 

     // not actually outputting any profiles:
     for(Iterator i = m_PC.iterator();i.hasNext();) {
        System.out.println(i.next());
     }

     // how I actually want this to work, but won't even compile:
     for(Profile prof: m_PC) {
        System.out.println(prof);
     }
}
Mridang Agarwalla
  • 43,201
  • 71
  • 221
  • 382
Dewayne
  • 3,682
  • 3
  • 25
  • 23

2 Answers2

59

Iterable is a generic interface. A problem you might be having (you haven't actually said what problem you're having, if any) is that if you use a generic interface/class without specifying the type argument(s) you can erase the types of unrelated generic types within the class. An example of this is in Non-generic reference to generic class results in non-generic return types.

So I would at least change it to:

public class ProfileCollection implements Iterable<Profile> { 
    private ArrayList<Profile> m_Profiles;

    public Iterator<Profile> iterator() {        
        Iterator<Profile> iprof = m_Profiles.iterator();
        return iprof; 
    }

    ...

    public Profile GetActiveProfile() {
        return (Profile)m_Profiles.get(m_ActiveProfile);
    }
}

and this should work:

for (Profile profile : m_PC) {
    // do stuff
}

Without the type argument on Iterable, the iterator may be reduced to being type Object so only this will work:

for (Object profile : m_PC) {
    // do stuff
}

This is a pretty obscure corner case of Java generics.

If not, please provide some more info about what's going on.

Community
  • 1
  • 1
cletus
  • 616,129
  • 168
  • 910
  • 942
  • 5
    Just a warning to your approach; if you just forward the iterator from ArrayList, you also forward on the ability to remove items. If you don't want that, you'd have to wrap the iterator, or wrap the ArrayList as a readonly collection. – Jason S Mar 02 '09 at 14:37
  • Cletus, thank you your solution works perfectly. The problem I was having was actually exactly what you described. The return type was Object instaead of Profile, sorry. Hey Jason, thanks for the comment. How do I wrap the iterator? – Dewayne Mar 02 '09 at 15:10
  • 4
    I think he's referring to: Collections.unmodifiableList(m_profiles).iterator(). This will stop the caller modifying the arraylist – cletus Mar 02 '09 at 22:04
  • Yes the likely reason for somebody to contain the list rather than exend it is encapsulation and by exposing the list iterator you expose the list. I do not like the collections either. Creating an instance of class for simple iteration is an overkill for me. – Val Aug 23 '13 at 13:12
4

First off:

public class ProfileCollection implements Iterable<Profile> {

Second:

return m_Profiles.get(m_ActiveProfile);
TofuBeer
  • 60,850
  • 18
  • 118
  • 163
  • what is wrong with the first line? can you edit in an explanation? its very unclear what is wrong. – Chii Mar 02 '09 at 09:58
  • 4
    ahh, finally saw it, its the generification. but the above still holds - just put in what the problem was, and what the fix was, and it would be a better answer. – Chii Mar 02 '09 at 09:58