2015-07-17 9 views
6

Sto utilizzando Eclipse Luna Service Release 2 (4.4.2), Java 8 u51.Costruttore funzionale Java 8 dall'oggetto modello

Sto provando a creare un metodo che creerà istanze di un oggetto passato in base a un altro parametro di metodo. Il prototipo è semplificata al

public <T> T test(Object param, T instance) { 
    Constructor<?> constructor = instance.getClass().getConstructors()[0]; // I actually choose a proper constructor 

    // eclipse reports "Unhandled exception type InvocationTargetException" 
    Function<Object, Object> createFun = constructor::newInstance; 

    T result = (T) createFun.apply(param); 
    return result; 
} 

on line con Function dichiarazione rapporti eclissi Unhandled exception type InvocationTargetException errore del compilatore. Ho bisogno dello Function per utilizzarlo successivamente in un flusso.

Ho provato ad aggiungere vari blocchi try/catch, genera dichiarazioni, ma niente risolve questo errore del compilatore.

Come utilizzare questo codice?

+1

Cosa pensi è il vantaggio del 'deviazione Function' oltre semplicemente chiamando' newInstance' sul 'Constructor'? – Holger

+0

@Holger Stavo usando 'newInstance' su' Constructor' in-stream e ha prodotto lo stesso messaggio, quindi ho creato un SSCE come questo. La deviazione della funzione è effettivamente necessaria per mantenere una catena 'stream()' relativamente leggibile. – Dariusz

+1

Vedo. Quindi è stato un po 'troppo semplificato per quanto riguarda il caso d'uso e un'espressione lambda come suggerito da assylias dovrebbe funzionare. Ma quello che mi piacerebbe sapere ora, è se c'è davvero un severo requisito riguardo al tipo risultante che è il tipo esatto di 'instance' (che potrebbe essere una sottoclasse di' T'), in altre parole se ricorrere a Reflection è davvero necessario ... – Holger

risposta

11

Non è possibile lanciare un'eccezione controllata da una lambda con un tipo di target Function perché il suo metodo apply non genera un'eccezione. Quindi è necessario farne un'eccezione incontrollato, ad esempio avvolgendolo:

Function<Object, Object> createFun = o -> { 
    try { 
    return constructor.newInstance(o); 
    } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) { 
    throw new RuntimeException(e); 
    } 
}; 

Un'alternativa è quella di portare il compilatore a pensare che sia un'eccezione incontrollato, che produce un detergente traccia dello stack contro l'opzione di cui sopra:

Function<Object, Object> createFun = o -> { 
    try { 
    return constructor.newInstance(o); 
    } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) { 
    return uncheck(e); 
    } 
}; 

con il seguente metodo di utilità:

@SuppressWarnings("unchecked") 
public static <E extends Throwable, T> T uncheck(Throwable t) throws E { 
    throw ((E) t); 
} 
+3

Puoi lanciare un'eccezione controllata da un lambda. Ma non da un lambda che dovrebbe implementare Function, perché Function.apply() non lancia un'eccezione controllata. –

+1

@JBNizet Sì, grazie. – assylias

+2

Probabilmente potresti stringere il tuo metodo 'descheck' introducendo un' ', quindi non devi fare nessun tipo di cast. Potresti anche eseguire il tuo tiro all'interno del metodo 'descheck', anche; non c'è bisogno di due metodi quando puoi semplicemente crearne uno. – Makoto

4

Questo perché il metodo di riferimento è quello di un metodo con le eccezioni citate nella errore di tempo di compilazione. Il singolo metodo astratto R apply(T t ) in java.util.Function non genera queste eccezioni. Quindi c'è una discrepanza tra il tipo funzionale di java.util.Function e il tipo del tuo Method-Reference.

Utilizzando un tipo funzionale con un metodo di corrispondenza funziona ... per esempio:

interface MyFunction<T,R> { 
     /** 
     * Applies this function to the given argument. 
     * 
     * @param t the function argument 
     * @return the function result 
     */ 
     R apply(T t) throws Throwable; 

    } 

    public <T> T test(Object param, T instance) throws InstantiationException, IllegalAccessException, 
      IllegalArgumentException, InvocationTargetException { 
     Constructor<?> constructor = instance.getClass().getConstructors()[0]; // I actually choose a proper constructor 

     // eclipse reports "Unhandled exception type InvocationTargetException" 
      MyFunction<Object,Object> createFun = constructor::newInstance; 

     T result = (T) createFun.apply(param); 
     return result; 
    }