2016-04-13 4 views
1

Angenommen, ich möchte etwas zugreifen wievermeiden endlose null/leer Kontrollen unter Verwendung von Try-Catch

productList.get(0).getCustomerList().get(0).getAddressList().get(0).getRegion.getCode() 

Und auf jeder Stufe I für null oder leere Liste überprüfen müssen. Die Datenstruktur ist wirklich kompliziert, und Refactoring könnte eine Option sein, könnte aber auch zu kompliziert oder unmöglich sein.

Der resultierende Code wäre:

if(productList != null 
    && !productList.isEmpty() 
    && productList.get(0).getCustomerList().get(0) != null 
    && ...){ 
    return productList.get(0).getCustomerList().get(0).getAddressList(0).getRegion.getCode(); 
} 

Der resultierende Code hässlich ist, ausführlich, trägt keine wirkliche Business-Logik und ist schwer zu lesen. Gibt es eine kluge Möglichkeit, das zu vermeiden? Wäre es akzeptabel, zu tun:

try{ 
    return productList.get(0).getCustomerList().get(0).getAddressList(0).getRegion.getCode(); 
} catch(NullPointerException | IndexOutOfBoundException e){ 
    return null; 
} 
+2

https://en.wikipedia.org/wiki/Law_of_Demeter ... – Tom

+0

ein Teaser: 'für {Produkt <- productList.headOption; Kunde <- product.getCustomerList.headOption; Adresse <- customer.getAddressList.headOption} yield {address.getRegion.getCode} 'Dies ergibt eine' Option [Int] ', die den Code enthält oder' None', wenn irgendwo im Pfad ein Element fehlt. Beseitigt das Risiko von 'NullPointerException'. Scala und Functional Programming sind deine Freunde. – maasg

+1

Randnotiz: Listen und andere Aufzählungen sollten eigentlich nie null sein. Leer, ja, null, nein. –

Antwort

2

Ich würde gespalten nur in etwas wie folgt aus:

Product p = getElementOrNull(productList, 0); 
if(p == null) { return null; } 

Customer c = getElementOrNull(p.getCustomerList(), 0); 
if(c == null) { return null; } 

Address a = getElementOrNull(c.getAddressList(), 0); 
if(a == null) { return null; } 

Region r = a.getRegion(); 
if(r == null) { return null; } 

return r.getCode(); 

mit

<T> T getElementOrNull(List<T> list, int index) { 
    if(list == null || index < 0 || index >= list.size()) { 
    return null; 
    }  

    return list.get(index); 
} 

Ausnahmen Mit normalen Code Fluss zu handhaben, wie Sie vorschlagen normalerweise wird nicht beraten. Manchmal sieht es so aus und in einigen Fällen funktioniert es, aber es macht den Code schwieriger zu verstehen (was null oder welcher Index könnte falsch sein) und könnte weniger Erfahrung verwirren Entwickler, die auf Ihren Code stolpern und schlussfolgern, dass es in Ordnung ist Verwenden Sie in anderen Fällen Ausnahmen.

In Ihrem Fall scheinen Sie in Ordnung zu sein, wenn ein Element/eine Liste in der Kette null ist, aber Fälle annehmen, in denen eine Adresse immer eine Region haben muss oder ein Kunde immer eine Adresse haben muss. In diesen Fällen könnten Sie einfach davon ausgehen, dass diese Dinge nicht null sind und die Null-Überprüfungen anpassen, um eine beschreibende Ausnahme (zumindest mit einer besseren Nachricht) zu werfen - was Sie in einem "Catch-All" -Fang nicht tun konnten blockiere wie du.

1

Hier ist ein weiterer Vorschlag mit Java 8 Optional.

Predicate<List> hasElement = list -> list != null && !list.isEmpty(); 

String code = Optional.ofNullable(productList) 
.filter(hasElement).map(p -> p.get(0).getCustomerList()) 
.filter(hasElement).map(c -> c.get(0).getAddressList()) 
.filter(hasElement).map(a -> a.get(0).getRegion()) 
.map(Region::getCode) 
.orElse(null); 
Verwandte Themen