Что такое коллекции — краткое описание
Как уже можно было видеть из описания классов, класс УправляющаяСистема использует два списка — список групп и список студентов. как видите в нашем крайне скудном приложении мы уже столкнулись с ситуацией, когда нам потребуется работать с группой/массивом/списком данных. Будем называть это коллекцией.
Рекомендуем: Здесь не будет приведена подробная информация о коллекциях. Для хорошего ознакомления с ними отсылаем вас к документации по 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 нам пришлось бы использовать следующую конструкцию:
1 2 3 4 5 6 7 |
// Предположим, что мы как-то получили список групп List groups = getGroups(); ... for (Iterator gi = groups.iterator(); gi.hasNext();) { Group group = (Group) gi.next(); System.out.println("---> Группа:" + group.getNameGroup()); } |
Обратите внимание, что мы должны использовать интерфейс Iterator. Это специальный класс, который позволяет работать с коллекцией. Идея его очень простая — при создании итератор указывает на начало коллекции и перемещается к следующему элементу вызовом метода next. Этот метод также возвращает тот объект из коллекции, на который в данный момент указывает итератор. А метод hasNext проверяет — есть ли еще элементы в коллекции. Таким образом можно просмотреть ЛЮБУЮ коллекцию. Также мы вынуждены приводить итератор к нужному нам типу насильно. Что не может не приводить иногда к ошибкам.
А теперь посмотрим на код, который позволяет нам написать Java 1.5
1 2 3 4 5 |
List<Group> groups = getGroups(); // Предположим, что мы как-то получили список групп ... for (Group group : groups) { System.out.println("---> Группа:" + group.getNameGroup()); } |
Как говориться — почувствуйте разницу. Во-первых, мы сразу говорим, что наш список содержит объекты типа Group. Это позволяет нам больше не думать о приведении типа при работе со списком. Компилятор не позволит нам добавлять объекты иного класса, автоматически сделает приведение — в общем всякие вкусности. Во-вторых — обратите внимание на новый вариант прохода по списку — цикл for теперь совсем простой и достаточно симпатично выглядит. По секрету — вы все еще можете использовать Iterator — и он будет работать точно также. Только теперь итератор тоже можно типизировать — например Iterator<Group>. И теперь метод next будет возвращать нужный нам тип данных сразу без приведения.
1 2 3 4 5 6 7 |
// Предположим, что мы как-то получили список групп List groups = getGroups(); ... for (Iterator<Group> gi = groups.iterator(); gi.hasNext();) { Group group = gi.next(); System.out.println("---> Группа:" + group.getNameGroup()); } |
Подводя итог краткому описанию возможностей коллекций я призываю вас очень внимательно отнестись к этому очень мощному инструменту обработки данных. В подавляющем большинстве приложений вам они потребуются обязательно.
А теперь попробуем написать несложную реализацию классов для нашей системы. Наши классы будут находится в следующих файлах JAVA
Student.java
Group.java
ManagementSystem.java
Замечание: Для класса ManagementSystem сделаем метод main, который решает две задачи:
- Запускает класс без каких-либо дополнительных усилий
- Позволяет проверить функциональность системы на тестовых данных
На данном этапе у нас не будет красивого графического интерфейса — мы просто пытаемся описать необходимые функции и проверить их работоспособность. Настоятельно рекомендую: внимательно просмотрите код метода main класса ManagementSystem — там преведены вызовы всех функций, которые мы будем использовать.
Классы Student и Group — эти классы содержат только описания необходимых полей, а также методы для доступа к этим полям. Так называемые сеттеры и геттеры (от слов set/get — установить/получить). Это уже по сути стандартный подход к работе с полями класса — поле для хранения объявляется как private, а для доступа используются методы set/get. Принцип именования следующий:
Имя переменной начинается со строчной буквы – например, ИД студента будет выглядеть как studentId. А методы будут выглядеть вот так:
1 2 3 4 5 6 7 8 9 |
private int studentId; public void setStudentId(int studentId) { this.studentId = studentId; } public int getStudentId() { return this.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 слово «ПАВЕЛ» больше, чем «артем». А при обычном сравнении строк результат обратный. И это понятно — символ «а» имеет числовой код больше, чем «П». Следовательно, сравнение будет некорректным, если данные о ФИО будут внесены в разном регистре. Конечно, можно при вводе приводить все к одному виду, но все-таки надежнее сделать сравнение корректно.
Я все-таки не совсем элегантно все делаю — сравниваю строки, в которых есть номера групп, даты — и в этом случае возможны тоже не совсем корректные сравнения, но предлагаю вам самим сделать необходимые исправления.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import java.text.Collator; import java.util.Locale; public class Test { public static void main(String[] arg) { Collator c = Collator.getInstance(new Locale("ru")); // Если закомментировать следующую строку, то "ПАВЕЛ" будет не равен "Павел" // (c.compare!=0) что по идее не совсем корректно c.setStrength(Collator.PRIMARY); System.out.println(c.compare("ПАВЕЛ", "ПАВЕЛ")); System.out.println(c.compare("ПАВЕЛ", "Павел")); System.out.println(c.compare("ПАВЕЛ", "артем")); System.out.println("ПАВЕЛ".compareTo("артем")); } } |
А теперь приведем код наших классов с комментариями:
Student.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
package students.logic; import java.text.Collator; import java.text.DateFormat; import java.util.Date; import java.util.Locale; public class Student implements Comparable { // поле ИД СТУДЕНТА private int studentId; // поле ИМЯ private String firstName; // поле ФАМИЛИЯ private String surName; // поле ОТЧЕСТВО private String patronymic; // поле ДАТА РОЖДЕНИЯ private Date dateOfBirth; // поле ПОЛ private char sex; // поле ИД ГРУППЫ private int groupId; // поле ГОД ОБУЧЕНИЯ private int educationYear; // get/set для ДАТА РОЖДЕНИЯ public Date getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(Date dateOfBirth) { this.dateOfBirth = dateOfBirth; } // get/set для ГОД ОБУЧЕНИЯ public int getEducationYear() { return educationYear; } public void setEducationYear(int educationYear) { this.educationYear = educationYear; } // get/set для ИД ГРУППЫ public int getGroupId() { return groupId; } public void setGroupId(int groupId) { this.groupId = groupId; } // get/set для ИД СТУДЕНТА public int getStudentId() { return studentId; } public void setStudentId(int studentId) { this.studentId = studentId; } // get/set для ИМЯ public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } // get/set для ОТЧЕСТВО public String getPatronymic() { return patronymic; } public void setPatronymic(String patronymic) { this.patronymic = patronymic; } // get/set для ФАМИЛИЯ public String getSurName() { return surName; } public void setSurName(String surName) { this.surName = surName; } // get/set для ПОЛ public char getSex() { return sex; } public void setSex(char sex) { this.sex = sex; } // DateFormat - класс для преобразования даты // в строку в определеннном формате. // Подробнее смотрите документацию по этому методу public String toString() { return surName + " " + firstName + " " + patronymic + ", " + DateFormat.getDateInstance(DateFormat.SHORT).format(dateOfBirth) + ", Группа ИД=" + groupId + " Год:" + educationYear; } public int compareTo(Object obj) { Collator c = Collator.getInstance(new Locale("ru")); c.setStrength(Collator.PRIMARY); return c.compare(this.toString(), obj.toString()); } } |
Group.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
package students.logic; public class Group { // поле ИД ГРУППЫ private int groupId; // поле ИМЯ ГРУППЫ private String nameGroup; // поле КУРАТОР private String curator; // поле СПЕЦИАЛЬНОСТЬ private String speciality; // get/set для КУРАТОР public String getCurator() { return curator; } public void setCurator(String curator) { this.curator = curator; } // get/set для ИД ГРУППЫ public int getGroupId() { return groupId; } public void setGroupId(int groupId) { this.groupId = groupId; } // get/set для ИМЯ ГРУППЫ public String getNameGroup() { return nameGroup; } public void setNameGroup(String nameGroup) { this.nameGroup = nameGroup; } // get/set для СПЕЦИАЛЬНОСТЬ public String getSpeciality() { return speciality; } public void setSpeciality(String speciality) { this.speciality = speciality; } public String toString() { return nameGroup; } } |
Давайте немного подробнее остановимся на ManagementSystem.java. Этот класс пока не очень сложный, но все таки он дает нам некоторую функциональность. Он позволяет добавить нового студента, изменить параметры студента, перевести всех студентов одной группы в другую (частая ситуация, когда после года обучения студенты переходят в другую группу), удалить студентов из группы — для тех, кто закончил учиться.
Если посмотреть на конструктор ManagementSystem, то можно увидеть, что мы вызываем загрузку списка студентов и групп. Таким образом получится, что при каждом создании ManagementSystem мы будем делать одну и ту же работу, что конечно не очень хорошо.
Для того, чтобы избежать такого мы воспользуемся шаблоном проектирования (очень интересная область знаний, которая описывает стандартные решения для каких-либо проектных задач) Singletone. Этот шаблон показывает, как можно использовать только один экземпляр объекта. Реализация делается следующим образом:
- конструктор объявляется private (теперь напрямую создать объект нельзя)
- описывается одна статическая переменная такого же класса (т.е. для всех объектов класса будет только одна такая переменная)
- создается метод (обычно его называют getInstance), который возвращает ссылку на единственный объект.
После кода мы еще остановимся на некоторых функциях.
ManagementSystem.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
package students.logic; import java.io.FileNotFoundException; import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.TreeSet; public class ManagementSystem { private List<Group> groups; private Collection<Student> students; // Для шаблона Singletone статическая переменная private static ManagementSystem instance; // закрытый конструктор private ManagementSystem() { loadGroups(); loadStudents(); } // метод getInstance - проверяет, инициализирована ли статическая // переменная (в случае надобности делает это) и возвращает ее public static synchronized ManagementSystem getInstance() { if (instance == null) { instance = new ManagementSystem(); } return instance; } // Метод, который вызывается при запуске класса public static void main(String[] args) { // Этот код позволяет нам перенаправить стандартный вывод в файл // Т.к. на экран выводится не совсем удобочитаемая кодировка, // файл в данном случае более удобен try { System.setOut(new PrintStream("out.txt")); } catch (FileNotFoundException ex) { ex.printStackTrace(); return; } ManagementSystem ms = ManagementSystem.getInstance(); // Просмотр полного списка групп printString("Полный список групп"); printString("*******************"); List<Group> allGroups = ms.getGroups(); for (Group gi : allGroups) { printString(gi); } printString(); // Просмотр полного списка студентов printString("Полный список студентов"); printString("***********************"); Collection<Student> allStudends = ms.getAllStudents(); for (Student si : allStudends) { printString(si); } printString(); // Вывод списков студентов по группам printString("Список студентов по группам"); printString("***************************"); List<Group> groups = ms.getGroups(); // Проверяем все группы for (Group gi : groups) { printString("---> Группа:" + gi.getNameGroup()); // Получаем список студентов для конкретной группы Collection<Student> students = ms.getStudentsFromGroup(gi, 2006); for (Student si : students) { printString(si); } } printString(); // Создадим нового студента и добавим его в список Student s = new Student(); s.setStudentId(5); s.setFirstName("Игорь"); s.setPatronymic("Владимирович"); s.setSurName("Перебежкин"); s.setSex('М'); Calendar c = Calendar.getInstance(); c.set(1991, 8, 31); s.setDateOfBirth(c.getTime()); s.setGroupId(1); s.setEducationYear(2006); printString("Добавление студента:" + s); printString("********************"); ms.insertStudent(s); printString("--->> Полный список студентов после добавления"); allStudends = ms.getAllStudents(); for (Student si : allStudends) { printString(si); } printString(); // Изменим данные о студенте - Перебежкин станет у нас Новоперебежкиным // Но все остальное будет таким же - создаем студента с таким же ИД s = new Student(); s.setStudentId(5); s.setFirstName("Игорь"); s.setPatronymic("Владимирович"); s.setSurName("Новоперебежкин"); s.setSex('М'); c = Calendar.getInstance(); c.set(1991, 8, 31); s.setDateOfBirth(c.getTime()); s.setGroupId(1); s.setEducationYear(2006); printString("Редактирование данных студента:" + s); printString("*******************************"); ms.updateStudent(s); printString("--->> Полный список студентов после редактирования"); allStudends = ms.getAllStudents(); for (Student si : allStudends) { printString(si); } printString(); // Удалим нашего студента printString("Удаление студента:" + s); printString("******************"); ms.deleteStudent(s); printString("--->> Полный список студентов после удаления"); allStudends = ms.getAllStudents(); for (Student si : allStudends) { printString(si); } printString(); // Здесь мы переводим всех студентов одной группы в другую // Мы знаем, что у нас 2 группы // Не совсем элегантное решение, но пока сделаем так Group g1 = groups.get(0); Group g2 = groups.get(1); printString("Перевод студентов из 1-ой во 2-ю группу"); printString("***************************************"); ms.moveStudentsToGroup(g1, 2006, g2, 2007); printString("--->> Полный список студентов после перевода"); allStudends = ms.getAllStudents(); for (Student si : allStudends) { printString(si); } printString(); // Удаляем студентов из группы printString("Удаление студентов из группы:" + g2 + " в 2006 году"); printString("*****************************"); ms.removeStudentsFromGroup(g2, 2006); printString("--->> Полный список студентов после удаления"); allStudends = ms.getAllStudents(); for (Iterator i = allStudends.iterator(); i.hasNext();) { printString(i.next()); } printString(); } // Метод создает две группы и помещает их в коллекцию для групп public void loadGroups() { // Проверяем - может быть наш список еще не создан вообще if (groups == null) { groups = new ArrayList<Group>(); } else { groups.clear(); } Group g = null; g = new Group(); g.setGroupId(1); g.setNameGroup("Первая"); g.setCurator("Доктор Борменталь"); g.setSpeciality("Создание собачек из человеков"); groups.add(g); g = new Group(); g.setGroupId(2); g.setNameGroup("Вторая"); g.setCurator("Профессор Преображенский"); g.setSpeciality("Создание человеков из собачек"); groups.add(g); } // Метод создает несколько студентов и помещает их в коллекцию public void loadStudents() { if (students == null) { // Мы используем коллекцию, которая автоматически сортирует свои элементы students = new TreeSet<Student>(); } else { students.clear(); } Student s = null; Calendar c = Calendar.getInstance(); // Вторая группа s = new Student(); s.setStudentId(1); s.setFirstName("Иван"); s.setPatronymic("Сергеевич"); s.setSurName("Степанов"); s.setSex('М'); c.set(1990, 3, 20); s.setDateOfBirth(c.getTime()); s.setGroupId(2); s.setEducationYear(2006); students.add(s); s = new Student(); s.setStudentId(2); s.setFirstName("Наталья"); s.setPatronymic("Андреевна"); s.setSurName("Чичикова"); s.setSex('Ж'); c.set(1990, 6, 10); s.setDateOfBirth(c.getTime()); s.setGroupId(2); s.setEducationYear(2006); students.add(s); // Первая группа s = new Student(); s.setStudentId(3); s.setFirstName("Петр"); s.setPatronymic("Викторович"); s.setSurName("Сушкин"); s.setSex('М'); c.set(1991, 3, 12); s.setDateOfBirth(c.getTime()); s.setEducationYear(2006); s.setGroupId(1); students.add(s); s = new Student(); s.setStudentId(4); s.setFirstName("Вероника"); s.setPatronymic("Сергеевна"); s.setSurName("Ковалева"); s.setSex('Ж'); c.set(1991, 7, 19); s.setDateOfBirth(c.getTime()); s.setEducationYear(2006); s.setGroupId(1); students.add(s); } // Получить список групп public List<Group> getGroups() { return groups; } // Получить список всех студентов public Collection<Student> getAllStudents() { return students; } // Получить список студентов для определенной группы public Collection<Student> getStudentsFromGroup(Group group, int year) { Collection<Student> l = new TreeSet<Student>(); for (Student si : students) { if (si.getGroupId() == group.getGroupId() && si.getEducationYear() == year) { l.add(si); } } return l; } // Перевести студентов из одной группы с одним годом обучения в другую группу с другим годом обучения public void moveStudentsToGroup(Group oldGroup, int oldYear, Group newGroup, int newYear) { for (Student si : students) { if (si.getGroupId() == oldGroup.getGroupId() && si.getEducationYear() == oldYear) { si.setGroupId(newGroup.getGroupId()); si.setEducationYear(newYear); } } } // Удалить всех студентов из определенной группы public void removeStudentsFromGroup(Group group, int year) { // Мы создадим новый список студентов БЕЗ тех, кого мы хотим удалить. // Возможно не самый интересный вариант. Можно было бы продемонстрировать // более элегантный метод, но он требует погрузиться в коллекции более глубоко // Здесь мы не ставим себе такую цель Collection<Student> tmp = new TreeSet<Student>(); for (Student si : students) { if (si.getGroupId() != group.getGroupId() || si.getEducationYear() != year) { tmp.add(si); } } students = tmp; } // Добавить студента public void insertStudent(Student student) { // Просто добавляем объект в коллекцию students.add(student); } // Обновить данные о студенте public void updateStudent(Student student) { // Надо найти нужного студента (по его ИД) и заменить поля Student updStudent = null; for (Student si : students) { if (si.getStudentId() == student.getStudentId()) { // Вот этот студент - запоминаем его и прекращаем цикл updStudent = si; break; } } updStudent.setFirstName(student.getFirstName()); updStudent.setPatronymic(student.getPatronymic()); updStudent.setSurName(student.getSurName()); updStudent.setSex(student.getSex()); updStudent.setDateOfBirth(student.getDateOfBirth()); updStudent.setGroupId(student.getGroupId()); updStudent.setEducationYear(student.getEducationYear()); } // Удалить студента public void deleteStudent(Student student) { // Надо найти нужного студента (по его ИД) и удалить Student delStudent = null; for (Student si : students) { if (si.getStudentId() == student.getStudentId()) { // Вот этот студент - запоминаем его и прекращаем цикл delStudent = si; break; } } students.remove(delStudent); } // Этот код позволяет нам изменить кодировку // Такое может произойти если используется IDE - например NetBeans. // Тогда вы получаете просто одни вопросы, что крайне неудобно читать public static void printString(Object s) { //System.out.println(s.toString()); try { System.out.println(new String(s.toString().getBytes("windows-1251"), "windows-1251")); } catch (UnsupportedEncodingException ex) { ex.printStackTrace(); } } public static void printString() { System.out.println(); } } |
Итак, самое интересно на взгляд автора кроется в следующих функциях:
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;
Это значит, что Вам надо создать вот такую структуру каталогов:
1 2 3 4 5 |
- /student - /logic - Student.java - Group.java - ManagementSystem.java |
Для того, чтобы собрать наш проект Вам надо установить текующую директорию, в которой находится директория 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
Архив с исходными кодами: Исходный код