Начните работу с Java Collections Framework

JDK 1.2 представляет новую структуру для коллекций объектов, называемую Java Collections Framework. «О нет, - стонете вы, - ни другой API, ни еще один фреймворк для изучения!» Но подождите, прежде чем отвернуться, выслушайте меня: фреймворк Collections стоит ваших усилий и во многих отношениях принесет пользу вашему программированию. На ум сразу приходят три больших преимущества:

  • Это значительно увеличивает удобочитаемость ваших коллекций, предоставляя стандартный набор интерфейсов, который может использоваться многими программистами во многих приложениях.
  • Это делает ваш код более гибким, позволяя передавать и возвращать интерфейсы вместо конкретных классов, обобщая ваш код, а не блокируя его.
  • Он предлагает множество конкретных реализаций интерфейсов, позволяя вам выбрать коллекцию, которая наиболее подходит и предлагает максимальную производительность для ваших нужд.

И это только для начала.

Наш тур по фреймворку начнется с обзора преимуществ, которые он предоставляет для хранения наборов объектов. Как вы скоро обнаружите, благодаря тому, что ваши старые друзья-рабочие лошадки Hashtableи Vectorподдерживают новый API, ваши программы будут единообразными и лаконичными, что наверняка понравится вам и разработчикам, имеющим доступ к вашему коду.

После предварительного обсуждения мы углубимся в детали.

Преимущество коллекций Java: обзор

До того, как Collections дебютировали с большим успехом, стандартные методы группировки объектов Java использовались с помощью массивов, классов Vectorи Hashtable. Все три из этих коллекций имеют разные методы и синтаксис для доступа к членам: массивы используют символы квадратных скобок ([]), Vectorиспользуют elementAtметод, а также Hashtableиспользуют getи putметоды. Эти различия долгое время приводили программистов к непоследовательности в реализации собственных коллекций: некоторые имитируют Vectorметоды доступа, а некоторые - Enumerationинтерфейс.

Чтобы еще больше усложнить ситуацию, большинство Vectorметодов помечены как окончательные; то есть вы не можете расширить Vectorкласс для реализации подобной коллекции. Мы могли бы создать класс коллекции, который выглядел бы как a Vectorи действовал как a Vector, но его нельзя было передать методу, который принимает Vectorкак параметр.

Наконец, ни одна из коллекций (массив Vectorили Hashtable) не реализует стандартный интерфейс доступа к членам. По мере того как программисты разрабатывали алгоритмы (например, сортировки) для управления коллекциями, разгорелся жаркий спор о том, какой объект передать алгоритму. Следует ли передавать массив или Vector? Следует ли реализовать оба интерфейса? Поговорим о дублировании и путанице.

К счастью, Java Collections Framework устраняет эти проблемы и предлагает ряд преимуществ по сравнению с отсутствием фреймворка или использованием Vectorи Hashtable:

  • Удобный набор интерфейсов сбора

    При реализации одного из основных интерфейсов - Collection, Set, Listили Map- вы обеспечиваете ваш класс Соответствует к общему API и становитесь более регулярными и легко понять. Итак, реализуете ли вы базу данных SQL, средство сопоставления образцов цвета или приложение удаленного чата, если вы реализуете Collectionинтерфейс, операции с вашей коллекцией объектов хорошо известны вашим пользователям. Стандартные интерфейсы также упрощают передачу и возврат коллекций в методы класса и из них и позволяют этим методам работать с более широким спектром коллекций.

  • Базовый набор реализаций коллекций

    В дополнение к надежным Hashtableи Vector, которые были обновлены для реализации Collectionинтерфейсов, были добавлены новые реализации коллекций, включая HashSetand TreeSet, ArrayListand LinkedList, and HashMapand Map. Использование существующей стандартной реализации делает ваш код короче и быстрее загружается. Кроме того, использование существующего ядра кода Core Java гарантирует, что любые улучшения базового кода также улучшат производительность вашего кода.

  • Другие полезные улучшения

    Каждая коллекция теперь возвращает Iteratorулучшенный тип, Enumerationкоторый позволяет выполнять операции с элементами, такие как вставка и удаление. Это Iterator«безотказно», что означает, что вы получите исключение, если список, который вы повторяете, изменен другим пользователем. Кроме того, коллекции на основе списков, такие как Vectorвозвращают, ListIteratorкоторые позволяют двунаправленную итерацию и обновление.

    Несколько коллекций ( TreeSetи TreeMap) неявно поддерживают порядок. Используйте эти классы, чтобы без труда вести отсортированный список. Вы можете найти самые маленькие и самые большие элементы или выполнить двоичный поиск, чтобы повысить производительность больших списков. Вы можете отсортировать другие коллекции, предоставив метод сравнения коллекций ( Comparatorобъект) или метод сравнения объектов ( Comparableинтерфейс).

    Наконец, статический класс Collectionsпредоставляет неизменяемые (только для чтения) и синхронизированные версии существующих коллекций. Неизменяемые классы полезны для предотвращения нежелательных изменений в коллекции. Синхронизированная версия коллекции необходима для многопоточных программ.

Платформа Java Collections Framework является частью Core Java и входит в java.util.collectionsпакет JDK 1.2. Платформа также доступна в виде пакета для JDK 1.1 (см. Ресурсы).

Примечание. Версия коллекций JDK 1.1 имеет имя com.sun.java.util.collections. Имейте в виду, что код, разработанный для версии 1.1, необходимо обновить и перекомпилировать для версии 1.2, а любые объекты, сериализованные в версии 1.1, не могут быть десериализованы в версию 1.2.

Давайте теперь более внимательно рассмотрим эти преимущества, применив Java Collections Framework с нашим собственным кодом.

A good API

The first advantage of the Java Collections Framework is a consistent and regular API. The API is codified in a basic set of interfaces, Collection, Set, List, or Map. The Collection interface contains basic collection operations such as adding, removing, and tests for membership (containment). Any implementation of a collection, whether it is one provided by the Java Collections Framework or one of your own creations, will support one of these interfaces. Because the Collections framework is regular and consistent, you will learn a large portion of the frameworks simply by learning these interfaces.

Both Set and List implement the Collection interface. The Set interface is identical to the Collection interface except for an additional method, toArray, which converts a Set to an Object array. The List interface also implements the Collection interface, but provides many accessors that use an integer index into the list. For instance, get, remove, and set all take an integer that affects the indexed element in the list. The Map interface is not derived from collection, but provides an interface similar to the methods in java.util.Hashtable. Keys are used to put and get values. Each of these interfaces are described in following code examples.

The following code segment demonstrates how to perform many Collection operations on HashSet, a basic collection that implements the Set interface. A HashSet is simply a set that doesn't allow duplicate elements and doesn't order or position its elements. The code shows how you create a basic collection and add, remove, and test for elements. Because Vector now supports the Collection interface, you can also execute this code on a vector, which you can test by changing the HashSet declaration and constructor to a Vector.

import java.util.collections.*; public class CollectionTest { // Statics public static void main( String [] args ) { System.out.println( "Collection Test" ); // Create a collection HashSet collection = new HashSet(); // Adding String dog1 = "Max", dog2 = "Bailey", dog3 = "Harriet"; collection.add( dog1 ); collection.add( dog2 ); collection.add( dog3 ); // Sizing System.out.println( "Collection created" + ", size=" + collection.size() + ", isEmpty=" + collection.isEmpty() ); // Containment System.out.println( "Collection contains " + dog3 + ": " + collection.contains( dog3 ) ); // Iteration. Iterator supports hasNext, next, remove System.out.println( "Collection iteration (unsorted):" ); Iterator iterator = collection.iterator(); while ( iterator.hasNext() ) System.out.println( " " + iterator.next() ); // Removing collection.remove( dog1 ); collection.clear(); } } 

Let's now build on our basic knowledge of collections and look at other interfaces and implementations in the Java Collections Framework.

Good concrete implementations

We have exercised the Collection interface on a concrete collection, the HashSet. Let's now look at the complete set of concrete collection implementations provided in the Java Collections framework. (See the Resources section for a link to Sun's annotated outline of the Java Collections framework.)

Implementations
Hash Table Resizable Array Balanced Tree (Sorted) Linked List Legacy
Interfaces Set HashSet * TreeSet * *
List * ArrayList * LinkedList Vector
Map HashMap * TreeMap * Hashtable

Implementations marked with an asterix (*) make no sense or provide no compelling reason to implement. For instance, providing a List interface to a Hash Table makes no sense because there is no notion of order in a Hash Table. Similarly, there is no Map interface for a Linked List because a list has no notion of table lookup.

Let's now exercise the List interface by operating on concrete implementations that implement the List interface, the ArrayList, and the LinkedList. The code below is similar to the previous example, but it performs many List operations.

import java.util.collections.*; public class ListTest { // Statics public static void main( String [] args ) { System.out.println( "List Test" ); // Create a collection ArrayList list = new ArrayList(); // Adding String [] toys = { "Shoe", "Ball", "Frisbee" }; list.addAll( Arrays.toList( toys ) ); // Sizing System.out.println( "List created" + ", size=" + list.size() + ", isEmpty=" + list.isEmpty() ); // Iteration using indexes. System.out.println( "List iteration (unsorted):" ); for ( int i = 0; i < list.size(); i++ ) System.out.println( " " + list.get( i ) ); // Reverse Iteration using ListIterator System.out.println( "List iteration (reverse):" ); ListIterator iterator = list.listIterator( list.size() ); while ( iterator.hasPrevious() ) System.out.println( " " + iterator.previous() ); // Removing list.remove( 0 ); list.clear(); } } 

As with the first example, it's simple to swap out one implementation for another. You can use a LinkedList instead of an ArrayList simply by changing the line with the ArrayList constructor. Similarly, you can use a Vector, which now supports the List interface.

When deciding between these two implementations, you should consider whether the list is volatile (grows and shrinks often) and whether access is random or ordered. My own tests have shown that the ArrayList generally outperforms the LinkedList and the new Vector.

Notice how we add elements to the list: we use the addAll method and the static method Arrays.toList. This static method is one of the most useful utility methods in the Collections framework because it allows any array to be viewed as a List. Now an array may be used anywhere a Collection is needed.

Notice that I iterate through the list via an indexed accessor, get, and the ListIterator class. In addition to reverse iteration, the ListIterator class allows you to add, remove, and set any element in the list at the point addressed by the ListIterator. This approach is quite useful for filtering or updating a list on an element-by-element basis.

Последний базовый интерфейс в Java Collections Framework - это Map. Этот интерфейс реализован с помощью двух новых конкретных реализаций: the TreeMapи HashMap. Это TreeMapреализация сбалансированного дерева, которая сортирует элементы по ключу.

Давайте проиллюстрируем использование Mapинтерфейса на простом примере, который показывает, как добавлять, запрашивать и очищать коллекцию. Этот пример, в котором используется HashMapкласс, не сильно отличается от того, как мы использовали Hashtableдо дебюта платформы Collections. Теперь, с обновлением Hashtableдля поддержки Mapинтерфейса, вы можете поменять местами строку, создающую экземпляр, HashMapи заменить ее экземпляром Hashtable.