2015-07-16 2 views
2

Я хочу проверить нулевой указатель при доступе к полем нескольких классов в глубину (в цепочке методов get). Однако, если один из ранних методов - null, я получаю NullPointerException в любом случае.Java NullPointerException проверка на цепные методы

Это то, что я хочу, чтобы проверить, хотя он все еще может получить NullPointerException:

if(x.getLocation().getBuilding().getSolidFuelInd() != null) 
      pol.setWood_heat_ind(x.getLocation().getBuilding().getSolidFuelInd() ? "Y" : "N"); 

Это поведение, я хочу, приведенный выше код, чтобы показать:

if(x.getLocation() != null) 
    if(x.getLocation().getBuilding() != null) 
     if(x.getLocation().getBuilding().getSolidFuelInd() != null) 
      pol.setWood_heat_ind(x.getLocation().getBuilding().getSolidFuelInd() ? "Y" : "N"); 

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

Есть ли какой-нибудь более короткий способ проверить все выше, как я хочу?

+0

Почему вы не прилагаете первое решение в блоке 'try catch NPE'? – Codebender

+0

Я мог бы, но я считаю, что попытки/уловы предназначены для обработки ошибок в коде. Получение нулевого указателя не было бы атипичным поведением. – tfbbt8

+0

Это также не намного чище, чем мой второй фрагмент кода. Я знаю, как справиться с ошибкой, я просто искал более простой и привлекательный способ сделать это. – tfbbt8

ответ

0

Вы могли бы просто поймать исключение

try{ 
     pol.setWood_heat_ind(x.getLocation().getBuilding().getSolidFuelInd() ? "Y" : "N"); 
    }catch(NullPointerException e){ 
     //e.printStackTrace(); or whatever you want 
    } 

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

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

Object loc=null,build=null; 

    Boolean SFI = ((loc=x.getLocation())==null?null: 
        ((build=loc.getBuilding())==null?null: 
         (build.getSolidFuelInd()))); 

    if(SFI!=null)pol.setWood_heat_ind(SFI?"Y":"N"); 

Но стоит ли это? Я сделал это более сложным, чем это было возможно, но в любом случае, зачем это делать, если вы можете try...catch в двух простых строках?

+0

Я мог бы, но я чувствую, что try/catchs предназначены для обработки ошибок в коде. Получение нулевого указателя не было бы атипичным поведением. – tfbbt8

+0

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

+0

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

0

Вы могли бы сократить это очень немного, комбинируя условия в один, если тест:

if (x.getLocation() != null 
&& x.getLocation().getBuilding() != null 
&& x.getLocation().getBuilding().getSolidFuelInd() != null) { 
    pol.setWood_heat_ind(x.getLocation().getBuilding().getSolidFuelInd() ? "Y" : "N"); 
} 

, но в остальном, нет, это примерно так же коротким, как он получает.

Поймать исключение может быть слишком широким, если что-то в реализации одного из этих геттеров изменится и вызывает NPE, после чего это может быть пойманным и в конечном итоге скрывать доказательства ошибки. Использование тестов if более преднамеренное и более преднамеренное.

Jay's version тоже хорошо, +1 от меня. Но это может привести к простому проверке. И его код не оставляет свойство Wood_heat_ind null, если любое из полей x равно null.

+0

Я чувствую, что так я склоняюсь. Try/catch для меня используются для изменения логики кода при обнаружении ошибки. В моем случае я просто хочу продолжить, будет ли значение установлено. – tfbbt8

+0

спасибо за товарища +1 –

2

Если вы хотите уменьшить его код, вы можете сохранить каждый вызов в переменной.

// note: Replace type with the correct type 
type location = x.getLocation(); 
type building = location == null ? null : location.getBuilding(); 

// note: you don't have to check for null on primitive types 
pol.setWood_heat_ind(building != null && building.getSolidFuelInd() ? "Y" : "N"); 

Это намного чище и легче следовать.

Пища для размышлений, вы не проверяют null на примитивных типов boolean, int, byte и т.д., поэтому последний null проверка building.getSolidFuelInd() не требуется

1

Java 8 имеет Optional<T>, который бы для одного прикованного выражения, хотя многословным.

Однако Java 8 также имеет Stream<T>, и у вас может быть «поток» 0 или 1, а затем запрос с лямбдами.

x.getLocation() 
    .map((loc) -> loc.getBuilding()) 
    .map((building) -> building.getSolidFuelInd() != null) 
    .findFirst() 
    .ifPresent ... 

Или

x.getLocation() 
    .map(Location::getBuilding) 
    .map(Building::getSolidFuelInd()) 
    .filter(fuelInd -> fuelId != null) 
    .findFirst() 
    .ifPresent ... 

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

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