2017-01-05 1 views
3

J'essayais d'avoir une méthode handleException, qui peut prendre un objet d'exception et une liste de classes d'exceptions acceptables pour vérifier si l'exception est acceptable et peut être réessayée.Comment passer une liste de classe en tant que paramètre?

void handleException(Exception e, String... acceptableExceptionNames) 
     throws MyException { 

    boolean isRetryable = false; 

    for(String acceptableExceptionName: acceptableExceptionNames) { 
     try { 
     if (Class.forName(acceptableExceptionName).isInstance(e)) { 
      isRetryable = true; 
      break; 
     } 
     } catch (ClassNotFoundException e1) { 
     continue; 
     } 
    } 

    if (isRetryable) { 
     // log retryable 
    } else { 
     // log error 
    } 

    throw new MyException(isRetryable, "Failed"); 
    } 

Le paramètre je passe un String... classNames au lieu de Class<? extends Exception> classes, parce que si je fais quelque chose comme ceci:

void handleException(
    Exception e, 
    Class<? extends Exception>... acceptableExceptions) 
     throws MyException { 
    for (Class acceptableException : acceptableExceptions) { 
     if (e instanceOf acceptableException) {} 
    } 
} 

L'IDE se plaindront unknown class acceptableException

Quelqu'un sait s'il y a un moyen pour passer Class<?>? Ou une meilleure façon d'éviter d'utiliser String classNames et Class.forName()?

+0

Vous ne pouvez pas utiliser un type générique dans Exceptions! – Michael

+2

Lorsque vous utilisez varargs, le type 'acceptableExceptions' est' Class [] '. – chrylis

+0

Pourquoi avez-vous essayé 'e instanceOf acceptableExceptions' avec un tableau de classes? Vous avez démontré que vous savez comment parcourir un tableau et appeler la méthode 'Class.isInstance' dans l'autre extrait. – user2357112

Répondre

6

acceptableExceptions est pas un Class, c'est un Class[]. Vous pouvez garder votre design original, cependant, et il suffit d'utiliser la place directement les objets Class de les créer à partir de chaînes:

void handleException 
     (Exception e, Class<? extends Exception>... acceptableExceptionNames) 
     throws MyException { 

    boolean isRetryable = false; 

    for(Class<?> acceptableExceptionName: acceptableExceptionNames) { 
     if (acceptableExceptionName.isInstance(e)) { 
      isRetryable = true; 
      break; 
     } 
    } 

    if (isRetryable) { 
     // log retryable 
    } else { 
     // log error 
    } 

    throw new MyException(isRetryable, "Failed"); 
} 

EDIT:
Comme une note de côté, ce code peut être fait beaucoup plus court en utilisant les flux de Java 8 :

void handleException 
     (Exception e, Class<? extends Exception>... acceptableExceptionNames) 
     throws MyException { 

    boolean isRetryable = 
     Arrays.stream(acceptableExceptionNames).anyMatch(x -> x.isInstance(e)); 

    if (isRetryable) { 
     // log retryable 
    } else { 
     // log error 
    } 

    throw new MyException(isRetryable, "Failed"); 
} 
+2

Pourquoi remplacer 'Class 'avec' Classe '? Vous ne restreignez plus les types de classe. – Andreas

+0

@Andreas parce que 'Class 'entraînera un avertissement de polarité de tas via' acceptableExceptionNames', bien que je ne comprenne pas complètement pourquoi cet avertissement se produit. – Turing85

+0

Qu'est-ce qu'un "heap-polution warning"? Mon Eclipse ne donne aucun avertissement. – Andreas

-1

Utiliser le contrôle suivant

for (Class<? extends Exception> exceptionClass : acceptableExceptions) { 
    if (exceptionClass.isInstance(e)) { 
     // it is your exception 
    } 
} 
1

à mon avis, il est plus facile de le faire si en effectuant les simples comparaisons de chaînes de caractères comme ceci:

private void handleException(Exception ex, String... acceptableException) { 
    for (int x = 0; x < acceptableException.length; x++) { 
     String[] exceptionClass = ex.getClass().toString().split("."); 
     if (!acceptableException[x] 
       .equals(exceptionClass[exceptionClass.length - 1])) { 
      /* Exception Not Acceptable */ 
     } 
    } 

    /* Exception Acceptable */ 
} 
2

Vous ne voulez pas vérifier si e est une instance d'un Class[], qui est ce que acceptableExceptions est, mais s'il s'agit d'une instance de l'une des les classes référencées par le tableau acceptableExceptions.

Pour ce faire, vous devez les itérer, et vous devez utiliser la méthode de réflexion Class.isInstance(Object obj). Comme le dit javadoc:

Cette méthode est l'équivalent dynamique de l'opérateur Java instanceof.

Pour éviter les avertissements du compilateur, vous devez également ajouter @SafeVarargs vous méthode si elle est static ou final. Sinon, vous devez ajouter @SuppressWarnings("unchecked") à la fois à la méthode et à l'appelant (s).

@SuppressWarnings("unchecked") 
void handleException(Exception e, Class<? extends Exception>... acceptableExceptions) throws MyException { 
    boolean acceptable = false; 
    for (Class<? extends Exception> acceptableException : acceptableExceptions) 
     if (acceptableException.isInstance(e)) { 
      acceptable = true; 
      break; 
     } 
    if (acceptable) { 
     // code here 
    } 
} 
+0

Malheureusement, '@ SafeVarargs' ne s'applique pas aux méthodes d'instance non-finales avec varargs. Si cela est nécessaire, vous allez vous retrouver avec ['@SuppressWarnings (" unchecked ")'] (http://stackoverflow.com/questions/12462079/potential-heap-pollution-via-varargs-parameter). – dhke

+0

@dhke Vous avez raison. J'avais fait la méthode 'static' dans mes tests. – Andreas