-1

So I am initializing an ArrayList of ArrayLists in order to have a set of resizable Arrays to hold the names of classes as strings for a Design Analyzer homework assignment. The ArrayLists are initialized to a size of 7 (For the test file that I am using), yet when I perform a get on element 1, I am getting an IndexOutOfBounds exception. Upon checking the size of the ArrayList causing the problem (providers), the size is zero. I am having a hard time understanding why the ArrayList is size zero, despite the fact that I have initialized it to be the size of my cls ArrayList (which is 7 in my test case). The exception is being thrown when I attempt the get(i) on providers in my if statement, but why? Any help would be appreciated.

public class DesignAnalyzer {

//private Hashtable classSet = new Hashtable();
//ArrayList<Integer> counters = new ArrayList<>();
private static ArrayList<ArrayList<String>> providers;
private static ArrayList<ArrayList<String>> clients;
//private static ArrayList<String>[] 

public static void analyze(ArrayList<Class<?>> cls, String path){
    Package homePkg = Package.getPackage(path.substring(path.lastIndexOf("\\")+1));
    ArrayList<ArrayList<String>> providers = new ArrayList<ArrayList<String>>(cls.size());
    ArrayList<ArrayList<String>> clients = new ArrayList<ArrayList<String>>(cls.size());
    providers.ensureCapacity(cls.size());
    clients.ensureCapacity(cls.size());
    for(int i = 0; i < cls.size(); ++i){
        providers.set(i, new ArrayList<String>());
        clients.set(i, new ArrayList<String>());
    }
    getProviders(cls, homePkg);
    getClients(cls);
    //providers.clear();
}

private static void getProviders(ArrayList<Class<?>> cls, Package pkg){
    for(int i = 0; i < cls.size(); ++i){
        Class<?> spr = cls.get(i).getSuperclass();
        int temp = providers.size(); //should be 7 in test case, but coming back as zero
        if(spr != null && spr.getPackage().toString().equals(pkg.toString()) &&
                !providers.get(i).contains(spr.toString())) // exception being thrown here at i = 1 b/c providers.size is zero...
            providers.get(i).add(spr.toString());
fazhaa
  • 11
  • 2
  • Possible duplicate of [ArrayList initial capacity and IndexOutOfBoundsException](http://stackoverflow.com/questions/11908037/arraylist-initial-capacity-and-indexoutofboundsexception) – Raedwald Feb 08 '16 at 15:33

2 Answers2

1

The number that you pass to ArrayList's constructor is the initial capacity of the ArrayList, not the initial size. The initial size is 0, unless you are passing to the constructor (not the same constructor that takes the capacity parameter) another Collection used to populate your ArrayList.

You should never call providers.get(i) before checking that providers.size() > i.

P.S.

I see that you have code that initializes the providers ArrayList in your analyze method. However, you initialize a local variable and not the static class member of the same name. This means that getProviders should actually throw a NullPointerException and not IndexOutOfBoundsException (unless you initialize the providers static member in some code you didn't include).

Try to change your analyze method to :

public static void analyze(ArrayList<Class<?>> cls, String path){
    Package homePkg = Package.getPackage(path.substring(path.lastIndexOf("\\")+1));
    providers = new ArrayList<ArrayList<String>>(cls.size());
    clients = new ArrayList<ArrayList<String>>(cls.size());
    ....
Eran
  • 387,369
  • 54
  • 702
  • 768
  • Ah, thank you, I must be tired. Confused capacity and size. As for initializing the ArrayLists as local variables, I was only doing that to be able to see inside of them to debug and have changed them back. I'll mark this as answered and probably get some sleep :) – fazhaa Nov 08 '15 at 10:44
1

Accordingly to the documentation, such a constructor does what follows:

Constructs an empty list with the specified initial capacity.

So, it's perfectly reasonable that accessing it ends in an out of bound exception, for it's empty. Something similar happens for ensureCapacity, that I see you are using in your code. It simply does what follows:

Increases the capacity of this ArrayList instance, if necessary, to ensure that it can hold at least the number of elements specified by the minimum capacity argument.

I guess you have misunderstood what capacity means for a container like ArrayList and what's actually the size. While the latter actually indicates how many items are there, the former is related to the internal representation of the container. As you know, such a container grows dynamically on demand, but you can slightly optimize it if you know which is the intended final size, as an example when used in algorithms bounded in terms of visited items.

skypjack
  • 49,335
  • 19
  • 95
  • 187