-
Перетворення масиву в ArrayList .
Для перетворення масиву в ArrayList розробники часто використовують такий спосіб:
List<String> list = Arrays.asList(arr);
Arrays.asList()
поверне об'єкт класуArrayList
який є внутрішнім приватним статичним класом(private static class)
класуArrays
, а це не клас.java.util.ArrayList.
Класjava.util.Arrays.ArrayList
містить методиset()
,get()
,contains()
, але не містить жодних методів для додавання елементів, його розмір фіксований . Для створення сьогоденняjava.util.ArrayList
слід зробити так:ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));
Конструктор класу
java.util.ArrayList
може приймати як параметр всі об'єкти реалізують інтерфейсCollection
, реалізацію якого успадкував і класjava.util.Arrays.ArrayList
(private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable).
-
Перевіряє масив на наявність конкретного значення.
Розробники часто роблять так:
Set<String> set = new HashSet<String>(Arrays.asList(arr)); return set.contains(targetValue);
Код виходить робочий, але немає необхідності перетворювати
List
наSet
. ПеретворенняSet
займе додатковий час. Насправді все просто:Arrays.asList(arr).contains(targetValue);
або
for(String s: arr){ if(s.equals(targetValue)) return true; } return false;
Перший спосіб значно коротший.
-
Видалення елемента з
List
циклуРозглянемо наступний код, який видаляє елементи в циклі:
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d")); for (int i = 0; i < list.size(); i++) { list.remove(i); } System.out.println(list);
Висновок:
[b, d]
Виходить серйозна помилка. Коли елемент видалено, розмір
List
зменшується та індекси елементів змінюються.Так що відмовтеся від такого способу, якщо ви хочете видалити кілька елементів у циклі, використовуючи індекс.
Можливо ви знаєте, що використання ітератора правильне рішення для видалення елементів у циклі, і ви знаєте, що цикл в стилі
for-each
працює як ітератор, але це не так.Розглянемо наступний код:
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d")); for (String s : list) { if (s.equals("a")) list.remove(s); }
Ми отримаємо виняток ConcurrentModificationException .
Правильно вчинити так:
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d")); Iterator<String> iter = list.iterator(); while (iter.hasNext()) { String s = iter.next(); if (s.equals("a")) { iter.remove(); } }
Метод
У циклі в стиліnext()
має бути викликаний до методуremove()
.for-each
компілятор викличе методremove()
, а вже потімnext()
, що викличе помилкуConcurrentModificationException
. Ви можете переглянути кодArrayList.iterator()
. -
Hashtable
протиHashMap
.Через відповідну реалізацію, Hashtable — це назва структури даних.
Але в Java назва для структури даних це
HashMap
. Одне з ключових відмінностей міжHashtable
іHashMap
це те, щоHashtable
синхронізовано.Так що не варто використовуватиHashtable
там де більше підходитьHashMap
. -
Використання колекцій без обмежень за вмістом
Java часто плутають колекції без обмежень за вмістом, і колекції з маскою за типом вмісту. Наприклад, для множин -
Set
це колекція без обмежень за вмістом, аSet<?>
- колекція у якої все-таки є обмеження, але ці обмеження нічого насправді не обмежують. Розглянемо наступний код, деList
без обмежень використовується як параметр методу:public static void add(List list, Object o){ list.add(o); } public static void main(String[] args){ List<String> list = new ArrayList<String>(); add(list, 10); String s = list.get(0); }
Цей код викине виняток:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at …
Використання колекцій без обмежень за вмістом дуже небезпечне, тому що ви не можете бути впевненими, що там лежить усередині. А для того щоб зрозуміти всю глибину різниці між ,
Set
іSet<?>
-Set<Object>
почитайте ось це посилання . -
Рівень доступу
Найчастіше для полів класу розробники використовують модифікатор доступу
public
. Так простіше отримати значення поля безпосередньо. Правильніше використовувати якомога обмеженіший доступ до членів класу. ArrayList
протиLinkedList
Коли розробники не знають чим відрізняється
ArrayList
відLinkedList
, вони використовують перший з його більшої популярності. Однак, є величезна різниця у продуктивності між ними. Насправді вибір між ними повинен бути продиктований їх внутрішніми особливостями —ArrayList
дозволяє швидко здійснювати доступ до довільного елементу масиву, аLinkedList
— швидко додавати/видаляти елементи в масиві. Почитайте статтю за посиланням ArrayList vs. LinkedList щоб зрозуміти причини їхньої різної продуктивності.Mutable
(Змінний) протиImmutable
(Незмінний)Незмінний об'єкт має багато переваг: простота, безпека тощо. Але він вимагає окремого об'єкта для кожного нового значення, і за дуже багато об'єктів доведеться заплатити зниженням продуктивності. Повинен бути баланс при виборі між об'єктом, що змінюється і незмінним.
В основному щоб уникнути підготовки проміжних об'єктів використовується об'єкт, що змінюється. Один із класичних прикладів це конкатенація великої кількості рядків. Якщо ви використовуєте незмінний об'єкт типу
String
, то ви створюєте багато об'єктів, які відразу потраплять до збирача сміття. Це витрачає час і енергію процесора, тому правильне рішення це використання об'єктів, що змінюються (наприкладStringBuilder
).String result=""; for(String s: arr){ result = result + s; }
Ще один приклад використання об'єктів, що змінюються - передача такого об'єкта в метод. Це дозволить повернути результат у ньому без створення зайвих об'єктів. Працюючи з об'єктами великого розміру, наприклад колекціями, передача колекції в спосіб сортування і повернення результату до іншої колекції призводить до зайвої витрати ресурсів. ( Відповідь користувача dasblinkenlight на Stack Overflow ).
-
Конструктори класів
Super
таSub
Ця помилка компіляції викликана тим, що у класу-предка не визначено конструктора за умовчанням. У Java , якщо ви самі не опишите конструктор класу, компілятор сам створить конструктор за замовчуванням, який не вимагає жодних аргументів. Якщо ж конструктор описаний у класі ,
Super
якSuper(String s){}
компілятор сам нічого додавати не буде. Що ми й спостерігаємо у нашому прикладі.Конструктор класу
Sub
, не важливо який з них, викличе конструктор за умовчанням класуSuper
, оскільки не вказано нічого іншого. Оскільки конструктора за умовчанням у класіSuper
немає, це призведе до помилки компіляції.Перший варіант вирішення цієї проблеми - додати конструктор за замовчуванням до класу
Super
public Super(){ System.out.println("Super"); }
Другий варіант - видаліть описаний нами конструктор із класу
Super
, щоб компілятор створив за замовчуванням конструктор.І останній варіант - додайте виклик
super(value)
у конструктори класуSub
, щоб замість конструктора за замовчуванням викликався конструктор класуSuper
-
" " чи конструктор?
Є два способи створити рядок:
//1. использовать двойные кавычки String x = "abc";
//2. использовать конструктор String y = new String("abc");
У чому між ними різниця?
Ви можете зрозуміти це з таких прикладів:
String a = "abcd"; String b = "abcd"; System.out.println(a == b); // True System.out.println(a.equals(b)); // True String c = new String("abcd"); String d = new String("abcd"); System.out.println(c == d); // False System.out.println(c.equals(d)); // True
Для того щоб докладніше дізнатися про те, як рядки зберігаються в пам'яті, читайте Create Java String Using "" or Constructor? .
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ