views:

126

answers:

6

Hi,

I have a statement as follows

getLD().get(cam.getName()).getAGS().get(aG.getName())

getLD(), getAGS() return Java collections

I would not consider it to be an error if getAGS() were empty, nor if the result of getAGS().get(aG.getName()) were empty. However it is rather messy and somewhat of a pain checking for these null conditions.

e.g. if(getLD().get(camp.getName()).getAGS() !=null && getLD().get(cam.getName()).getAGS().get(aG.getName()) != null) {

Can anyone suggest the best way to deal with this? Obviously I could create a variable x = getLD().get(camp.getName()).getAGS() to shorten the code, but is there a way in which I would not have to do the two checks for null?

All help is much appreciated!

A: 
try {
   foo().bar().baz();
} catch (NullPointerException e) {
    // Check if it was actually an error
}
Borealid
Dirty, but definitely what I'd consider using if I have to write a.().b().c().d()!
Enno Shioji
Ugh, no! This will silently discard any NPE thrown by foo(), bar(), or baz().
Sean
I would consider this bad code. What happens if the implementation of one of these methods throws a NullPointerException internally?
RMorrisey
True, but if you are strictly using a java bean (like a JAXB generated DTO), that risk seems not to exist to me..
Enno Shioji
+1  A: 

The apache commons project has a library called Bean Introspection Utilities (BeanUtils), which looks like it can do what you need. Check out the nested property access section, in the user guide, and look at the BeanUtils class:

http://commons.apache.org/beanutils/

It has utility classes that I think can do what you need.

Another thing to consider: you should try to avoid doing this many levels of nested property access. This is a code smell called "feature envy", where an object wants to use features of another object regularly. Consider creating methods on the top-level object, or find a way to redesign so that the feature you need is shared more readily.

RMorrisey
A: 

Code in groovy!.

Not always possible depending on your environment and performance requirments. But its a joy to just type

if (getLD(camp?.GetName())?.getAGS(ag?.GetName()))

Alternativly you could just code what you mean and catch the null pointer exception. In your case this would be much more readable especially of you dont care which element is null.

James Anderson
+3  A: 

IMO, the best strategy is to design your data structures so that there aren't any nulls in the first place. For example, use empty collections or zero length arrays, or "" instead of null. For application classes, consider implementing special instance that you can use instead of null.

A second strategy is to replace use of exposed generic data structures (e.g. maps, lists, arrays) with custom classes. This hides the implementation details inside a class, and allows you to make use of Java's static typing to avoid many of the situations where a null check would be required.

A third strategy is to create a helper class with a bunch of methods that implement common operations; e.g. "get the Cam for an LD". (IMO, this approach is a poor alternative, compared with the others, but at least it reduces the amount of code repetition.)

To the extent that you cannot get rid of the nulls, you've got no option but to explicitly test for them. (There was a proposal to add an "elvis" operator to Java 7 as part of project Coin, but unfortunately it was cut.)

Stephen C
Mostly agree, but in case like JAXB, they generate the structure for you and unfortunately there is no consideration for that..
Enno Shioji
So if I have a HashMap with elements put with keys "1" and "2", but I try to get the value of key "3" how do I get this to return something other than null?
QuakerOat
@Zwei - that is covered by my second paragraph. If the `null` values cannot be designed away, you need to explicitly test for them ... or use a different language.
Stephen C
@QuackerOat - if you want to avoid null checks you shouldn't be using HashMaps as your primary data structures. Write and use custom classes instead.
Stephen C
+3  A: 

The best way would be to avoid the chain. If you aren't familiar with the Law of Demeter (LoD), in my opinion you should. You've given a perfect example of a message chain that is overly intimate with classes that it has no business knowing anything about.

Law of Demeter: http://en.wikipedia.org/wiki/Law_of_Demeter

Jerod Houghtelling
A: 

I think Something is more complext than needed if you require to do

getLD().get(cam.getName()).getAGS().get(aG.getName())

If you need to check if the second collection or the result is null you can do something like:

Map<?,?> firstList= getLD();
Object value = null;
if (firstList!=null && !firstList.isEmpty() && fistList.containsKey(cam.getName())){
    Map<?,?> secondList = firstList.get(cam.getName());
    if (secondList!=null && !secondList.isEmpty() && secondList.containsKey(aG.getName())){
        value = secondList.get(aG.getName());
    }
}

if(value != null){
  // Do the required operations if the value is not null
}else{
  // Do the required operations if the value is null
}

With this code i checked if the first collection is not null, is not empty and if it has the content. The i get the second collection and i repeated the process in the second collection.

Also a method can be created to do this operation:

private Map<?,?> getItem(Map<?,?> map,Object key){
    if (map!=null && !map.isEmpty() && map.containsKey(key)){
        return map.get(key);
    }
    return null;
}

and in your code:

Object value = getItem(getItem(getLD(),cam.getName()),aG.getName());

if(value != null){
    // Do the required operations if the value is not null
}else{
     // Do the required operations if the value is null
}
Dubas