2011-01-24 2 views
9

У меня есть некоторый код по следующему шаблону:Неплохо ли использовать NullPointerException для проверки нулевого значения?

return a().b().c().d().e(); 

теперь, так как каждый из этих методов может вернуться null, один, как правило, проверить для этого:

if((a()!=null) && (a().b() != null) && ....) { 
    return a().b().c().d().e(); 
} else { 
    return null; 
} 

(и, возможно, использовать некоторые локальные переменные чтобы избежать повторяющихся вызовов)

Я испытываю желание сделать:

try { 
    return a().b().c().d().e(); 
} catch (NullPointerException e) { 
    return null; 
} 

Это считается плохой стиль? неэффективны? Или совсем нормально?

+0

Я думаю, что использовать исключения для управления потоком управления плохо. – Sweeper

ответ

16

Не делайте этого. Исключение броска и ловушки довольно дорого по сравнению с базовыми нулевыми проверками.

Возможно, вам также будет интересно узнать, какой синтаксис был предложен для будущей версии Java, что сделало бы это проще. Было бы примерно так:

a()?.b()?.c()?.d() 

«?». операция будет необязательной версией «.». оператор. Если значение LHS равно null, оно будет возвращать null в этой точке вместо того, чтобы пытаться оценить RHS. Именно то, что вы ищете, но я боюсь, что он не сделал сокращение для Java 7. Не знаю статус этой функции для Java 8.

+0

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

+1

@Martijn Courteaux: Вопрос не в том, будет ли работать над улавливанием NPE. Это ясно. Вопрос в том, является ли получение привычки писать такой код, это хорошая идея. Это не так. –

1

Вместо того, чтобы возвращать null, пусть каждый из них вернуть NullObject или что-то в этом роде. Читайте о Null Object Pattern.

+1

Хотя объект Null может быть полезным, он может скрыть некоторые проблемы и сделать отладку сложнее. НЕ используйте его, если только выигрыш сохраняет пару тестов в одном месте. – maaartinus

2

Я бы этого не сделал, потому что, если у a() или b() или c() и т. Д. Есть ошибка, которая заставляет их бросать NullPointerException? В этом случае вы поймаете его и продолжаете, когда вам этого не будет.

2

Измените методы, чтобы они не возвращали значение null или не избегали методов цепочки, которые могут возвращать значение null.

5

Это считается плохим стилем, поскольку исключения должны представлять собой исключительные условия, которые вряд ли могут возникнуть при нормальном выполнении, и которые указывают на то, что что-то пошло не так. Использование исключений для проверки того, являются ли объекты нулями, использует это оборудование для проверки более мирских сбоев. Как упоминалось в сообщении Константина, есть также штраф за выполнение за исключением исключений. Кроме того, обертывание всех ошибок в одном из NullPointerException означает, что вы теряете информацию о том, что, в частности, пошло не так. Какая функция вернулась null? Это из-за обычных ошибок, или что-то более серьезное происходит?

Есть и другие варианты, которые вы не учли здесь. Вместо того, чтобы иметь a(), b(), и т. Д., Возвращать null, чтобы сигнализировать об ошибке, подумайте о том, чтобы они бросили более подробные исключения, объясняющие, почему они не могут что-то вернуть. Если они потерпят неудачу из-за падения сетевого соединения, попросите их бросить IOException или что-то подобное. Если они терпят неудачу, потому что у вас есть плохой индекс в массиве, сделайте это также ясным.

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

5

Как правило, эта строка кода была бы плохой, игнорируя нулевую проблему. См. "Law of Demeter" or "Principle of Least Knowledge".

return a().b().c().d().e(); 

Если я не имел никакого контроля над а, б, в, г, е, я бы переписать в следующем.

if((a()!=null) && (a().b() != null) && ....) { 
    return a().b().c().d().e(); 
} else { 
    return null; 
} 

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

B b = a.a(); 
if(b == null) 
{ 
    return null; 
} 

C c = b.b(); 
if(c == null) 
{ 
    return null; 
} 

D d = c.c(); 
if(d == null) 
{ 
    return null; 
} 

return d.d(); 

Нет, ловя NullPointerException не является подходящим, что нужно сделать. Это вроде как обертывание петли for в блоке try, чтобы поймать ArrayIndexOutOfBoundsException.

Если это должно быть fluent API, где целая цепь - это сила и цель, то она никогда не должна возвращать нули.

+1

Я вообще согласен, но у вас не всегда есть выбор, например. при использовании сторонних библиотек. Другой случай, когда это может произойти много, - это сопоставления DB объекта - отношения, например: resultSet.getFirst(). GetPerson(). GetBusinessUnit(). GetAddress(). GetPostCode(); если схема БД допускает очень частичную информацию, этот случай может случиться много. – Carsten

+0

+1 для сравнения с массивом без сравнения, это точка на. – Epaga

Смежные вопросы