- 37. Do not shadow or obscure identifiers in subscopes
- 38. Do not declare more than one variable per declaration
- 39. Use meaningful symbolic constants to represent literal values in program logic
- 40. Properly encode relationships in constant definitions
- 41. Return an empty array or collection instead of a null value for methods that return an array or collection
- 42. Use exceptions only for exceptional conditions
- 43. Use a try-with-resources statement to safely handle closeable resources
- 44. Do not use assertions to verify the absence of runtime errors
- 45. Use the same type for the second and third operands in conditional expressions
- 46. Do not serialize direct handles to system resources
- 47. Prefer using iterators over enumerations
- 48. Do not use direct buffers for short-lived, infrequently used objects
- 49. Remove short-lived objects from long-lived container objects
47. Prefer using iterators over enumerations
According to the Java API Interface Enumeration<E> documentation [API 2013],
- An object that implements the Enumeration interface generates a series of elements, one at a time. Successive calls to the nextElement method return successive elements of the series.
As an example, the following code uses an Enumeration to display the contents of a Vector:
for (Enumeration e = vector.elements(); e.hasMoreElements();) { System.out.println(e.nextElement()); }
The Java API [API 2013] recommends, “New implementations should consider using Iterator in preference to Enumeration.” Iterators are superior to enumerations because they use simpler method names, and, unlike enumerations, iterators have well-defined semantics when elements in a collection are removed while iterating over the collection. Consequently, iterators rather than enumerators should be preferred when examining iterable collections.
Noncompliant Code Example
This noncompliant code example implements a BankOperations class with a removeAccounts() method used to terminate all the accounts of a particular account holder, as identified by the name. Names can be repeated in the vector if a person has more than one account. The remove() method attempts to iterate through all the vector entries, comparing each entry with the name “Harry.”
class BankOperations { private static void removeAccounts(Vector v, String name) { Enumeration e = v.elements(); while (e.hasMoreElements()) { String s = (String) e.nextElement(); if (s.equals(name)) { v.remove(name); // Second Harry is not removed } } // Display current account holders System.out.println("The names are:"); e = v.elements(); while (e.hasMoreElements()) { // Prints Dick, Harry, Tom System.out.println(e.nextElement()); } } public static void main(String args[]) { // List contains a sorted array of account holder names // Repeats are admissible List list = new ArrayList(Arrays.asList( new String[] {"Dick", "Harry", "Harry", "Tom"})); Vector v = new Vector(list); removeAccount(v, "Harry"); } }
Upon encountering the first “Harry,” it successfully removes the entry, and the size of the vector diminishes to three. However, the index of the Enumeration remains unchanged, causing the program to perform the next (now final) comparison with “Tom.” Consequently, the second “Harry” remains in the vector unscathed, having shifted to the second position in the vector.
Compliant Solution
According to the Java API Interface Iterator<E> documentation [API 2013],
Iterator takes the place of Enumeration in the Java collections framework. Iterators differ from enumerations in two ways:
- Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.
- Method names have been improved.
This compliant solution remedies the problem described in the noncompliant code example and demonstrates the advantages of using an Iterator over an Enumeration:
class BankOperations { private static void removeAccounts(Vector v, String name) { Iterator i = v.iterator(); while (i.hasNext()) { String s = (String) i.next(); if (s.equals(name)) { i.remove(); // Correctly removes all instances // of the name Harry } } // Display current account holders System.out.println("The names are:"); i = v.iterator(); while (i.hasNext()) { System.out.println(i.next()); // Prints Dick, Tom only } } public static void main(String args[]) { List list = new ArrayList(Arrays.asList( new String[] {"Dick", "Harry", "Harry", "Tom"})); Vector v = new Vector(list); remove(v, "Harry"); } }
Applicability
Using Enumeration when performing remove operations on an iterable Collection may cause unexpected program behavior.
Bibliography
[API 2013] |
Interface Enumeration<E> |
Interface Iterator<E> |
|
[Daconta 2003] |
Item 21, “Use Iteration over Enumeration” |