2014-04-20 17 views
10
CompletableFuture.supplyAsync(
() -> { 
    transporter.write(req); 
    //here take the value from a blocking queue,will throw a interruptedException 
    return responseQueue.take(); 
}, executorService); 

Il metodo comune per affrontare InterruptedException è o interrompere di nuovo o diretta tiro InterruptedException, ma entrambi non possono lavorare. Qualcuno ha l'idea?JDK8 CompletableFuture.supplyAsync come affrontare InterruptedException

+0

"* ma entrambi non possono funzionare. *" => Perché? – assylias

+0

hanno entrambi errori di compilazione. se l'eccezione di lancio diretto, il compilatore mostrerà un'eccezione non gestita, se la cattura e chiama Thead.current.interrupt, il compilatore mostrerà deve restituire un tipo T. – GrapeBaBa

+0

Sì, è necessario restituire o lanciare. Se si decide di restituire null, ad esempio: 'try {return queue.take(); } catch (InterruptedException e) {Thread.currentThread(). interrupt(); return null; } ' – assylias

risposta

10

Ho cambiato il codice in questo modo.

CompletableFuture<Rep> result = new CompletableFuture<>(); 
    CompletableFuture.runAsync(() -> { 

     transporter.write(req); 
     try { 
      Rep rep = responseQueue.take(); 
      result.complete(rep); 
     } catch (InterruptedException e) { 
      result.completeExceptionally(e); 
      Thread.currentThread().interrupt(); 
     } catch (Exception e) { 
      result.completeExceptionally(e); 
     } 

    }, executorService); 
    return result; 
+0

Quello che hai fatto è equivalente al mio. Purtroppo, 'CompletableFuture result' può essere sostituito da QUALSIASI classe conforme al paradigma" risultato o eccezione ". Ad esempio è possibile aggiungere i metodi 'get',' complete' e 'completeExceptionally' a' ResultWrapper' e usare 'ResultWrapper rep = new ResultWrapper();'. È piuttosto una coincidenza che tu abbia riscontrato questa limitazione della funzione lambda usando 'CompletableFuture' e di nuovo l'hai risolto usando' CompletableFuture', facendo uso di quei metodi che hai usato. – mostruash

+1

Sì, ma completabilefuturo ha già l'astrazione per un risultato di calcolo, quindi non voglio creare un nuovo tipo per lo stesso. – GrapeBaBa

+0

Se lavori con altre persone, ciò potrebbe confondere i lettori del tuo codice. Altrimenti, bello che ha funzionato per te. – mostruash

3

Poiché le funzioni lambda non supportano eccezioni di lancio, penso che gli sviluppatori Java avranno bisogno di un nuovo paradigma. Una cosa che viene in mente è la seguente:

public class ResultWrapper<R, E extends Exception> { 
    E exception; 
    R result; 
} 

Le funzioni Lambda possono restituire istanze di questo wrapper. (Modifica: il tuo caso)

CompletableFuture<ResultWrapper<String, InterruptedException>> aFuture = ...; 
... 
aFuture.supplyAsync(
() -> { 
    try { 
     transporter.write(req); 
    } catch(InterruptedException e) { 
     ResultWrapper<String, InterruptedException> r = new ResultWrapper<>(); 
     r.exception = e; 
     r.result = null; 
     return r; 
    } 
    ... 
}, executorService); 
+0

Sembra una soluzione – GrapeBaBa

+0

Si prega di contrassegnarla come risposta se si ritiene che ti abbia aiutato :) – mostruash

+0

Invece di convertire le eccezioni in un valore di ritorno, dovresti raggrupparle in un'eccezione non controllata e, se necessario, tradurle nuovamente in un'eccezione controllata all'esterno. Conserva le eccezioni come eccezioni per tutto il percorso. I valori di ritorno sono riservati per condizioni non di errore. – Gili

2

ho incontrato la stessa domanda, ma dopo aver letto di più da commenti qui e libro di riferimento Penso che si può fare uno di questi due:

1 (quello che finisce per fare):

CompletableFuture.runAsync(() -> { 
    transporter.write(req); 
    try { 
     Rep rep = responseQueue.take(); 
     result.complete(rep); 
    } catch (Exception e) { 
     throw new CompletionException(e); 
    } 
}, executorService); 
return result; 

o 2:

CompletableFuture<Rep> result = new CompletableFuture<>(); 
new Thread(()-> { 
    transporter.write(req); 
    try { 
     Rep rep = responseQueue.take(); 
     result.complete(rep); 
    } catch (Exception e) { 
     retsult.completeExceptionally(e); 
    } 
}).start(); 

so che il 2 ° uno non usa il executorService, ma Sento che l'intero punto di utilizzo di CompletableFuture è l'utilizzo delle API di CompletionStage in stile funzionale.

+0

Le tue seconde soluzioni possono essere migliorate. Vedi http://stackoverflow.com/a/28961083/868941 per spiegazioni dettagliate. – rmuller

Problemi correlati