2015-09-11 9 views
16

1.Come il codice sopra, voglio impostare il valore di una variabile accanto al blocco foreach, può funzionare?In java8, come impostare il valore globale nel blocco foreach di lambda?

2. E perché?

3. E l'iteratore predefinito è in ordine o disordine?

4. Credo che il blocco di lamda foreach sia semplice e freddo per l'iteratore, ma questa è una cosa molto complicata da fare piuttosto che lo stesso lavoro in java 7 o precedenti.

+2

il ciclo può essere sostituito (per esempio) da 'if (list.stream() filtro ("d" :: uguale) .findAny () .isPresent()) x = "confronta il valore"; '. Nella maggior parte dei casi, ci sarà un modo per scrivere il codice senza dover manipolare variabili esterne. – assylias

+2

@assylias: 'if (list.stream(). AnyMatch (" d ":: equals)) ...' o 'if (list.contains (" d ")) ...' – Holger

+1

@Holger Argh - Mi dimentico sempre di ciò metodo (anyMatch) e sì anzi, contiene ancora meglio. Grazie! – assylias

risposta

20

Si potrebbe, naturalmente, "rendere il valore esterno mutevole" tramite un trucco:

public void test() { 
    String[] x = new String[1]; 
    List<String> list = Arrays.asList("a", "b", "c", "d"); 

    list.forEach(n -> { 
     if (n.equals("d")) 
      x[0] = "match the value"; 
    }); 
} 

Preparatevi per una battitura dal puristi funzionale della squadra, però. Molto più bello, però, è quello di utilizzare un approccio più funzionale (similar to Sleiman's approach):

public void test() { 
    List<String> list = Arrays.asList("a", "b", "c", "d"); 
    String x = list.stream() 
        .filter("d"::equals) 
        .findAny() 
        .map(v -> "match the value") 
        .orElse(null); 
} 
7
  1. No, non puoi farlo. (Anche se avresti dovuto provarlo tu stesso)
  2. Poiché le variabili utilizzate all'interno di espressioni interne anonime e espressioni lambda devono essere effectively final.
  3. è possibile ottenere lo stesso più conciso utilizzando filter e map.

    Optional<String> d = list.stream() 
             .filter(c -> c.equals("d")) 
             .findFirst() 
             .map(c -> "match the value"); 
    
5

Come è già spiegato, non è possibile modificare la variabile locale del metodo esterno dal corpo lambda (così come dal corpo classe anonima). Il mio consiglio è di non provare ad usare lambda quando sono completamente inutili. Il tuo problema può essere risolto in questo modo:

public void test(){ 
    String x; 
    List<String> list = Arrays.asList("a","b","c","d"); 
    if(list.contains("d")) 
     x = "match the value"; 
} 

In lambda generale sono amici con la programmazione funzionale in cui si dispone di rado variabili mutabili (ogni variabile viene assegnato solo una volta). Se usi lambda, ma continui a pensare in modo imperativo avrai sempre questi problemi.

+3

Come nota a margine, il tuo codice corrisponde effettivamente al codice dell'OP in cui 'x' è completamente inutile in seguito, in quanto potrebbe non essere assegnato. – Holger

7

Oltre ai già fornito esempi idiomatiche, un altro trucco potrebbe essere quella di utilizzare AtomicReference, ma lo consiglio solo se si ha bisogno ' forEach' e preferiscono qualcosa di più leggibile di vero-funzionale variante:.

public void test(){ 
    AtomicReference<String> x = new AtomicReference<>(); 
    List<String> list= Arrays.asList("a", "b", "c", "d"); 

    list.forEach(n->{ 
     if(n.equals("d")) 
      x.set("match the value"); 
    }); 
} 
+1

In suvato solo per 'AtomicReference' sebbene non lo consiglierei per foreach. Invece questo approccio ha senso se usato per un parallelismo. – dmachop

Problemi correlati