Потратил несколько часов на обобщение некоторых подверженных ошибкам знаний по Java!

Java

Эта статья взята сJavaGuide(61k+Star! [Java Learning + Interview Guide] Копия основных знаний, которые необходимо освоить большинству Java-программистов. Добро пожаловать в Star! Добро пожаловать в травлю!)

Исходный адрес: https://javaguide.cn/2019/08/20/java/java%E5%9F%BA%E7%A1%80/Java%E7%96%91%E9%9A%BE%E7%82 %B9/

1. Основы

1.1. Правильное использование метода equals

Метод equals объекта склонен генерировать исключения нулевого указателя.Вы должны использовать константы или объекты с определенными значениями для вызова equals.

Например:

// 不能使用一个值为null的引用类型变量来调用非静态方法,否则会抛出异常
String str = null;
if (str.equals("SnailClimb")) {
  ...
} else {
  ..
}

Запуск вышеуказанной программы вызовет исключение нулевого указателя, но если мы изменим оператор условного суждения во второй строке на следующий, исключение нулевого указателя не будет выдано, и будет выполнен блок операторов else. :

"SnailClimb".equals(str);// false 

Однако рекомендуется использоватьjava.util.Objects#equals(Класс инструментов, представленный JDK7).

Objects.equals(null,"SnailClimb");// false

Давайте взглянемjava.util.Objects#equalsИсходный код будет знать причину.

public static boolean equals(Object a, Object b) {
        // 可以避免空指针异常。如果a==null的话此时a.equals(b)就不会得到执行,避免出现空指针异常。
        return (a == b) || (a != null && a.equals(b));
    }

Уведомление:

Reference:Причины и решения исключения нулевого указателя, вызванного методом equals в Java

  • Каждый примитивный тип имеет одно и то же значение по умолчанию, например, значение по умолчанию для int равно 0, значение по умолчанию для логического значения — false, а значение null — это значение по умолчанию для любого ссылочного типа, строго говоря, значение по умолчанию для всех типов объектов. .
  • Вы можете использовать операции == или != для сравнения нулевых значений, но не другие арифметические или логические операции. на Явеnull == nullвернет истину.
  • Нестатический метод нельзя вызывать с переменной ссылочного типа, значение которой равно null, иначе будет выдано исключение

1.2 Сравнение значений класса целочисленной оболочки

Все сравнения значений объектов целочисленного класса-оболочки должны использовать метод equals.

Взгляните на следующий пример:

Integer x = 3;
Integer y = 3;
System.out.println(x == y);// true
Integer a = new Integer(3);
Integer b = new Integer(3);
System.out.println(a == b);//false
System.out.println(a.equals(b));//true

Когда объект Integer создается с использованием метода автоупаковки, когда значение находится в диапазоне от -128 до 127, созданный объект Integer будет кэшироваться.Когда значение появится в следующий раз, соответствующий объект Integer будет извлечен непосредственно из кэша. Таким образом, в приведенном выше коде x и y относятся к одному и тому же объекту Integer.

Уведомление:Если в вашей среде IDE (IDEA/Eclipse) установлен подключаемый модуль Alibaba p3c, этот подключаемый модуль сообщит об ошибке, если обнаружит, что вы используете ==. Рекомендуется установить этот подключаемый модуль, что очень хорошо.

1.3. BigDecimal

1.3.1. Полезность BigDecimal

В «Руководстве по разработке Java для Alibaba» упоминается:Для оценки равенства между числами с плавающей запятой базовые типы данных не могут сравниваться с помощью ==, а типы данных пакета не могут оцениваться по равенству.Конкретный принцип связан с методом кодирования чисел с плавающей запятой, поэтому я не буду его здесь упоминать, а сразу перейдем к примеру ниже:

float a = 1.0f - 0.9f;
float b = 0.9f - 0.8f;
System.out.println(a);// 0.100000024
System.out.println(b);// 0.099999964
System.out.println(a == b);// false

Обладая базовыми математическими знаниями, мы знаем, что на выходе получается не то, что нам нужно (потеря точности), как решить эту проблему? Очень распространенный метод:Используйте BigDecimal для определения значения чисел с плавающей запятой, а затем выполняйте операции с числами с плавающей запятой.

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
BigDecimal c = new BigDecimal("0.8");
BigDecimal x = a.subtract(b);// 0.1
BigDecimal y = b.subtract(c);// 0.1
System.out.println(x.equals(y));// true 

1.3.2 Сравнение размеров BigDecimal

a.compareTo(b): Возвращает -1, если меньше, 0, если равно, 1, если больше.

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
System.out.println(a.compareTo(b));// 1

1.3.3. BigDecimal сохраняет несколько знаков после запятой

пройти черезsetScaleМетод устанавливает количество сохраняемых десятичных разрядов и правила хранения. Правил хранения довольно много, запоминать не нужно, IDEA подскажет.

BigDecimal m = new BigDecimal("1.255433");
BigDecimal n = m.setScale(3,BigDecimal.ROUND_HALF_DOWN);
System.out.println(n);// 1.255

1.3.4 Меры предосторожности при использовании BigDecimal

Примечание. Когда мы используем BigDecimal, во избежание потери точности рекомендуется использовать егоBigDecimal(String)Конструктор для создания объектов. В «Руководстве по разработке Java для Alibaba» также упоминается эта часть, как показано на рисунке ниже.

《阿里巴巴Java开发手册》对这部分BigDecimal的描述

1.3.5. Резюме

BigDecimal в основном используется для работы с (большими) числами с плавающей запятой, а BigInteger в основном используется для работы с большими целыми числами (больше, чем тип long).

Реализация BigDecimal использует BigInteger, разница в том, что BigDecimal добавляет концепцию десятичных разрядов.

1.4 Стандарт использования базовых типов данных и типов данных-оболочек

Ссылка: «Руководство по разработке Java для Alibaba»

  • [Обязательно] Все свойства класса POJO должны использовать типы данных-оболочек.
  • [Обязательно] Возвращаемые значения и параметры методов RPC должны использовать типы данных-оболочек.
  • [Рекомендуется] Используйте примитивные типы данных для всех локальных переменных.

Например, если мы настраиваем класс Student, одним из которых является оценка атрибута, если мы используем Integer вместо int для определения теста, студент может не пройти тест, значение равно null или он может пройти тест. , но оценка теста равна 0, значение равно 0, состояние этих двух выражений явно различно.

инструкцияАтрибут класса :POJO не имеет начального значения, чтобы напомнить пользователю, что он должен быть явно назначен, когда его необходимо использовать.Любая проблема NPE или проверка хранилища гарантируется пользователем.

Положительный пример: Результат запроса к базе данных может быть нулевым из-за автоматической распаковки, получение с примитивными типами данных имеет риск NPE.

Контрпример: Например, для отображения взлетов и падений общего оборота, то есть положительного или отрицательного x%, x — это базовый тип данных, и вызванная служба RPC, когда вызов не удался, возвращается значение по умолчанию, и на странице отображается 0%, что нецелесообразно и должно отображаться пунктирной линией. Следовательно, нулевое значение упакованного типа данных может представлять дополнительную информацию, такую ​​как: сбой удаленного вызова, аварийный выход.

2. Коллекция

2.1. Руководство по использованию Arrays.asList()

Недавно использованныйArrays.asList()Я столкнулся с некоторыми ямами, а затем увидел эту статью в Интернете:Java Array to List ExamplesЭто чувствует себя довольно хорошо, но не очень всеобъемлющим. Итак, я сделал краткое изложение этого небольшого пункта знаний.

2.1.1 Введение

Arrays.asList()Это относительно распространено в обычной разработке, и мы можем использовать его для преобразования массива в коллекцию List.

String[] myArray = { "Apple", "Banana", "Orange" }; 
List<String> myList = Arrays.asList(myArray);
//上面两个语句等价于下面一条语句
List<String> myList = Arrays.asList("Apple","Banana", "Orange");

Исходный код JDK описывает этот метод:

/**
 *返回由指定数组支持的固定大小的列表。此方法作为基于数组和基于集合的API之间的桥梁,与           Collection.toArray()结合使用。返回的List是可序列化并实现RandomAccess接口。
 */ 
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

2.1.2.Описание в "Руководстве по разработке Java для Alibaba"

Arrays.asList()После преобразования массива в коллекцию нижний слой фактически является массивом.Руководство по разработке Java для Alibaba описывает этот метод следующим образом:

阿里巴巴Java开发手-Arrays.asList()方法метод.png)

2.1.3. Краткий обзор мер предосторожности при использовании

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

Arrays.asList()Является универсальным методом, входящий объект должен быть массивом объектов.

int[] myArray = { 1, 2, 3 };
List myList = Arrays.asList(myArray);
System.out.println(myList.size());//1
System.out.println(myList.get(0));//数组地址值
System.out.println(myList.get(1));//报错:ArrayIndexOutOfBoundsException
int [] array=(int[]) myList.get(0);
System.out.println(array[0]);//1

При передаче массива примитивных типов данныхArrays.asList()Настоящим параметром являются не элементы массива, а сам объект массива! Единственным элементом списка на данный момент является этот массив, который объясняет приведенный выше код.

Мы можем решить эту проблему, используя массив типов оболочки.

Integer[] myArray = { 1, 2, 3 };

Модифицированные методы с использованием коллекций:add(),remove(),clear()вызовет исключение.

List myList = Arrays.asList(1, 2, 3);
myList.add(4);//运行时报错:UnsupportedOperationException
myList.remove(1);//运行时报错:UnsupportedOperationException
myList.clear();//运行时报错:UnsupportedOperationException

Arrays.asList()метод возвращает неjava.util.ArrayList, ноjava.util.ArraysВнутренний класс , этот внутренний класс не реализует методы модификации коллекции или не переопределяет эти методы.

List myList = Arrays.asList(1, 2, 3);
System.out.println(myList.getClass());//class java.util.Arrays$ArrayList

На картинке нижеjava.util.Arrays$ArrayListВ простом исходном коде мы можем увидеть, какие методы переписаны в этом классе.

  private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        ...

        @Override
        public E get(int index) {
          ...
        }

        @Override
        public E set(int index, E element) {
          ...
        }

        @Override
        public int indexOf(Object o) {
          ...
        }

        @Override
        public boolean contains(Object o) {
           ...
        }

        @Override
        public void forEach(Consumer<? super E> action) {
          ...
        }

        @Override
        public void replaceAll(UnaryOperator<E> operator) {
          ...
        }

        @Override
        public void sort(Comparator<? super E> c) {
          ...
        }
    }

давайте посмотрим еще разjava.util.AbstractListизremove()метод, поэтому мы можем понять, почему он бросаетUnsupportedOperationException.

public E remove(int index) {
    throw new UnsupportedOperationException();
}

2.1.4 Как правильно преобразовать массив в ArrayList?

переполнение стека: https://dwz.cn/vcBkTiTW

1. Сделай сам (в образовательных целях)

//JDK1.5+
static <T> List<T> arrayToList(final T[] array) {
  final List<T> l = new ArrayList<T>(array.length);

  for (final T s : array) {
    l.add(s);
  }
  return (l);
}

Integer [] myArray = { 1, 2, 3 };
System.out.println(arrayToList(myArray).getClass());//class java.util.ArrayList

2. Самый простой способ (рекомендуется)

List list = new ArrayList<>(Arrays.asList("a", "b", "c"))

3. Используйте поток Java8 (рекомендуется)

Integer [] myArray = { 1, 2, 3 };
List myList = Arrays.stream(myArray).collect(Collectors.toList());
//基本类型也可以实现转换(依赖boxed的装箱操作)
int [] myArray2 = { 1, 2, 3 };
List myList = Arrays.stream(myArray2).boxed().collect(Collectors.toList());

4. Используйте гуаву (рекомендуется)

Для неизменяемых коллекций вы можете использоватьImmutableListклассы и ихof()иcopyOf()Заводской метод: (параметр не может быть пустым)

List<String> il = ImmutableList.of("string", "elements");  // from varargs
List<String> il = ImmutableList.copyOf(aStringArray);      // from array

Для изменяемых коллекций вы можете использоватьListsклассы и ихnewArrayList()Заводской метод:

List<String> l1 = Lists.newArrayList(anotherListOrCollection);    // from collection
List<String> l2 = Lists.newArrayList(aStringArray);               // from array
List<String> l3 = Lists.newArrayList("or", "string", "elements"); // from varargs

5. Использование коллекций Apache Commons

List<String> list = new ArrayList<String>();
CollectionUtils.addAll(list, str);

2.2 Яма, используемая методом Collection.toArray(), и как перевернуть массив

Метод является общим методом: T[] toArray(T[] a);еслиtoArrayЕсли в метод не переданы параметры, возвращаетсяObjectтипизированный массив.

String [] s= new String[]{
    "dog", "lazy", "a", "over", "jumps", "fox", "brown", "quick", "A"
};
List<String> list = Arrays.asList(s);
Collections.reverse(list);
s=list.toArray(new String[0]);//没有指定类型的话会报错

Благодаря оптимизации JVM,new String[0]в видеCollection.toArray()Параметры метода теперь используются лучше,new String[0]Он действует как шаблон, указывающий тип возвращаемого массива, 0 используется для экономии места, потому что это только для иллюстрации типа возвращаемого значения. Видеть:

2.3. Не выполнять операции удаления/добавления над элементами в циклах foreach

Если вы хотите сделатьremoveоперация, которая может вызвать функцию итератораremove метод вместо метода удаления класса коллекции. Потому что если список структурно модифицируется в любой момент после создания итератора, никак иначе, как через сам итераторremove/addметоды, итераторы оба будут генерироватьConcurrentModificationException, который генерируется в однопоточном состоянииотказоустойчивый механизм.

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

java.utilВсе классы коллекций в пакете отказоустойчивы, в то время какjava.util.concurrentВсе классы в пакете отказоустойчивы.

不要在 foreach 循环里进行元素的 remove/add 操作

Рекомендация проекта с открытым исходным кодом

Другие рекомендации автора по проектам с открытым исходным кодом:

  1. JavaGuide: [Изучение Java + интервью] Обложка, которая охватывает основные знания, которые необходимо освоить большинству Java-программистов.
  2. springboot-guide: Учебное пособие по Spring Boot, подходящее для начинающих и опытных разработчиков (поддержка в свободное время, добро пожаловать в совместную поддержку).
  3. programmer-advancement: Я думаю, некоторые хорошие привычки, которые должны быть у техников!
  4. spring-security-jwt-guide:Начинать с нуля! Spring Security с JWT (включая проверку авторизации) бэкэнд-часть кода.

публика

我的公众号