2016-11-21 5 views
0

J'ai une classe qui dérive de java.util.concurrent.AbstractExecutorService. Ma classe remplace shutdownNow(). Tout compile et fonctionne bien. J'ai ajouté [email protected] à la classe. J'ai réussi à corriger toutes les erreurs et les avertissements, sauf pour 1 erreur sur shutdownNow(). Le message d'erreur indique ...@NonNullByDefault Le type de retour est incompatible avec 'List <Runnable>' retourné par ExecutorService.shutdownNow() (non concordant avec les contraintes nulles)

Le type de retour est incompatible avec 'Liste' est revenu de ExecutorService.shutdownNow() (désadaptation contraintes null)

Les solutions rapides ne sont pas d'aide.

Voici le code incriminé.

@NonNullByDefault // Adding this causes an error 
public abstract class ShutdownThreadPool extends AbstractExecutorService implements ExecutorService 
{ 
    @Override 
    public List<Runnable> shutdownNow() // The error is on this line 
    { 
     return(Collections.emptyList()); 
    } 
} 

Remarque: Collections.emptyList() n'est pas le problème. C'est juste une simplification du code réel qui reproduit le même message d'erreur.

Voici une image du code.

enter image description here

Répondre

1

Il semble que ExecutorService est pas dans le champ d'application de @NonNullByDefault tout, non? En outre, ExecutorService déclare List<Runnable> shutdownNow().

La dérogation, cependant, est affectée par @NonNullByDefault rendant sa signature effective @NonNull List<@NonNull Runnable> shutdownNow().

Malheureusement, la solution rapide ne concerne que la première @NonNull, alors que l'annotation sur l'argument de type Runnable est réellement la cause de l'incompatibilité:

Nous ne savons pas la sémantique destinées de ExecutorService.shutdownNow(): doivent clients s'attendre annulable ou non nulle éléments dans la liste renvoyée? En supposant que List<@NonNull Runnable> casse les appelants potentiels de shutdownNow() qui aiment insérer null dans la liste des résultats (en ignorant la conception étrange que cela impliquerait). Pour sécuriser ce type de substitution, il faut d'abord introduire des annotations nulles sur la superinterface (dans ce cas en utilisant des annotations externes), puis laisser les implémentations suivre.

Si annoter le superinterface n'est pas viable pour une raison quelconque, par exemple, en continuant avec le type « héritage » List<Runnable> est souhaité, la valeur par défaut null peut être annulée pour cette seule méthode en disant @NonNullByDefault({}), et en ajoutant manuellement @NonNull où il est toujours désiré.