2013-07-25 1 views
1

Est-il possible d'intégrer le code suivant dans une fonction réutilisable?La fonction appelante doit renvoyer la valeur par défaut, si l'objet (ou tout autre résultat de la fonction) est nul

EDIT:cela est juste un exemple, je veux une solution de travail pour toutes les profondeurs de récursion

ce que je veux est que le code suivant est généré:

if (MyObject o == null || 
    o.getSubObject() == null || 
    o..getSubObject().getSubSubObject() == null /*|| 
    ... */) 
    return defaultValue; 
return o.getSubObject().getSubObject()/*...*/.getDesiredValue(); 

en appelant quelque chose comme

Object defaultValue = null; 
Object result = NullSafeCall(o.getSubObject().getSubObject()/*...*/.getDesiredValue(), defaultValue); 

Le bloc de code seond est juste une idée, je ne sais pas attention à quoi il ressemble, tout ce que je veux, c'est que je, si désiré, peut éviter toutes les vérifications null avant d'appeler une fonction plus profonde ...

L'injection pourrait faire cela propably, mais il n'y a pas d'autre/solution plus facile? Jamais regardé injection avant encore ...

EDIT2:exemple dans une autre langue: http://groovy.codehaus.org/Operators#Operators-SafeNavigationOperator

+0

Je suis intéressé par chaque solution ... la raison pour laquelle cette question est survenue est un projet android cependant ... – prom85

Répondre

1

Pas vraiment, tout code que vous écrivez cette façon regarderait horrible et/ou utiliser la réflexion très lent. Sauf si vous utilisez un préprocesseur Java réel qui peut comprendre et modifier le code que vous avez écrit.

Une meilleure approche (mais associée à un peu de refactoring) serait de s'assurer que les valeurs en question ne peuvent pas être nulles. Par exemple, vous pouvez modifier les accesseurs individuels (getSubObject(), getDesiredValue()) pour ne jamais renvoyer de null en premier lieu: faites-les retourner les valeurs par défaut. Les accesseurs sur les valeurs par défaut retournent les valeurs par défaut à leur tour.

+0

c'est une solution, je sais ... en fait, je me fous si ces fonctions retournent null, tout ce que je veux est une valeur par défaut (peut-être même nulle) pour être le résultat, si n'importe quel objet (quel que soit le niveau) est nul ... pour éviter le NullPointerException ... je pensais juste qu'il pourrait y avoir, comme vous l'avez dit, par exemple une solution de préprocesseur ou autre chose ... et dans mon cas, j'accède à une instance d'une classe abstraite, qui ne peut être créée qu'à un moment précis ... et avant cela, je ne veux pas créer une instance vide sans raison ... – prom85

+0

Quelque chose comme ceci: http://groovy.codehaus.org/Operators#Operators-SafeNavigationOperator Malheureusement, c'est une langue différente. –

+0

BTW a trouvé un billet de blog qui proposait ceci pour Java7 - apparemment, il n'a pas été inclus. Http://blog.joda.org/2009/01/java-7-null-default-and-null-safe_7527.html –

0

Vous pouvez faire quelque chose comme ça

public static Object NullSafeCall(MyObject o,Object defaultValue){ 
    if (o == null || o.getSubObject() == null) 
    { 
     return defaultValue; 
    } 
    else 
    { 
     return o.getSubObject().getDesiredValue(); 
    } 
} 

Maintenant, vous pouvez appeler cette méthode comme suit

Object result = NullSafeCall(o, defaultValue); 
+0

merci, je suis au courant de cette solution SPECIFIQUE, ce que je want est une fonction/Pre compilateur ou quelle que soit la syntaxe qui fonctionne avec toutes les classes et toutes les profondeurs ... une solution réutilisable pour tous les objets ... – prom85

0

Je suggère simplement remplacer

Object result = NullSafeCall(o.getSubObject().getDesiredValue(), defaultValue); 

par le

Object result = (o == null || o.subObject == null) ? defaultVlue : o.getSubObject().getDesiredValue(); 

Créer une méthode uniquement si vous pouvez la réutiliser ......

+0

c'est juste une solution SPECIFIQUE (en faire un one-liner) ... non réutilisable ... J'ai édité mon post principal pour clarifier ce que je veux – prom85

0

Ce que vous voulez n'est pas possible. Il est essentiel de comprendre que l'utilisation de cette syntaxe: Object result = NullSafeCall(o.getSubObject().getSubObject() ...); la partie de o.getSubObject().getSubObject() sera évaluée avant tout contrôle passe à la fonction/méthode rejetant ainsi l'exception.

Il est nécessaire d'avoir un certain type de contexte avant d'exécuter un tel code.Le plus proche de ce que je pouvais penser, peut être fait en utilisant des classes internes anonymes comme dans l'exemple ci-dessous:

// intended to be implemented by an anonymous inner class 
interface NullSafeOperation<T> { 
    public T executeSafely(); 
}; 

// our executor that executes operations safely 
public static class NullSafeExecutor<T> { 
    public NullSafeExecutor() {} 

    public T execute(T defaultValue, NullSafeOperation<T> nso) { 
     T result = defaultValue; 
     try { 
      result = nso.executeSafely(); 
     } catch(NullPointerException e) { 
      // ignore 
     } 
     return result; 
    } 

    // utility method to create a new instance and execute in one step 
    public static <T> T executeOperation(T defaultValue, NullSafeOperation<T> nso) { 
     NullSafeExecutor<T> e = new NullSafeExecutor<T>(); 
     T result = e.execute(defaultValue, nso); 
     return result; 
    } 
} 


public static void main(String[] args) { 

    final String aNullString = null; 

    String result = NullSafeExecutor.executeOperation("MyDefault", new NullSafeOperation<String>() { 
     @Override 
     public String executeSafely() { 
      // trying to call a method on a null string 
      // it will throw NullPointerException but it will be catched by the executor 
      return aNullString.trim(); 
     } 
    }); 

    System.out.println("Output = " + result); // prints: Output = MyDefault 
} 
+0

Je suis conscient que cette syntaxe ne peut pas fonctionner, elle montre seulement ce que je veux ... vous pouvez changer la syntaxe en 'NullSafeCall (" o.getSubObject(). getDesiredValue() ", defaultValue);' ... cela fonctionne très bien ... Je pourrais par la suite analyser la chaîne et analyser le sous-fonctions et vérifier toutes leurs valeurs de retour (avec réflexion) ... le code dans ma question, comme indiqué, démontre juste ce que je veux ... – prom85

+0

Je comprends. Je voulais juste souligner que s'il n'y a pas de contexte, une telle méthode n'est pas possible. La solution ci-dessus en fournit une: votre code est enveloppé dans une classe interne. L'utilisation d'une version de chaîne et de la réflexion comme vous le dites fournit un autre contexte. –

+0

vous avez raison ... mais si le compilateur pouvait interpréter une telle syntaxe, il n'aurait pas besoin de contexte ... et votre solution est une solution, qui fonctionnerait, mais cela ne me protégerait pas d'écrire du code inutile qui pourrait être généré automatiquement ... et dans ce cas, en utilisant un try/catch autour de l'appel de fonction le plus externe ferait l'affaire aussi bien ... – prom85

1

Java8 aide à obtenir le plus proche, vous aurez à votre syntaxe avec des performances décentes je pense;

// Evaluate with default 5 if anything returns null. 
int result = Optional.eval(5, o, x->x.getSubObject(), x->x.getDesiredValue()); 

Cela peut être fait avec cette classe d'utilitaire;

class Optional { 
    public static <T, Tdef, T1> Tdef eval(Tdef def, T input, Function<T,T1> fn1, 
              Function<T1, Tdef> fn2) 
    { 
     if(input == null) return def; 
     T1 res1 = fn1.apply(input); 
     if(res1 == null) return def; 
     return fn2.apply(res1); 
    } 
} 

Malheureusement, vous aurez besoin d'un eval séparé() défini par le nombre d'appels de méthode dans la chaîne, de sorte que vous pouvez définir un peu, mais la compilation type de temps sûr et réutilisable avec à peu près tous les appels/les types.

+0

ça sonne vraiment bien et se rapproche de ce que je veux ... malheureusement, juste java 8 ... merci pour cette solution si ... – prom85

Questions connexes