10 ошибок, которые проще всего написать на Java

Java задняя часть
10 ошибок, которые проще всего написать на Java

Оригинальная ссылка:10 раздражающих ошибок

Тот кто, сегодня опять написал баг, да он вроде про меня говорит. . . . . .

Как разработка Java, мы неизбежно будем генерировать всевозможные причудливые ошибки в процессе написания кода.Некоторые ошибки довольно неприятны, такие как различные исключения нулевого указателя, а операция удаления в итерации ArrayList вызовет исключение, индекс массива исключение за пределами границ и т. д.

Если вы случайно увидите код коллеги с описанными мной ошибками, то свалите на него эту статью! ! ! Кинешь ему статью, и пусть обратит внимание на волну cxuan, ты пожнешь его глаза, как сокровище, и поклонишься великому богу в спину.

Без лишних слов, давайте к делу.

Ошибка 1: Преобразование массива в ArrayList

Могу ли я ошибиться при преобразовании Array в ArrayList? Что это за дурак. . . . . .

Подождите, не беспокойтесь об этом, давайте сначала посмотрим, что происходит.

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

List<String> list = Arrays.asList(arr);

Arrays.asList() вернет ArrayList, который является частным статическим классом в Arrays, который не является классом java.util.ArrayList. Как показано ниже

image-20211005232205213

ArrayList внутри Arrays имеет только методы set, get, contains и другие, но нет такого метода, как add, который может изменить его внутреннюю структуру, поэтому размер ArrayList внутри Arrays фиксирован.

image-20211006094537453

Если вы хотите создать ArrayList, который может добавлять элементы, вы можете использовать следующий метод создания:

ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));

Это возможно, потому что конструктор ArrayList принимает коллекцию.

image-20211006094827686

Ошибка № 2: Проверка, содержит ли массив значение

Проверка наличия в массиве определенного значения, что часто делают некоторые программисты:

Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);

Несмотря на то, что этот код корректен, он имеет дополнительную потерю производительности, в обычных условиях нет необходимости преобразовывать его вset, просто сделайте это так:

return Arrays.asList(arr).contains(targetValue);

Или используйте следующий метод (исчерпывающий метод, петлевая оценка)

for(String s: arr){
	if(s.equals(targetValue))
		return true;
}
return false;

Первый фрагмент кода выше читается лучше, чем второй.

Ошибка № 3: Циклический просмотр списков для удаления элементов

Я считаю, что многие мелкие партнеры знают об этой ошибке. Удаление элементов в цикле является табу. Какое-то время, когда я просматривал код, мне нравилось смотреть, совершают ли эту ошибку другие мелкие партнеры в команде.

image-20211006101709155

Ведь почему нельзя сделать это (удалить элементы из коллекции)? И посмотрите на код ниже

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]

Почему только два значения? Разве я не зацикливаю вывод?

На самом деле, внутри списка, когда вы используетевнешнийПри удалении, как только элемент будет удален, изменится внутренняя структура списка.В начале общая емкость коллекции равна 4, а после удаления элемента станет 3, а затем сравнить и судить с i. . . . . . Таким образом, можно вывести только два элемента.

Вы, вероятно, знаете, что использование итератора — это правильный способ удаления элемента, и вы, вероятно, знаете, что 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);
}

Затем вы уверенно запускаете метод xxx.main() и получаете результат. . . . . .ConcurrentModificationException

Зачем?

Это связано с тем, что использование внешнего элемента удаления в ArrayList приведет к изменению его внутренней структуры и курсора.

В спецификации разработки Ali также есть инструкции не выполнять операции удаления/добавления над элементами в цикле for-each.

image-20211006100608623

Поэтому, если вы хотите использовать список для добавления или удаления элементов, вы должны использовать итератор для удаления. это

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(). В цикле foreach компилятор вызовет .next() после операции по удалению элемента, что вызовет исключение ConcurrentModificationException.

Ошибка № 4: Hashtable и HashMap

Это алгоритмическая спецификация: по алгоритму Hashtable — это имя структуры данных, а в Java имя структуры данных — HashMap.Одно из основных отличий Hashtable от HashMap заключается в том, что раз вам не нужен Hashtable, вместо этого используйте HashMap.

Ошибка № 5: Использование коллекций примитивных типов

Это общее ограничение:

В Java примитивные типы и неограниченные подстановочные типы легко смешиваются. Возьмем, к примеру, Set. 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);
}

Этот код выдастjava.lang.ClassCastExceptionненормально, почему?

image-20211006162921268

Использование коллекций типов-примитивов опасно, потому что типы-примитивы пропускают общие проверки и небезопасны.Set、Set<?> 和 Set<Object>Существуют огромные различия, и дженерики склонны к стиранию типов при их использовании.

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

как определено в кодеList<Object>иList<String>и другие типы, станутList, все, что видит JVM, этоList, в то время как информация о типе, прикрепленная дженериками, невидима для JVM. Компилятор Java попытается выяснить, что может пойти не так, во время компиляции, но он по-прежнему не может увидеть исключение преобразования типа, которое возникает во время выполнения.Стирание типа также является важным отличием между дженериками Java и реализацией механизма шаблонов C++.

Например следующий пример

public class Test {

    public static void main(String[] args) {

        ArrayList<String> list1 = new ArrayList<String>();
        list1.add("abc");

        ArrayList<Integer> list2 = new ArrayList<Integer>();
        list2.add(123);

        System.out.println(list1.getClass() == list2.getClass());
    }

}

В этом примере мы определяем дваArrayListмассивы, но одинArrayList<String>Универсальные типы могут хранить только строки;ArrayList<Integer>Универсальные типы могут хранить только целые числа Наконец, мы передаемlist1объект иlist2объектgetClass()метод, чтобы получить информацию об их классе, и, наконец, обнаружил, что результатtrue. Описание универсальных типовStringиIntegerвсе стерты, остался только исходный тип.

Итак, в верхнем фрагменте кода совершенно нормально добавить 10 к типу объекта, но преобразование «10» типа объекта в тип String вызовет исключение преобразования типа.

Ошибка № 6: Проблемы с уровнем доступа

Я считаю, что большинство разработчиков будут просто и грубо объявлять напрямую при разработке переменных класса или члена.public xxx, это плохой дизайн, и легко быть голым, когда он объявлен общедоступным, что опасно для классов или переменных-членов.

Ошибка 7: ArrayList и LinkedList

Ха-ха-ха, ArrayList — это наиболее часто используемый класс инструментов, который я видел, чтобы программисты использовали, никто.

image-20211006165557687

Когда разработчики не знают разницы между ArrayList и LinkedList, они часто используют ArrayList (на самом деле, даже если они знают их разницу, они не используют LinkedList, потому что производительность не стоит упоминания), потому что ArrayList кажется более привычным. . . . . .

Но на самом деле существует огромная разница в производительности между ArrayList и LinkedList, короче говоря, LinkedList следует предпочесть, если операции добавления/удаления тяжелые, а операции произвольного доступа — нет. ArrayList предпочтительнее, если есть много операций доступа, но ArrayList не подходит для выполнения большого количества операций добавления/удаления.

Ошибка 8: Изменчивость и неизменяемость

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

Вообще говоря, изменяемые объекты используются, чтобы избежать создания слишком большого количества промежуточных объектов. Скажем, вы хотите объединить много строк. Если вы используете неизменяемую строку, вы создадите много объектов, которые могут быть немедленно удалены сборщиком мусора. Это тратит впустую время и усилия ЦП, и использование изменяемых объектов является правильным решением (например, StringBuilder). Как показано в следующем коде:

String result="";
for(String s: arr){
	result = result + s;
}

Поэтому правильный выбор изменяемых или неизменяемых объектов требует тщательного решения.

Ошибка 9: Конструкторы

Сначала посмотрите на фрагмент кода и проанализируйте, почему он не компилируется?

image-20211006172246303

Эта ошибка компиляции возникает из-за того, что конструктор для Super по умолчанию не определен. В Java, если класс не определяет конструктор, компилятор по умолчанию вставляет конструктор без аргументов для класса. Если конструктор определен в классе Super, в данном случае Super(String s), компилятор не будет вставлять конструктор без параметров по умолчанию. Это относится к классу Super выше.

Чтобы это исправить, просто добавьте в Super конструктор без параметров.

public Super(){
    System.out.println("Super");
}

Ошибка 10: использовать "" или конструктор

Рассмотрим следующий код:

String x = "abc";
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

Это типичная проблема распределения памяти.

постскриптум

Сегодня я расскажу вам о 10 распространенных ошибках в Java-разработке. Хотя они относительно просты, их легко игнорировать. Детали идеальны. Посмотрим, совершишь ли ты это снова. Если совершишь еще раз, хе-хе.

image-20211005230533419

Нравится, смотришь, делишься кругом друзей — базовое упражнение! Давай, в один клик три ссылки! ! !