Конспект вийшов досить громіздким, тож поділив його на дві частини. У другій частині зібрані відповіді на питання щодо канкаренсі та багатопоточності. У першій частині решта. Написання далося досить важко. Багато чого все одно не розумію, тому як завжди, коментарі, зауваження, доповнення – вітаються)
obj. На відміну від методу
1. Як користуватись інтерфейсом Comparable?
В інтерфейсіComparable
оголошено лише один метод compareTo(Object obj)
, призначений для реалізації впорядкування об'єктів класу. Його зручно використовувати при сортуванні впорядкованих списків чи масивів об'єктів. Даний метод порівнює об'єкт, що викликається зequals
, який повертає
true або
false ,
compareTo
повертає:
- 0 якщо значення рівні;
- Негативне значення, якщо об'єкт, що викликається, менший за параметр;
- Позитивне значення , якщо об'єкт, що викликається, більший за параметр.
java.util.List
) та масивів об'єктів. Якщо список/масив містить елементи, що реалізують цей інтерфейс, вони можуть бути відсортовані автоматично методами
java.util.Collections.sort(List)/Arrays.sort(Object[])
. З інтерфейсом
Comparable
пов'язане поняття натурального впорядкування, оскільки він встановлює натуральний порядок екземплярів будь-якого класу, що реалізує цей інтерфейс. Інакше висловлюючись, порядок (x, y) відповідає виконанню умови
x.compareTo(y) <= 0
. Правила реалізації
Comparable
, а вірніше, його методу
compareTo(Object)
такі (x та y – екземпляри класу, що реалізує
Comparable
):
x.compareTo(y)
повертає -1 або 1, якщо x повинен знаходитися відповідно раніше або пізніше y. Якщо метод повертає 0, то порядки (x, y) та (y, x) еквівалентні.- Якщо
sign(a)
– функція, що повертає -1,0,1 для а, відповідно, менше 0, що дорівнює 0 і більше 0, то має виконуватись рівністьsign(x.compareTo(y))==-sign(y.compareTo(x))
. Що логічно: якщо x йде раніше за y, то y повинен йти пізніше x, і навпаки. - Якщо
x.compareTo(y) > 0
іy.compareTo(z) > 0
, тоx.compareTo(z) > 0
співвідношення транзитивності нерівностей. - Якщо
x.compareTo(y) == 0
, тоsign(x.compare(z)) == sign(y.compareTo(z))
для будь-яких z. - Виклик
x.compareTo(null)
повинен кидати винятокNullPointerException
. У цьому є розбіжність із логікою реалізаціїequals
(нагадаю,x.equals(null)
повертає false ). - Якщо y за своїм типом не може бути порівняний з x, виклик
x.compareTo(y)
повинен кидати винятокClassCastException
. (x.compareTo(y) == 0) == x.equals(y)
, тобто. викликx.compareTo(y)
повинен повертати 0 тоді, і тільки тоді, колиx.equals(y)
повертає true . Це правило несуперечливості, і його дуже важливо враховувати.
- Сортування та впорядкування. Інтерфейси Comparable та Comparator
- Упорядкування – інтерфейс java.lang.Comparable
2. Як користуватись інтерфейсом Comparator?
В інтерфейсіComparator
оголошено два методи
compare(Object obj1, Object obj2)
та
equals(Object obj)
. При використанні інтерфейсу
Comparator
логіка порівняння пари об'єктів не ховається всередину класу/об'єкта, а реалізується в окремому класі. Метод
compare(x,y)
точно відповідає за своєю суттю виклику
x.compareTo(y)
. Так само повинні виконуватися всі правила, як і правила реалізації методу
compareTo(Object)
інтерфейсу
Comparable
.
Comparator
може використовуватися в будь-якому місці, де потрібне сортування. При цьому, по-перше, з'являється необхідна гнучкість – можливість кількох правил сортування. А по-друге, об'єкти, що сортуються, можуть не реалізовувати інтерфейс
Comparable
. Якщо вони його все-таки реалізують,
Comparator
має пріоритет. Інтерфейс
Comparator
визначає ще й метод
equals(Object)
, хоч як це парадоксально. Цей метод служить для порівняння самих екземплярів інтерфейсу
Comparator
і повинен повертати
true тільки в тому випадку, якщо об'єкти, що порівнюються, забезпечують однаковий порядок сортування. Однак завжди безпечно залишати вихідну реалізацію
Object.equals(Object)
недоторканою
.
- Сортування та впорядкування. Інтерфейси Comparable та Comparator
- Упорядкування – інтерфейс java.lang.Comparable
3. Які методи мають клас Collections?
public static <T> boolean addAll(Collection<? super T> c, T... elements)
Метод додає елементи масиву
elements
до колекції
Collection<? super T> c
. Елементи можуть бути вказані поодинці або як масив. Коли елементи вказані окремо, цей метод надає можливість зручно додати всі елементи до наявної колекції:
Collections.addAll(flavors, "Peaches 'n Plutonium", "Rocky Racoon");
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)
public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
Обидва методи шукають у списку переданому в параметрі об'єкт, переданий у параметрі, використовуючи алгоритм двійкового пошуку. Повертають індекс елемента, якщо такий елемент у списку є, інакше індекс першого елемента списку більшого
key
, якщо всі елементи менші
key
, повертає
list.size()
. Перед використанням цих методів списки мають бути відсортовані. У першому випадку відсортовані за зростанням у "природному" порядку прямування елементів списку (такий самий, як при використанні
Collections.sort(list)
). У другому випадку список повинен бути відсортований за зростанням у порядку слідування, який забезпечує переданий компаратор (такий самий порядок, як при використанні
Collections.sort(list, c)
[тут "с" - компаратор з параметрів методу, що описується))
public static <E> Collection<E> checkedCollection(Collection<E> c, Class<E> type)
Преамбула: механізм дженериків у мові забезпечує перевірку типів під час компіляції . Зазвичай цього й достатньо, проте трапляються випадки, коли таки немає. Наприклад, ми нашу колекцію передаємо в код бібліотеки, кудись набік, нам невідому, і нам дуже хочеться, щоб код цієї "third-party library" не вставив у нашу колекцію елемент неправильного типу. Це ось можлива проблема №1. Можлива проблема №2 наступна. Припустимо наша програма видає нам
ClassCastException
, який повідомляє нам про те, що в колекцію був вставлений елемент неправильного типу. На жаль, цей виняток може вилетіти в будь-який момент, після того, як неправильний елемент був вставлений, і зазвичай надає нам зовсім небагато або взагалі нуль інформації про джерело проблеми. Використовуючи метод метод
checkedCollection
ми можемо позбавити себе проблеми один і два, т.к. цей метод створює колекцію, що перевіряється на етапі виконання. Вирішення проблеми номер два, за допомогою цього методу: Наприклад ми маємо ось це, і у нас вивалюється
ClassCastException
.
Collection<String> c = new HashSet<String>();
Код вище можна тимчасово замінити на:
Collection<String> c = Collections.checkedCollection(
new HashSet<String>(), String.class);
При запуску програми ми знову локалізуємо рядок коду, який вставляє елемент неправильного типу в нашу колекцію. Споріднені на мій погляд методи:
public static <E> List<E> checkedList(List<E> list,Class<E> type)
public static <K,V> Map<K,V> checkedMap(Map<K,V> m, Class<K> keyType,Class<V> valueType)
public static <E> Set<E> checkedSet(Set<E> s,Class<E> type)
public static <K,V> SortedMap<K,V> checkedSortedMap(SortedMap<K,V> m,Class<K> keyType,Class<V> valueType)
public static <E> SortedSet<E> checkedSortedSet(SortedSet<E> s,Class<E> type)
public static <T> void copy(List<? super T> dest,List<? extends T> src)
Метод копіює елементи src у dest. індекси у копійованих елементів збігатимуться.
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
public static <T> T min(Collection<? extends T> coll,Comparator<? super T> comp)
public static <T> T max(Collection<? extends T> coll,Comparator<? super T> comp)
Способи повертають мінімальний\максимальний елемент у колекції з погляду "природного порядку"(інтерфейс Comparable) або порядку переданого компаратора.
public static boolean disjoint(Collection<?> c1,Collection<?> c2)
Повертає
true якщо колекції не мають однакових елементів.
<T> List <T> emptyList(), <K,V> Map <K,V> emptyMap(),
<T> Set <T> emptySet()
– повертають порожній список, карту відображення та безліч відповідно;
<T> void fill(List<? super T> list, T obj)
- Заповнює список заданим елементом;
int frequency(Collection<?> c, Object o)
– повертає кількість входження до колекції заданого елемента;
<T> List <T> nCopies(int n, T o)
– повертає список із
nзаданих елементів;
<T> boolean replaceAll(List<T> list, T oldVal, T newVal)
- Замінює всі задані елементи новими;
void reverse(List<?> list)
- "перевертає" список;
void rotate(List<?> list, int distance)
- Зсуває список циклічно на задану кількість елементів;
void shuffle(List<?> list)
- Перетасовує елементи списку;
<T> Set <T> singleton(T o), singletonList(T o), singletonMap(K key, V value)
- Створюють безліч, список і карту відображення, що складаються з одного елемента;
<T extends Comparable<? super T>> void sort(List<T> list),
<T> void sort(List<T> list, Comparator<? super T> c)
– сортування списку, природним порядком та використовуючи
Comparator
відповідно;
void swap(List<?> list, int i, int j)
– змінює місцями елементи списку, що стоять на заданих позиціях.
Джерела:
4. Які методи є у класу Arrays?
Повний перелік методів класу Arrays можна побачити у документації . У цьому конспекті наведу лише деякі з них. [перекладав методи з документації, і на жаль втратив більшу частину свого перекладу. Прикро, і витрачати час на те саме не хочеться, так що вставлю нагуглене]public static <T> List<T> asList(T... a)
формує список на основі масиву. Масив у своїй використовується для внутрішнього уявлення списку. Таким чином зберігається зв'язок між списком та вихідним масивом: зміни в масиві позначаться на списку:
String[] a = { "foo", "bar", "baz"};
List<String> list = Arrays.asList(a);
System.out.println(list); // [foo, bar, baz]
a[0] = "aaa";
System.out.println(list); // [aaa, bar, baz]
зміни у списку позначаться на масиві:
String[] a = { "foo", "bar", "baz"};
List<String> list = Arrays.asList(a);
System.out.println(list); // [foo, bar, baz]
list.set(0, "bbb");
System.out.println(Arrays.toString(a)); // [bbb, bar, baz]
Якщо масив містить об'єкти, очевидно, і масив і список будуть посилатися на одні й ті самі екземпляри:
Object[] a = { new Object(), new Object(), new Object()};
List<Object> list = Arrays.asList(a);
System.out.println(a[0] == list.get(0)); // true
int binarySearch(параметры)
– перевантажений метод організації бінарного пошуку значення масивах примітивних і об'єктних типів. Повертає позицію першого збігу;
void fill(параметры)
– перевантажений метод для заповнення масивів значеннями різних типів та примітивами;
void sort(параметри) – перевантажений метод сортування масиву або його частини з використанням інтерфейсу Comparator без нього;
static <T> T[] copyOf(T[] original, int newLength)
-Заповнює масив певної довжини, відкидаючи елементи або заповнюючи null при необхідності;
static <T> T[] copyOfRange(T[] original, int from, int to)
- Копіює задану область масиву в новий масив;
<T> List<T> asList(T… a)
– метод, що копіює елементи масиву об'єкт типу List<T>.
Джерело:
5. Як називається сортування, яке використовується під час виклику Collections.sort()?
З документації : Реалізація є адаптованим варіантом сортування списку для Python Тіма Петерса (TimSort). Дана реалізація скидає список масив, сортує масив, потім проходить по списку і перезавантажує кожен елемент списку з відповідного елемента масиву. Це дозволяє уникнути складності n*n log(n), яка виникла б при спробі відсортувати зв'язковий список безпосередньо .: Timsort - гібридний алгоритм сортування, що поєднує сортування вставками та сортування злиттям, опублікований в 2002 році Тімом Петерсом. В даний час Timsort є стандартним алгоритмом сортування у Python, OpenJDK 7 та реалізований в Android JDK 1.5. Основна ідея алгоритму в тому, що в реальному світі масиви даних, що сортуються, часто містять у собі впорядковані підмасиви. На таких даних Timsort значно швидше за багато алгоритмів сортування.10. Що таке ітератор?
Поданий у релізі JDK 1.2 мови Java інтерфейсjava.util.Iterator
забезпечує ітерацію контейнерних класів. Кожен Iterator реалізує методи
next()
і
hasNext()
додатково може підтримувати метод
remove()
. Ітератори створюються відповідними контейнерними класами, зазвичай методом
iterator()
. Метод
next()
переводить ітератор на таке значення і повертає значення ітератору. При початковому створенні ітератор вказує на спеціальне значення перед першим елементом, тому перший елемент можна отримати тільки після першого виклику
next()
. Для визначення моменту, коли всі елементи контейнера були перебрані, використовується тестовий метод
hasNext()
. Наступний приклад демонструє просте використання ітераторів:
Iterator iter = list.iterator();
//Iterator<MyType> iter = list.iterator(); в J2SE 5.0
while (iter.hasNext())
System.out.println(iter.next());
Для колекції типів, що підтримує подібне, метод ітератора
remove()
видаляє останній "відвіданий" елемент контейнера. Багато інших типів модифікації контейнера під час ітерації є небезпечними. Крім того,
java.util.List
існує
java.util.ListIterator
з подібним API, але що дозволяє пряму і зворотну ітерації, забезпечуючи визначення поточного індексу в списку і перехід до елемента за його позицією.
Джерело:
Частина 2
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ