Java se сервлеты и jsp паттерны Gof junit Log4j ant



Pdf көрінісі
бет15/22
Дата11.12.2019
өлшемі8,99 Mb.
#53432
1   ...   11   12   13   14   15   16   17   18   ...   22
Байланысты:
JAVA Methods Programming v2.march2015 (2)

Глава 10
КОЛЛЕКЦИИ
Программирование заставило дерево зацвести.
Алан Дж. Перлис
Общие определения
Коллекции — это хранилища или контейнеры, поддерживающие различные 
способы накопления и упорядочения объектов с целью обеспечения возможно-
стей  эффективного  доступа  к  ним.  Они  представляют  собой  реализацию  аб-
страктных структур данных, поддерживающих три основные операции:
•  добавление нового элемента в коллекцию;
•  удаление элемента из коллекции;
•  изменение элемента в коллекции.
В качестве других операций могут быть реализованы следующие: заменить, 
просмотреть элементы, подсчитать их количество и др.
Применение коллекций обусловливается возросшими объемами обрабаты-
ваемой информации. Когда счет используемых объектов идет на сотни тысяч, 
массивы  не  обеспечивают  ни  должной  скорости,  ни  экономии  ресурсов. 
Современные информационные системы тестируются на примере электронно-
го магазина, содержащего около 40 тысяч товаров и 125 миллионов клиентов, 
сделавших 400 миллионов заказов.
Примером коллекции является стек (структура LIFO — Last In First Out), в ко-
тором всегда удаляется объект, вставленный последним. Для очереди (структура 
FIFO — First In First Out) используется другое правило удаления: всегда удаляет-
ся элемент, вставляемый первым. В абстрактных типах данных существует не-
сколько видов очередей: двусторонние очереди, кольцевые очереди, обобщен-
ные очереди, в которых запрещены повторяющиеся элементы. Стеки и очереди 
могут быть реализованы как на базе массива, так и на базе связного списка.
Коллекции в языке Java объединены в библиотеке классов java.util и пред-
ставляют  собой  контейнеры  для  хранения  и  манипулирования  объектами. 
До  появления  Java  2  эта  библиотека  содержала  классы  только  для  работы 
с простейшими структурами данных: VectorStackHashtableBitSet, а также 
интерфейс Enumeration для работы с элементами этих классов. Коллекции, поя-
вившиеся в Java 2, представляют собой общую технологию хранения и доступа 
к объектам. Скорость обработки коллекций повысилась по сравнению с предыдущей 

ИСПОЛЬЗОВАНИЕ КЛАССОВ И БИБЛИОТЕК
254
версией языка за счет отказа от их потокобезопасности. Поэтому, если объект 
коллекции может быть доступен из различных потоков, что наиболее естествен-
но для распределенных приложений, необходимо использовать коллекции из Java 1.
Так как в коллекциях при практическом программировании хранится набор 
ссылок на объекты одного типа, следует обезопасить коллекцию от появления 
ссылок на другие, не разрешенные логикой приложения типы. Такие ошибки 
при использовании нетипизированных коллекций выявляются на стадии вы-
полнения, что повышает трудозатраты на исправление и верификацию кода. 
Поэтому, начиная с версии Java SE 5, коллекции стали типизированными.
Более удобным стал механизм работы с коллекциями, а именно:
•  предварительное  сообщение  компилятору  о  типе  ссылок,  которые  будут 
храниться в коллекции, при этом проверка осуществляется на этапе компи-
ляции;
•  отсутствие  необходимости  постоянно  преобразовывать  возвращаемые 
по ссылке объекты (тип Object) к требуемому типу.
Структура коллекций характеризует способ, с помощью которого програм-
мы Java обрабатывают группы объектов. Так как Object — суперкласс для всех 
классов, то в коллекции можно хранить объекты любого типа, кроме базовых. 
Коллекции — это динамические массивы, связные списки, деревья, множест-
ва, хэш-таблицы, стеки, очереди.
Интерфейсы коллекций:
Map — карта отображения вида «ключ-значение»;
Collection — вершина иерархии коллекций List, Set;
List — специализирует коллекции для обработки списков;
Set  —  специализирует  коллекции  для  обработки  множеств,  содержа-
щих уникальные элементы.
Все классы коллекций реализуют также интерфейсы SerializableCloneable 
(кроме  WeakHashMap).  Кроме  того,  классы,  реализующие  интерфейсы 
List и Set, реализуют также интерфейс Iterable.
В интерфейсе Collection определены методы, которые работают на всех 
коллекциях:
boolean add(E obj) — добавляет obj к вызывающей коллекции и возвраща-
ет true, если объект добавлен, и false, если obj уже элемент коллекции;
boolean remove(Object obj) — удаляет obj из коллекции;
boolean addAll(Collection c) — добавляет все элементы кол-
лекции к вызывающей коллекции;
void clear() — удаляет все элементы из коллекции;
boolean contains(Object obj) — возвращает true, если вызывающая коллек-
ция содержит элемент obj;
boolean equals(Object obj) — возвращает true, если коллекции эквивалентны;
boolean isEmpty() — возвращает true, если коллекция пуста;
Iterator iterator() — извлекает итератор;

КОЛЛЕКЦИИ
255
int size() — возвращает количество элементов в коллекции;
Object[] toArray() — копирует элементы коллекции в массив объектов;
 T[] toArray(T a[]) — копирует элементы коллекции в массив объектов 
определенного типа.
При работе с элементами коллекции применяются следующие интерфейсы:
Comparator, Comparable — для сравнения объектов;
IteratorListIteratorMap.Entry — для перечисления и до-
ступа к объектам коллекции.
Интерфейс  Iterator  используется  для  построения  объекта,  который 
обеспечивает доступ к элементам коллекции. К этому типу относится объект, 
возвращаемый методом iterator(). Такой объект позволяет просматривать со-
держимое коллекции последовательно, элемент за элементом. Позиции итера-
тора располагаются в коллекции между элементами. В коллекции, состоящей 
из N элементов, существует N+1 позиций итератора.
Методы интерфейса Iterator:
boolean hasNext() — проверяет наличие следующего элемента, а в случае 
его отсутствия (завершения коллекции) возвращает false. Итератор при этом 
остается неизменным;
E
 next() — возвращает ссылку на объект, на который указывает итера-
тор, и передвигает текущий указатель на следующий, предоставляя доступ 
к следующему элементу. Если следующий элемент коллекции отсутствует, 
то метод next() генерирует исключение NoSuchElementException;
void remove() — удаляет объект, возвращенный последним вызовом метода 
next(). Если метод next() до вызова remove() не вызывался, то будет сгенериро-
вано исключение IllegalStateException.
Интерфейс Map.Entry предназначен для извлечения ключей и значений кар-
ты с помощью методов K getKey() и V getValue() соответственно. Вызов мето-
да V setValue(V value) заменяет значение, ассоциированное с текущим ключом.
Списки
Класс ArrayList — динамический массив объектных ссылок. Реализует 
интерфейсы ListCollectionIterable.
java.util.AbstractCollection
   
java.util.AbstractList
       
java.util.ArrayList
В классе объявлены конструкторы:
ArrayList()
ArrayList(Collection c)
ArrayList(int capacity)
Практически все методы класса являются реализацией абстрактных мето-
дов из суперклассов и интерфейсов. Методы интерфейса List позволяют 

ИСПОЛЬЗОВАНИЕ КЛАССОВ И БИБЛИОТЕК
256
вставлять и удалять элементы из позиций, указываемых через отсчитываемый 
от нуля индекс:
void add(int index, E element) — вставляет element в позицию, указанную 
в index;
E
 remove(int index) — удаляет объект из позиции index;
E
 set(int index, E element) — заменяет объект в позиции index, возвращает 
при этом удаляемый элемент;
void addAll(int index, Collection c) — вставляет в вызываю-
щий список все элементы коллекции с, начиная с позиции index;
E
 get(int index) — возвращает элемент в виде объекта из позиции index;
int indexOf(Object ob) — возвращает индекс указанного объекта;
List subList(int fromIndex, int toIndex) — извлекает часть коллекции 
в указанных границах.
Удаление и добавление элементов для такой коллекции представляет собой 
ресурсоемкую задачу, поэтому объект ArrayList лучше всего подходит для 
хранения списков с малым числом подобных действий. С другой стороны, на-
вигация  по  списку  осуществляется  очень  быстро,  поэтому  операции  поиска 
производятся за более короткое время.
/* # 1 # создание параметризованной коллекции # DemoGeneric.java */
package 
by.bsu.collect;
import
 java.util.ArrayList;
public
 class DemoGeneric {
public static void main(String args[ ]) {
      ArrayList list = new ArrayList<>();
             
// ArrayList b = new ArrayList(); // ошибка компиляции
list.add("Java"); 
/* компилятор "знает" 
           
допустимый тип передаваемого значения */
list.add("JavaFX 2");
         
String res = list.get(0); /* компилятор 
"знает" 
          
допустимый тип возвращаемого значения */
         
// list.add(new StringBuilder("C#")); // ошибка компиляции
              
// компилятор не позволит добавить "посторонний" тип
System.out.print(list); // удобный вывод
}
}
В результате будет выведено:
[Java, JavaFX 2]
В данной ситуации не создается новый класс для каждого конкретного типа 
и сама коллекция не меняется, просто компилятор снабжается информацией 
о типе элементов, которые могут храниться в list. При этом параметром коллек-
ции может быть только объектный тип.

КОЛЛЕКЦИИ
257
Следует отметить, что указывать тип следует при создании ссылки, иначе 
будет позволено добавлять объекты всех типов. На этом основан принцип ти-
побезопасности, обеспечиваемый параметризацией коллекций. Пусть в систе-
ме онлайн-торговли используются понятия Order и Item. Заказы могут соби-
раться в списки, например, список заказов за день. Возможна ситуация, когда 
по каким-либо причинам в список заказов будет добавлен экземпляр товара. 
В  этой  ситуации  даже  свести  баланс  действительно  сделанных  заказов  про-
стым  определением  размера  списка  будет  невозможно.  Придется  извлекать 
каждый объект, определять его тип и проч.
/* # 2 # некорректная(raw) и корректная коллекция # UncheckCheckRun.java */
package
 by.bsu.collection;
import
 java.util.ArrayList;
public
 class UncheckCheckRun {
 
public
 static void main(String[ ] args) {
 
 
ArrayList raw = new ArrayList() { // "сырая" коллекция – raw type
   { 
// логический блок анонимного класса
    add(new Order(231, 12.f));
    add(new Item(23154, 120.f, "Xerox"));
    add(new Order(217, 1.7f));
   }
  };
  // при извлечении требуется приведение типов
  Order or1 = (Order) raw.get(0);
 
 
Item or2 = (Item) raw.get(1);
 
 
Order or3 = (Order) raw.get(2);
  for (Object ob : raw) {
   System.out.println("raw " + ob);
  }
 
 
ArrayList orders = new ArrayList() {
   {
    add(new Order(231, 12.f));
    add(new Order(389, 2.9f));
    add(new Order(217, 1.7f));
    // add(new Item(23154, 120.f, "Xerox"));
 
 
 
 
// ошибка компиляции: список параметризован
   }
  };
  for (Order ob : orders) {
   System.out.println("Order: " + ob);
  }
 }
}
В результате будет выведено: 
raw Order [idOrder=231, amount=12.0]
raw Item [idItem=231, price=12.0, name=Xerox]

ИСПОЛЬЗОВАНИЕ КЛАССОВ И БИБЛИОТЕК
258
raw Order [idOrder=217, amount=1.7]
Order: Order [idOrder=231, amount=12.0]
Order: Order [idOrder=389, amount=2.9]
Order: Order [idOrder=217, amount=1.7]
где классы Order и Item представляют собой сущности Заказ и Товар в следу-
ющем виде:
/* # 3 # класс используется здесь и далее для наполнения коллекций # Order.java */
package
 by.bsu.collection;
public
 class Order {
 
private
 int orderId;
 
private
 float amount;
 
// поля и методы описания подробностей заказа
 
public
 Order(int orderId, float amount) {
  this.orderId = orderId;
  this.amount = amount;
 }
 
public
 int getOrderId () {
  return orderId;
 }
 
public
 float getAmount() {
  return amount;
 }
 @Override
 
public
 String toString() {
  return "Order [orderId =" + orderId + ", amount=" + amount + "]";
 }
}
/* # 4 # класс используется здесь и далее для наполнения коллекций # Item.java */
package
 by.bsu.collection;
public
 class Item {
 
private
 int itemId;
 
private
 float price;
 
private
 String name;
 
public
 Item(int itemId, float price, String name) {
  this itemId = itemId;
  this.price = price;
  this.name = name;
 }
 
public
 int getItemId () {
  return itemId;
 }
 
public
 float getPrice() {
  return price;
 }
 
public
 String getName() {

КОЛЛЕКЦИИ
259
  return name;
 }
 @Override
 
public
 String toString() {
  return "Item [itemId =" + itemId + ", price=" + price + ", name=" + name + "]\n";
 }
}
Чтобы параметризация коллекции была полной, необходимо указывать па-
раметр и при объявлении ссылки, и при создании объекта.
Интерфейс Iterator используется для последовательного доступа к элемен-
там коллекции. Ниже приведен пример поиска с помощью итератора заказов, 
сумма которых превышает заданную.
/* # 5 # методы класса ArrayList и интерфейса Iterator # RunIterator.java # FindOrder.java*/
package
 by.bsu.collection;
import
 java.util.Iterator;
import
 java.util.List;
import
 java.util.ArrayList;
public
 class RunIterator {
 
public
 static void main(String[ ] args) {
 
 
ArrayList orders = new ArrayList() {
   {
    add(new Order(231, 12.f));
    add(new Order(389, 2.9f));
    add(new Order(217, 1.7f));
   }
  };
 
 
FindOrder fo = new FindOrder();
 
 
List res = fo.findBiggerAmountOrder(10f, orders);
  System.out.println(res);
 }

package
 by.bsu.collection;
import
 java.util.List;
import
 java.util.Iterator;
public
 class FindOrder {
 public
 List findBiggerAmountOrder(float bigAmount, List orders) {
 
 
ArrayList bigPrices = new ArrayList();
 
 
Iterator it = orders.iterator();
  while (it.hasNext()) {
 
 
 
Order current = it.next();
   if(current.getAmount() >= bigAmount) {
    bigPrices.add(current);
   }
 
          }
 
return 
bigPrices;
 }
}

ИСПОЛЬЗОВАНИЕ КЛАССОВ И БИБЛИОТЕК
260
В результате на консоль будет выведено:
[Order [idOrder=231, amount=12.0]]
Метасимвол в коллекциях
Метасимволы используются при параметризации коллекций для расшире-
ния  возможностей  самой  коллекции  и  обеспечения  ее  типобезопасности. 
Например, если параметр метода предыдущего примера изменить с List 
на List, то в метод можно будет передавать коллекции, пара-
метризованные любым допустимым типом, а именно классом Order и любым 
его подклассом, что невозможно при записи без анонимного символа.
Но в методе нельзя будет добавить к коллекции новый элемент, пусть даже 
и допустимого типа, так как компилятору неизвестен заранее тип параметриза-
ции списка.
List findBiggerAmountOrder(float bigAmount, Listextends Order> orders) {
 
// orders.add(new Order(231, 12.f)); // ошибка компиляции
 orders.remove(0); 
// удалять можно
 
// some code here
}
Объясняется это тем, что список, передаваемый в качестве параметра мето-
да, может быть параметризован классом DiscountOrder, а в методе будет со-
вершаться попытка добавления экземпляра самого класса Order, как показано 
выше, что недопустимо определением самой параметризации передаваемого 
в метод списка, а именно:
findBiggerAmountOrder(10.f, new ArrayList());
где
public
 class DiscountOrder extends Order {
 
// поля
 
public
 DiscountOrder(int idOrder, float amount) {
  super(idOrder, amount);
 }
 
// методы
}
Поэтому добавление к спискам, параметризованным метасимволом с при-
менением extends, запрещено всегда.
Параметризация List утверждает, что параметр метода или 
возвращаемое значение может получить список типа Order или любого из его 
суперклассов,  в  то  же  время  разрешает  добавлять  туда  экземпляры  класса 
Order и любых его подклассов.
List findBiggerAmountOrder(float bigAmount, Listsuper Order> orders) {
  orders.add(new Order(231, 12.f));
  // 
some code here
}

КОЛЛЕКЦИИ
261
Или, если использовать super для определения типа возвращаемого значения:
Listsuper Order> findBiggerAmountOrder(float bigAmount, Listextends Order> orders) {
 
// some code here
}
В этом случае к списку, возвращенному методом, можно будет добавлять 
экземпляры класса Order и его подклассов.
Интерфейс ListIterator
Для  доступа  к  элементам  списка  может  также  использоваться  интерфейс 
ListIterator, который позволяет получить доступ сразу в необходимую про-
граммисту позицию списка вызовом метода listIterator(int index). Интерфейс 
ListIterator расширяет интерфейс Iterator и предназначен для обработ-
ки списков и их вариаций. Наличие методов E previous(), int previousIndex() 
и boolean hasPrevious() обеспечивает обратную навигацию по списку. Метод 
int nextIndex() возвращает номер следующего итератора. Метод void add(E obj) 
позволяет  вставлять  элемент  в  список  текущей  позиции.  Вызов  метода  void 
set(E obj) производит замену текущего элемента списка на объект, передавае-
мый методу в качестве параметра.
При внесении изменений в коллекцию после извлечения итератора гаранти-
рует  генерацию  исключения  java.util.ConcurrentModificationException  при 
попытке использовать итератор позднее.
ArrayList orders = new ArrayList<>();
// добавление элементов
Iterator it = orders.iterator();
orders.add(new Order(12, 12.1f)); // или remove(0);
while
 (it.hasNext()) {
 System.out.println(it.next());
}
Параллельная или конкурентная модификация коллекции различными актив-
ностями (самой коллекцией и ее итератором) приводит к неразрешимой пробле-
ме и заканчивается генерацией исключения практически всегда. Проблема за-
ключается в том, что итератор извлек N число позиций, а коллекция изменила 
число своих экземпляров и итератор перестал соответствовать коллекции. Если 
модификацию коллекции и работу с итератором нужно выполнять из различных 
потоков,  то  для  решения  такой  задачи  используются  ограниченно  потокобез-
опасные решения для коллекций из пакета java.util.concurrent.
При  создании  класса,  содержащего  коллекцию  элементов,  возможны  два 
способа: агрегация коллекции в качестве поля класса или отношение HAS-A 
и наследование от класса, представляющего коллекцию или отношение IS-A
Последнее встречается значительно реже.

ИСПОЛЬЗОВАНИЕ КЛАССОВ И БИБЛИОТЕК
262
/* # 6 # класс, агрегирующий список, с реализацией интерфейса Iterable # Order.java*/
import
 java.util.Iterator;
import
 java.util.List;
import
 java.util.Collections;
public
 class Order implements Iterable {
 
private
 int orderId;
 
private
 List listItems;
 
// private float amount; // не нужен, т.к. сумму можно вычислить
 
public
 Order(int orderId, List listItems) {
  this.orderId = orderId;
  this.listItems = listItems;
 }
 
public
 int getOrderId () {
  return orderId;
 }
 
public
 List getListItems() {
  return Collections.unmodifiableList(listItems);
 
}
 
// некоторые делегированные методы интерфейсов List и Collection
 


Достарыңызбен бөлісу:
1   ...   11   12   13   14   15   16   17   18   ...   22




©engime.org 2024
әкімшілігінің қараңыз

    Басты бет