Vector, but, as I'll explain in more detail below, this is often overkill. The first tool I will introduce is a simple object-oriented
wrapper for a primitive array. After discussing arrays, I will move on to the second tool, a pair of little string manipulation
routines that I use for splitting and joining, and that have come in handy for me many times.Dealing with arrays can be a hairy business. You want to use primitive arrays for fast access and low memory overhead, but
you don't always know how big an array has to be until it's already populated. You can use a Vector, but doing so means that each primitive value must be wrapped in an object. For example, any int has to be wrapped in an Integer object. But don't lose heart -- there is a happy medium, and that is this month's first tool.
Here's a scenario with which I am commonly confronted: I need to populate an array of primitive values (usually ints). However, I don't know how many values there are until after I've already cycled through them -- thus, I don't know in
advance at which size I should initialize the array.
For the sake of the following code examples, let us assume that rset is the object from which I will be extracting the integer values. However, rset does not provide any size, length, or count methods that would tell me how many values it contains.
The first solution that comes to mind, from my old days of C hacking, is to declare a very large array, populate it with the values, and then trim it down. Here's how that would look in Java:
public int[] method01( SomeContainer rset )
{
int[] bigArray = new int[ 1024 ];
int count = 0;
while( rset.next() )
{
bigArray[ count ] = rset.getInt();
count += 1;
}
int[] smallArray = new int[ count ];
System.arraycopy( bigArray, 0, smallArray, 0, smallArray.length );
return smallArray;
}
If you chose to implement this code, the obvious downfall here would be that the actual number of values could be even greater
than your initial estimate. That would result in an ArrayOutOfBoundsException, and you'd be in big trouble. Such an exception is known as a runtime exception. If you expect it, you can attempt to catch it in your code; more often than not, however, you wouldn't see such an error
until the application was running.
If you were dead set on using this method, you could make it safer, by which I mean that you would prevent the occurence of the dreaded out-of-bounds exception. In order to do so, you would have to catch the array when it was about to overflow, and then increase the size of the array to accommodate the excess data. There isn't really a growing utility in Java per se, so what you would have to do is create a second, bigger array and copy over the full array. Here's how:
public int[] method01( SomeContainer rset )
{
int[] bigArray = new int[ 1024 ];
int count = 0;
while( rset.next() )
{ if( count >= bigArray.length ) // time to grow!
{
int[] tmpArray = new int[ bigArray.length + 1024 ];
System.arraycopy( bigArray, 0, tmpArray,
0, bigArray.length );
bigArray = tmpArray;
}
bigArray[ count ] = rset.getInt();
count += 1;
}
int[] smallArray = new int[ count ];
System.arraycopy( bigArray, 0, smallArray, 0, smallArray.length );
return smallArray;
}
Of course, there is a cleaner and more object-oriented solution to dealing with arrays. Java has provided us with a dynamic
array mechanism called the Vector. You simply put objects into the Vector, and it grows as needed. You can't directly place primitives into a Vector, however; the primitive values must be wrapped in objects. Thankfully, Java has provided us with wrapper objects for all
of the primitives. Using the Integer object to wrap the int and storing it into a Vector dramatically cleans up our code: