July 30, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Objects and Collections: ArrayLists

  • September 11, 2006
  • By Matt Weisfeld
  • Send Email »
  • More Articles »

In the previous columns, you explored the topic of Java Arrays and Vectors, from a technical approach as well as a somewhat historical perspective. In this column, you are going to take a look at one of the more common Java containers, the ArrayList.

Recall that Vectors had some potentially thorny issues relating to their use with threads. Whereas ArrayLists can be used in a way similar to Vectors, they are designed for use within a single thread. Vectors are able to be synchronized; however; there are certain side effects to deal with, including performance issues.

You will also touch upon the topic of <Generics>, which are a new addition to the Java platform. Although you will explore generics in much more detail in a later article, you will see why generics can be used to make your applications more type safe and thus much more robust.

Note: The Object-Oriented Thought Process series is intended for someone just learning an object-oriented language and who wants to understand the basic concepts before jumping into the code, or someone who wants to understand the infrastructure behind an object-oriented language he or she is already using. These concepts are part of the foundation that any programmer will need to make the paradigm shift from procedural programming to object-oriented programming. You should see the first article in this series for detailed descriptions for compiling and running all the code examples.

ArrayLists

Start directly by looking at some code. Listing 1 presents a very simple example of an ArrayList.

Listing 1: TestArrayList.java

import java.util.ArrayList;

class TestArrayList{
   public static void main(String[] args){
      ArrayList myList = new ArrayList();
      myList.add("One");
   }
}

The functionality is very similar to that of the Vector class that was covered in the last column. In fact, the Java documentation states the following.

Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)

Just as with the Vector, perhaps the biggest advantage of the ArrayList is that it is resizable, overcoming one of the limitations of an Array.

If you compile this code (which hopefully you will), the following message appears.


C:\column26>"C:\Program Files\Java\jdk1.5.0_06\bin\javac"
   -classpath . TestArray
List.java
Note: TestArrayList.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
C:\column26>

Although the code will compile and execute, as always, you should pay attention to the messages provided. In this case, the note informs you that there is a problem with unchecked or unsafe operations and encourages you to recompile with the .Xlint compiler option. When you add the .Xlint option, you get further information.


C:\column26>"C:\Program Files\Java\jdk1.5.0_06\bin\javac"
   -Xlint -classpath . TestArrayList.java
TestArrayList.java:9: warning: [unchecked] unchecked call to add(E)
   as a member of the raw type java.util.ArrayList
   myList.add("One");
        ^
1 warning
C:\column26>

The key part of this message is unchecked call to add(E). This relates to the use of <Generics>, which are a recent addition to the Java platform. Generics allow types as well as variables to be parameterized. You may recall that, when using collections of objects, casts are often required to specify the type being used. By specifying a generic, the correct type is returned, thus eliminating the need for certain casts. You will cover generics in much more detail in the near future.

However, the reason that generics come up at this point is because they are at the heart of the warning message you received in the previous compile. The error message indicates that the add() method performs an unchecked operation.

myList.add("One");

You are, in fact, adding a String to this ArrayList; however, you have not specified the type of the parameter in the definition of the ArrayList.

ArrayList myList = new ArrayList();

Note that, in the previous line of code, you have used original syntax (pre Java SE 1.5) when declaring the myList. Thus, any legacy code written prior to Java SE 1.5 will result in the warnings. Before you update the code to incorporate the generics, add some code to retrieve the value in the ArrayList in the earlier fashion.

Listing 2 demonstrates how to use an ArrayList to add and retrieve elements.

Listing 2: TestArrayList.java

import java.util.ArrayList;
import java.util.Iterator;

class TestArrayList{

   public static void main(String[] args){

      ArrayList myList = new ArrayList();

      myList.add("One");
      myList.add("Two");

      Iterator i = myList.iterator();
      while (i.hasNext()) {
         System.out.println(i.next());
      }
   }
}

When you run the code in Listing 2, you get the following output.


C:\column26>"C:\Program Files\Java\jdk1.5.0_06\bin\java"
   -classpath . TestArrayList
One
Two
C:\column26>

This output behaves in the same way that you would expect from the Vector implementation that you investigated in the previous article. However, when you move to Java SE 1.5, you want to take care of the issues pertaining to the generics.

Listing 3 includes code (in bold) that specifies the parameter type of ArrayList, in this case a String.

Listing 3: TestArrayList.java

import java.util.ArrayList;
import java.util.Iterator;

class TestArrayList{

   public static void main(String[] args){

      ArrayList<String> myList = new ArrayList<String>( );

      myList.add("One");
      myList.add("Two");

      Iterator i = myList.iterator();
      while (i.hasNext()) {
         System.out.println(i.next());
      }
   }
}

When this code is compiled, no warnings or errors are displayed.

The messages that were displayed before the generics were added complained about an unchecked call to add(E). See how this actually works, and whether the generics are really doing their job. To test this, send a non-string to the add() method as seen in Listing 4.

Listing 4: TestArrayList.java

import java.util.ArrayList;
import java.util.Iterator;

class TestArrayList{

   public static void main(String[] args){

      ArrayList<String> myList = new ArrayList<String>();

      myList.add("One");
      myList.add("Two");
      myList.add(3);

      Iterator i = myList.iterator();
         while (i.hasNext()) {
         System.out.println(i.next());
      }
   }
}

C:\column26>"C:\Program Files\Java\jdk1.5.0_06\bin\javac"
   -Xlint -classpath . TestArrayList.java
TestArrayList.java:12: cannot find symbol
symbol  : method add(int)
location: class java.util.ArrayList<java.lang.String>
          myList.add(3);
            ^
1 error
C:\column26>

Based on the error message, it appears that the generic specification is doing its job. When you try to pass an integer, the compiler catches the mistake. This is the key point here, the compiler catches the mistake. Type safety has been a major issue ever since the C Programming Language spawned C++, Java, C#, and so forth. As with all testing, it is better to catch errors as early as possible in the software life cycle. In this case, you are using generics to catch certain errors at compile-time rather than run-time. You should explore this issue a bit further.





Page 1 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel