
Преобразование массива в 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?.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Делаю так:
Как вариант:
А то всегда найдется тот, кто не будет вчитываться, а скопипастит сразу же))
Да читабельность улучшитья — т.к. статья по существу о коде.