что можно сделать, чтобы избежать скрытой ошибки из-за автобокса при работе с записями - PullRequest
1 голос
/ 26 января 2020

Иногда я пишу небольшие сценарии, либо для управления записями в БД, либо для создания некоторых данных для целей отчетности.

В большинстве случаев мы используем тип Long для идентификатора объекта пользователя. Если я сделаю что-то вроде следующего:

List<Long> listOfLong = Arrays.asList(1L, 2L, 3L);
System.out.println(listOfLong.contains(2));

, он вернет false, но для этого:

System.out.println(integers.contains(2L));

вернет true.

Не должны ли мы получить ошибку времени компиляции для такой вещи?

Ответы [ 4 ]

5 голосов
/ 26 января 2020

Причина, по которой вы не видите ошибку компиляции, заключается в том, что подпись для contains в Collection<E> определяется как:

boolean contains(Object o)

Это верно, Object. Не contains(<E> o).

(Почему они определили это таким образом? Я понимаю, что это для совместимости с версиями Java до Java 5, когда типы коллекций не были обобщенными c. Если они переопределили Метод contains в Java 5, разрешающий только аргументы <E>, может привести к поломке большого количества кода, который работал в более ранних версиях Java.)

Итак, что касается компилятора , экземпляр Integer является подходящим типом аргумента при вызове contains для List<Long>.

Разве мы не должны получить ошибку времени компиляции для такой вещи?

Нет. Это действительно Java.

(Если вы имеете в виду «должен» в смысле «было бы лучше, если бы» ... тогда я согласен. Но contains был определен таким образом по причине, и пути назад нет. )

Что можно сделать, чтобы избежать скрытой ошибки

Попробуйте использовать анализатор кода stati c, например FindBugs или PMD. Я не знаю наверняка, обнаружат ли эти инструменты эту конкретную ошибку, но они могут найти и другие ошибки.

Кроме этого:

  • Еще тестирование.
  • Измените свою кодовую базу, чтобы использовать пользовательский тип для идентификаторов. Тот, который не может быть автоматически / распакован. (Много работы, и лекарство может быть хуже болезни ... как говорится.)
1 голос
/ 26 января 2020

Вы спросили:

Разве мы не должны получить ошибку времени компиляции для такой вещи?

Да, я бы предпочел это, и, возможно, так и было бы , если бы сегодня Java было сделано с нуля снова.

Если бы это было серьезной проблемой в моем коде, я бы создал обертку для числа, например

class UserId {
  public UserId(long id) { ... }
  public long getId() { ... }
}
0 голосов
/ 28 января 2020

Чтобы добавить к другим, правильные ответы: хотя это не ошибка компиляции (поскольку ничто в JLS не нарушено), ваш инструмент может выдать предупреждение. Eclipse скажет вам:

Невероятный тип аргумента int для contains(Object) для Collection<Long>

Невероятный тип аргумента long для contains(Object) для Collection<Integer>

0 голосов
/ 26 января 2020

содержит проверку с использованием метода equals для параметра Тип объекта

 boolean contains(Object o)

список содержит хотя бы один элемент e такой, что (o==null ? e==null : o.equals(e))

Если вы не помните / уверены, что вы установите значение Long, прежде чем использовать его

Вы можете сначала преобразовать его в long, вы можете использовать Long.valueOf

List<Long> listOfLong = Arrays.asList(1l, 2l, 3l);
System.out.println(listOfLong.contains(Long.valueOf(2)));

Или сделать значение 2 передается как параметр метода, поэтому он будет длинным в сигнатуре метода

public void myMethod(Long number) {
     List<Long> listOfLong = Arrays.asList(1l, 2l, 3l);
     System.out.println(listOfLong.contains(number));
}
...