Недавно я обнаружил необычную ошибку в моем коде случайным ad-hoc-тестированием. Итак, я сделал для этого тестовый пример.
Вот мой тестовый пример:
SampleRequest request = new SampleRequest();
request.setA(null);
request.setB(null);
assertEquals(null, request.getAOrB());
A и B определяются как типы java.lang.Integer и имеют прямые методы настройки, чтобы установить их значения в запрос.
Существует также перечисление. Он имеет примитивное целочисленное значение и метод, используемый в этом коде. Я разместил здесь следующие разделы:
enum Swapper {
public int c;
Swapper findSwapperToUse(final int a) {
for(Swapper swapper : values()) {
if(swapper.c == a) {
return swapper;
}
}
return null;
}
}
Теперь, здесь метод, который запутывает. Вызов метода теста для этого метода приводит к NPE, но в последней строке метода.
public class SampleRequest {
private Integer A;
private Integer B;
public void setA(final Integer A) {
this.A = A;
}
public void setB(final Integer B) {
this.B = B;
}
public Integer getAOrB() {
return A != null ? Swapper.findSwapperToUse(A).c
: B;
}
}
В тесте оба A и B установлены в нуль. Следовательно, A!= Null возвращает false. Тем не менее, я получаю исключение NullPointerException в номере строки для строки: B.
Я предполагаю, что по какой-то причине оценивается первое выражение Swapper.findSwapperToUse(A).c, и поэтому A.intValue() вызывается с помощью autoboxing, в результате чего NullPointerException имеет значение null. Благодаря отладке известно, что findSwapperToUse() не вызывается.
Однако, согласно этому вопросу, этого не должно произойти: Явная трехмерная (немедленная) оценка
Выраженное выражение операнда не оценивается для этой конкретной оценки условного выражения.
Возврат null (B) не приведет к исключению NullPointerException - он отлично подходит для возврата здесь нулевого результата.
Что происходит?
EDIT: Я забыл добавить, что я изменил код, чтобы избежать этого, используя оператор "прямо вверх" if - следующий код работает как ожидалось:
public Integer getAOrB() {
if(A != null) {
return Swapper.findSwapperToUse(A).c;
}
return B;
}