Что такое коллекции — краткое описание

Как уже можно было видеть из описания классов, класс УправляющаяСистема использует два списка — список групп и список студентов. как видите в нашем крайне скудном приложении мы уже столкнулись с ситуацией, когда нам потребуется работать с группой/массивом/списком данных. Будем называть это коллекцией.

Рекомендуем: Здесь не будет приведена подробная информация о коллекциях. Для хорошего ознакомления с ними отсылаем вас к документации по JAVA. В первую очередь это оригинал от SUN: The Collections Framework
А также ссылки статей на форуме Vingrad: Collections Framework и Коллекции

Хоть я и говорил, что мы не будем рассматривать очень подробно коллекции, все же считаю необходимым привести некоторую информацию.
Коллекции являются очень популярными типами данных. По сути любое действие над группой каких-либо данных потребует какое-то хранилище. И это хранилище будет коллекцией.Т.е. сказать, что коллекции востребованы — это почти ничего не сказать. Без коллекций было бы очень сложно программировать.

Типов коллекций достаточно много. Это связано с тем, что пока никто не смог создать коллекцию, которая прекрасно подходила бы для всех видов работы с ней. Например, если коллекция позволяет быстро добавлять в нее новый элемент вне зависимости от размера коллекции, то скорость обращения к какому-то элементу этой коллекции по индексу скоре всего будет зависеть от размера. И чем больше будет ваша коллекция, тем больше потребуется времени для этого. Такие коллекции обычно организуются как связанные списки, где первый элемент ссылается на второй, второй — на третий и т.д.
Также например одни коллекции позволяют иметь одинаковые элементы, другие — нет. С одними коллекциями можно работать из нескольких потоков, с другими надежная работа не гарантруется. Одни коллекции сразу сортируют все данные, другие хранят данные в том порядке, в котором их добавляли.
Что очень важно отметить — коллекции все-таки имеют много общего, на что указывает реализация этими коллекциями определенных интерфейсов. Вы можете использовать одинаковые механизмы для работы с разными типами коллекций. Отличие будет заключаться в скорости работы.
Коллекции имеют очень широкий спектр всевозможных функций — их можно сливать в одну, узнавать какие элементы есть в обеих коллекциях, какие наоборот отсутствуют в первой, но есть во второй. Коллекции можно сортировать по определенному алгоритму — вы можете использовать стандартные варианты, можете написать свои правила сортировки.

До версии Java 1.5 коллекции не были типизированы — т.е. программист мог поместить в коллекцию любой объект. Таким образом в коллекции могли мирно уживаться строки, даты и другие объекты разных классов. Что на самом деле встречается достаточно редко — чаще в коллекции находятся данные одного типа. Версия Java 1.5 ввела понятие Generic. Об этом вы можете более подробно узнать в статье Что нового в Java SE 5.0. Основная мысль в следующем: программист при объявлении коллекции указывает, какой тип данных может в ней храниться. И с этого момента уже на уровне компиляции есть проверка, что в коллекции будут данные определенного типа. Это позволяет не писать код приведения типа в виде String s = (String)list.get(0);.
Использование типизации позволяет разрабатывать более строгий код и выявлять многие ошибки еще на стадии компиляции, что безусловно гораздо удобнее.
Например если бы мы хотели распечатать список групп из списка, то до Java 1.5 нам пришлось бы использовать следующую конструкцию:

Обратите внимание, что мы должны использовать интерфейс Iterator. Это специальный класс, который позволяет работать с коллекцией. Идея его очень простая — при создании итератор указывает на начало коллекции и перемещается к следующему элементу вызовом метода next. Этот метод также возвращает тот объект из коллекции, на который в данный момент указывает итератор. А метод hasNext проверяет — есть ли еще элементы в коллекции. Таким образом можно просмотреть ЛЮБУЮ коллекцию. Также мы вынуждены приводить итератор к нужному нам типу насильно. Что не может не приводить иногда к ошибкам.
А теперь посмотрим на код, который позволяет нам написать Java 1.5

Как говориться — почувствуйте разницу. Во-первых, мы сразу говорим, что наш список содержит объекты типа Group. Это позволяет нам больше не думать о приведении типа при работе со списком. Компилятор не позволит нам добавлять объекты иного класса, автоматически сделает приведение — в общем всякие вкусности. Во-вторых — обратите внимание на новый вариант прохода по списку — цикл for теперь совсем простой и достаточно симпатично выглядит. По секрету — вы все еще можете использовать Iterator — и он будет работать точно также. Только теперь итератор тоже можно типизировать — например Iterator<Group>. И теперь метод next будет возвращать нужный нам тип данных сразу без приведения.

Подводя итог краткому описанию возможностей коллекций я призываю вас очень внимательно отнестись к этому очень мощному инструменту обработки данных. В подавляющем большинстве приложений вам они потребуются обязательно.

А теперь попробуем написать несложную реализацию классов для нашей системы. Наши классы будут находится в следующих файлах JAVA
Student.java
Group.java
ManagementSystem.java

Замечание: Для класса ManagementSystem сделаем метод main, который решает две задачи:

  1. Запускает класс без каких-либо дополнительных усилий
  2. Позволяет проверить функциональность системы на тестовых данных

На данном этапе у нас не будет красивого графического интерфейса — мы просто пытаемся описать необходимые функции и проверить их работоспособность. Настоятельно рекомендую: внимательно просмотрите код метода main класса ManagementSystem — там преведены вызовы всех функций, которые мы будем использовать.
Классы Student и Group — эти классы содержат только описания необходимых полей, а также методы для доступа к этим полям. Так называемые сеттеры и геттеры (от слов set/get — установить/получить). Это уже по сути стандартный подход к работе с полями класса — поле для хранения объявляется как private, а для доступа используются методы set/get. Принцип именования следующий:
Имя переменной начинается со строчной буквы – например, ИД студента будет выглядеть как studentId. А методы будут выглядеть вот так:

 

Как видите, методы имеют слова set/get и дальше уже с заглавной буквы идет имя переменной. Также при установке поля в метод передается параметр такого же типа. Я люблю именовать его так же, хотя это не обязательно. Многие системы разработки (Eclipse, JBuilder, IDEA) содержат специальные меню, которые позволяют создать set/get автоматически по списку переменных. Такой принцип именования был предложен SUN для того, чтобы можно было легко определять, какие свойства и методы есть у класса — об этом подробно описывается в спецификации JavaBeans.
Также отметим, что прародитель всех классов Object (все классы в JAVA наследуются от Object, даже если Вы не указали это явно) имеет метод toString(). Этот метод используется очень часто и к нему обращаются в случае если хотят вывести объект на экран. Самая простая строка System.out.println(s); на самом деле вызовет у объекта s метод toString() и его результат уже покажет на экране.
Сам Object делает это не очень красиво — он выводит имя класса и некое число (что-то похожее на адрес в памяти). В подавляющем большинстве случаев это не информативно, да и не очень красиво. Т.к. наши классы Student и Group будут выводится на экран, мы изменим поведение toString() для них — Вы сможете посмотреть их реализацию в коде.
И еще — вряд ли нас устроит, что студенты в списке будут идти не по алфавиту. Коллекции позволяют делать сортировку, но для этого надо выполнить условие — то, что находится в коллекции, должно иметь способы для сравнения. Ведь по сути при составлении списка студентов мы располагаем их по алфавиту — вот такой прицип и будет использован.

Для того, чтобы студенты имели «возможность сравниваться друг с другом» мы должны реализовать интерфейс Comparable, который имеет только один метод —
public int compareTo(Object obj)
Как видите, метод возвращает целое число больше 0, если объект obj меньше, 0 — если они равны, и отрицательное число — если больше. Класс String уже имеет такой метод и мы могли бы им воспользоваться, но это будет не совсем корректно. Во-первых — хотелось бы учитывать локализацию. Т.е. языковые настройки. Во-вторых — если мы будем сравнивать «ПАВЕЛ» и «артем», то хотелось бы, чтобы на первом месте был «артем». Для этого используем специальный класс — Collator. Этот класс позволяет сравнивать строки с учетом языка (Locale) а также устанавливать насколько точно должно быть сравнение — с учетом регистра или без учета и т.д. Я приведу здесь простенький пример, с которым вы можете поэкспериментировать. Сразу обращу ваше внимание на то. что последние две строки возвращают совершенно разные результаты — при сравнении через класс Collator слово «ПАВЕЛ» больше, чем «артем». А при обычном сравнении строк результат обратный. И это понятно — символ «а» имеет числовой код больше, чем «П». Следовательно, сравнение будет некорректным, если данные о ФИО будут внесены в разном регистре. Конечно, можно при вводе приводить все к одному виду, но все-таки надежнее сделать сравнение корректно.
Я все-таки не совсем элегантно все делаю — сравниваю строки, в которых есть номера групп, даты — и в этом случае возможны тоже не совсем корректные сравнения, но предлагаю вам самим сделать необходимые исправления.

А теперь приведем код наших классов с комментариями:

Student.java

Group.java

 

Давайте немного подробнее остановимся на ManagementSystem.java. Этот класс пока не очень сложный, но все таки он дает нам некоторую функциональность. Он позволяет добавить нового студента, изменить параметры студента, перевести всех студентов одной группы в другую (частая ситуация, когда после года обучения студенты переходят в другую группу), удалить студентов из группы — для тех, кто закончил учиться.
Если посмотреть на конструктор ManagementSystem, то можно увидеть, что мы вызываем загрузку списка студентов и групп. Таким образом получится, что при каждом создании ManagementSystem мы будем делать одну и ту же работу, что конечно не очень хорошо.
Для того, чтобы избежать такого мы воспользуемся шаблоном проектирования (очень интересная область знаний, которая описывает стандартные решения для каких-либо проектных задач) Singletone. Этот шаблон показывает, как можно использовать только один экземпляр объекта. Реализация делается следующим образом:

  • конструктор объявляется private (теперь напрямую создать объект нельзя)
  • описывается одна статическая переменная такого же класса (т.е. для всех объектов класса будет только одна такая переменная)
  • создается метод (обычно его называют getInstance), который возвращает ссылку на единственный объект.

 

После кода мы еще остановимся на некоторых функциях.

ManagementSystem.java

Итак, самое интересно на взгляд автора кроется в следующих функциях:
loadGroups, loadStudents, getStudentsFromGroup, moveStudentsToGroup, removeStudentsFromGroup, insertStudent, updateStudent, deleteStudent

loadGroups и loadStudents — эти функции на сегодня делают неблагодарную работу. Они создают данные и помещают их в коллекции. Остальные функции как раз и демонстрируют в какой-то мере возможности коллекций.

insertStudent — здесь вы можете видеть, что добавление в коллекцию — очень простая опреация. Вы просто добавляете и все. Вам не надо думать о том, как ее расширять, где взять памяти. Вы просто вызываете метод add.

deleteStudent, updateStudent — эти функции демонстрируют некоторые сложности при работе с коллекциями. Во-первых, здесь есть демонстрация того, каким образом можно просмотреть все элементы коллекции. Как вы могли заметить, функции достаточно похожи. В случае удаления мы просто удаляем найденного студента. В случае изменения — заменяем поля студента на новые.

getStudentsFromGroup — здесь мы получаем список студентов для определенной группы. Как видите, мы создаем еще один список, куда перемещаем всех студентов из конкретной группы и возвращаем уже вновь созданный список.

moveStudentsToGroup — здесь все проще в связи с тем, что при просмотре коллекции мы получаем ссылки на реальные объекты и их изменение будет сразу заметно.

removeStudentsFromGroup — здесь предложен следующий вариант — создать новый список из студентов, которые должны остаться.

Также надо обратить внимание на то, что наши списки групп и студентов — разные. ArrayList — простой список, который имеет порядок в каком были добавлены эдементы.
TreeSet — список, который умеет сортировать. Но умеет сортировать объекты только такого класса, который имеет реализацию интерфейса Comparable.

Ну и конечно вам просто необходимо просмотреть код метода main (напоминаю еще раз). В нем мы сделали несколько вызовов реализованных методов и убедились, что они работают.

Рекомендуем: Для более тонкого понимания как ищутся объекты в коллекциях рекомендуем вам посмотреть описания методов hashCode и equals. Коллекции часто рассматривают объекты как одинаковые, если у них одинаковый хэшкод. Мы привели не самый интересные решения. Если переопределить для класса Student методы hashCode и equals, которые будут считать студентов «равными» если у них одинаковый ИД, то процесс удаления будет короче — просто вызов students.remove(student)

ВНИМАНИЕ!!!
Наши классы находятся в пакете students.logic — обратите внимание на первую строку во всех файлах — package students.logic;
Это значит, что Вам надо создать вот такую структуру каталогов:

Для того, чтобы собрать наш проект Вам надо установить текующую директорию, в которой находится директория students. Для сборки нашего проекта используется команда
 

javac students/logic/*.java

Если вы собираетесь использовать пример из архива, то вам необходимо сделать вот такой вызов:

javac -encoding UTF-8 students/logic/*.java

Дело в том, что я использую IDE NetBeans и в ней кодировка UTF-8, которая при обычном запуске не определяется компилятором javac и вы получаете море ошибок. Так что будьте внимательны.
Для запуска наберите следующую команду:

java -cp . students.logic.ManagementSystem

При запуске все данные записываются в файл out.txt. Я ввел его из-за проблем с кодировкой. Файл всегда проще посмотреть — в том же Notepad. Если хочется все-таки выводить данные на консоль — закомментируйте кусок кода, где я перенаправляю стандартный вывод в файл. И Вы можете просто не использовать русский шрифт — используйте только английский. Тогда будет проще.
А пока давайте перейдем к следующей части, где сможем насладиться нормальным видом нашего приложения. Итак, Часть 2 — Введение в GUI

Архив с исходными кодами: Исходный код

2 comments to Используем коллекции

  • Левон  says:

    Здравствуйте,можете мне объяснить зачем в методах loadStudent и loadGroup нужен метод clear, что он будет делать если список не null.

    • admin  says:

      Очищает список. В принципе можно было бы каждый раз создавать список заново. Старый код, писался не так вдумчиво, как хотелось. Сейчас я бы написал иначе.

Leave a reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.