2016-01-08 9 views
5

Un progetto su cui lavoro è passato da Java 7 a Java 8. Mi piacerebbe poter trovare interfacce che abbiano un unico metodo astratto come candidati per l'introduzione di interfacce funzionali nel nostro codice base. (Annotando le interfacce esistenti come @FunctionalInterface, estendendole dalle interfacce in java.util.function o eventualmente semplicemente sostituendole).Come posso cercare una base di codice Java per le interfacce che hanno un singolo metodo?

+1

Questo è disponibile come ispezione in IntelliJ. Creare un profilo di ispezione che abbia solo questa ispezione ed eseguirlo sul progetto. –

+0

Poiché questo cambiamento richiederebbe un'analisi caso per caso e, a parte per aggiungere l'annotazione, le altre due soluzioni richiedono entrambi un refactoring significativo, non ci andrei. Se non si sta progettando una libreria, l'aggiunta dell'annotazione non fornisce molto valore, poiché si vedrebbero rapidamente problemi di compilazione se si trasforma un'interfaccia in una non funzionale mentre ha implementazioni lambda. –

risposta

6

Il progetto reflections è in grado di individuare e restituire tutte le classi sul classpath. Ecco un esempio di lavoro:

ReflectionUtils.forNames(new Reflections(new ConfigurationBuilder().setScanners(new SubTypesScanner(false)) 
                    .addUrls(ClasspathHelper.forClassLoader())) 
         .getAllTypes()).stream() 
       .filter(Class::isInterface) 
       .collect(toMap(c -> c, 
           c -> Arrays.stream(c.getMethods()) 
             .filter(m -> !m.isDefault()) 
             .filter(m -> !Modifier.isStatic(m.getModifiers())) 
             .filter(m -> !isObjectMethod(m)) 
             .collect(toSet()))) 
       .entrySet().stream() 
       .filter(e -> e.getValue().size() == 1) 
       .sorted(comparing(e -> e.getKey().toString())) 
       .map(e -> e.getKey().toString() + " has single method " + e.getValue())//getOnlyElement(e.getValue())) 
       .forEachOrdered(System.out::println); 

Il isObjectMethod aiutante si definisce in questo modo:

private static final Set<Method> OBJECT_METHODS = ImmutableSet.copyOf(Object.class.getMethods()); 
private static boolean isObjectMethod(Method m){ 
    return OBJECT_METHODS.stream() 
         .anyMatch(om -> m.getName().equals(om.getName()) && 
             m.getReturnType().equals(om.getReturnType()) && 
             Arrays.equals(m.getParameterTypes(), 
                 om.getParameterTypes())); 
} 

Questo non aiuta si torna al codice sorgente e aggiungere le annotazioni, ma ti do una lista da cui lavorare.

+0

Cosa succede se l'interfaccia sovrascrive un metodo 'Object', come fa il' Comparator'? Quindi, il metodo dovrebbe essere filtrato. E anche i metodi 'static' dovrebbero essere rimossi. O meglio, lascia che il filtro passi solo i metodi 'abstract'. E c'è un motivo per usare 'stream (spliterator (c.getMethods(), 0), false)' invece di 'Arrays.stream (c.getMethods())'? – Holger

+0

aggiornato con i tuoi commenti –

+0

Perché non '.filter (m -> Modifier.isAbstract (m.getModifiers()))' invece di '.filter (m ->! M.isDefault()). Filter (m ->! Modifier.isStatic (m.getModifiers())) '? – Holger