2015-10-08 6 views
18

Penso che questa domanda sia già da qualche parte, ma non sono stata in grado di trovarla.Perché ho bisogno di un'interfaccia funzionale per funzionare con lambdas?

Non capisco, perché è necessario avere un'interfaccia funzionale per lavorare con lambda. Si consideri il seguente esempio:

public class Test { 

    public static void main(String...args) { 
     TestInterface i =() -> System.out.println("Hans"); 
//  i = (String a) -> System.out.println(a); 

     i.hans(); 
//  i.hans("Hello"); 
    } 
} 

public interface TestInterface { 
    public void hans(); 
// public void hans(String a); 
} 

Questo funziona senza problemi, ma se si rimuove il commento le righe di commento, non è così. Perché? A mio avviso, il compilatore dovrebbe essere in grado di distinguere entrambi i metodi, poiché hanno parametri di input diversi. Perché ho bisogno di un'interfaccia funzionale e faccio esplodere il mio codice?

MODIFICA: i duplicati collegati non hanno risposto alla mia domanda perché sto chiedendo di parametri di metodo diversi. Ma ho avuto alcune risposte davvero utili qui, grazie a tutti quelli che mi hanno aiutato! :)

EDIT2: Scusate, sono, ovviamente, non un madrelingua, ma per me stesso preciso:

public interface TestInterface { 
    public void hans();     //has no input parameters</br> 
    public void hans(String a);   //has 1 input parameter, type String</br> 
    public void hans(String a, int b); //has 2 input parameters, 1. type = String, 2. type = int</br> 
    public void hans(int a, int b);  //has also 2 input parameters, but not the same and a different order than `hans(String a, int a);`, so you could distinguish both 
} 

public class Test { 

    public static void main(String...args) { 
     TestInterface i =() -> System.out.println("Hans"); 
     i = (String a) -> System.out.println(a); 
     i = (String a, int b) -> System.out.println(a + b); 
     i = (int a, int b) -> System.out.println(a); 

     i.hans(2, 3); //Which method would be called? Of course the one that would take 2 integer arguments. :) 
    } 
} 

Tutto quello che chiedo è di circa gli argomenti. Il nome del metodo non ha importanza, ma ogni metodo richiede un ordine univoco di argomenti diversi e, a causa di ciò, Oracle potrebbe aver implementato questa funzione, invece, semplicemente rendendo possibile un singolo metodo per "Lambda-Interface".

+3

'int i = 7; i = 5; System.out.println (i); // non sarebbe fantastico se questo stampasse sia il 7 che il 5? ' – immibis

+1

Davvero non capisco il tuo ragionamento. Se qualcosa non implementa un'interfaccia, allora come può essere di quel tipo? Un iPod non conta come iPhone solo perché non ti capita di fare telefonate. – zeroflagL

+0

@immibis: Ciò che descrivi qui è diverso da quello che ho chiesto. :) – codepleb

risposta

20

Quando si scrive:

TestInterface i =() -> System.out.println("Hans"); 

Tu dai un'implementazione del metodo della TestInterfacevoid hans().

Se si potesse assegnare un'espressione lambda a un'interfaccia avente più di un metodo astratto (cioè un'interfaccia non funzionale), l'espressione lambda poteva solo implementare uno dei metodi, lasciando gli altri metodi non implementati.

Non è possibile risolverlo assegnando due espressioni lambda con diverse firme alla stessa variabile (proprio come non è possibile assegnare riferimenti di due oggetti a una singola variabile e aspettarsi che la variabile faccia riferimento a entrambi gli oggetti contemporaneamente) .

+0

Hm, sembra logico, ma mi chiedo ancora perché Oracle abbia fatto così. Se potessi semplicemente chiamare metodi per i quali hai implementato un corpo, sarebbe in qualche modo più intuitivo. Questo è ovviamente un problema del concetto di interfaccia e non di lambdas stesso. Grazie. :) – codepleb

+2

@TrudleR, quindi Java sarebbe un linguaggio funzionale. Se sei interessato a tale implementazione su JVM. Potresti provare la lingua di Scala. –

+0

Hm, Scala Scala Scala. : D Penso di aver davvero bisogno di imparare questa lingua. Tutti ne parlano infine. Il mio caso è possibile con quella lingua? Sarebbe davvero bello. – codepleb

3

Non è necessario creare un'interfaccia funzionale per creare la funzione lambda. L'interfaccia consente di creare un'istanza per l'invocazione futura della funzione.

Nel tuo caso si potrebbe usare già esistente interfaccia runable

Runnable r =() -> System.out.println("Hans");

e quindi chiamare

r.run();

Si può pensare di lambda -> come solo breve portata di mano per:

Runnable r = new Runnable() { 
    void run() { 
      System.out.println("Hans");` 
    } 
} 

Con lambda non hai bisogno della classe anonima, che viene creata sotto il cofano nell'esempio sopra.

Ma questo ha alcune limitazioni, al fine di capire quale metodo dovrebbe essere chiamato interfaccia utilizzata con lambdas deve essere SAM (Single Abstract Method). Quindi abbiamo solo un metodo.

Per una spiegazione più dettagliata lettura:

Introduction to Functional Interfaces – A Concept Recreated in Java 8

13

Il motivo più importante per cui devono contenere solo un metodo, è che la confusione è facilmente possibile altrimenti. Se nell'interfaccia fossero consentiti più metodi, quale metodo dovrebbe scegliere un lambda se gli elenchi degli argomenti sono gli stessi?

interface TestInterface { 
    void first(); 
    void second(); // this is only distinguished from first() by method name 
    String third(); // maybe you could say in this instance "well the return type is different" 
    Object fourth(); // but a String is an Object, too ! 
} 

void test() { 
    // which method are you implementing, first or second ? 
    TestInterface a =() -> System.out.println("Ido mein ado mein"); 
    // which method are you implementing, third or fourth ? 
    TestInterface b =() -> return "Ido mein ado mein"; 
} 
+0

Sì, lo so, dovrebbe solo risultare in un'eccezione se si desidera eseguire tale codice. Ma ho pensato che argomenti diversi dovrebbero essere chiari per il compilatore. Se dichiari 2 metodi con lo stesso nome e parametri, fornisce anche un'eccezione, quindi perché Oracle dovrebbe impedirlo qui? – codepleb

+0

Buon esempio. Grazie – greenhorn

3

Lei sembra essere alla ricerca di classi anonime. Il seguente codice funziona:

public class Test { 

    public static void main(String...args) { 
     TestInterface i = new TestInterface() { 
      public void hans() { 
       System.out.println("Hans"); 
      } 
      public void hans(String a) { 
       System.out.println(a); 
      } 
     }; 

     i.hans(); 
     i.hans("Hello"); 
    } 
} 

public interface TestInterface { 
    public void hans(); 
    public void hans(String a); 
} 

lambda espressioni sono (soprattutto) un modo più breve per scrivere classi anonime con un solo metodo. (Allo stesso modo, le classi anonime sono abbreviazioni di classi interne che si usano solo in un posto)

+0

Ehi, non sono un principiante. :) Certo che so come posso farlo funzionare. Volevo solo chiedere, perché i lambda sono tagliati per funzionare solo con interfacce funzionali. È chiaro che avrei bisogno di scrivere classi anonime (o implementare una classe stessa) per il mio caso. Tutto quello che volevo dire è che penso che Oracle avrebbe potuto estendere l'uso di lambda. Ma dopo le discussioni qui è chiaro il motivo per cui ti costringono a utilizzare interfacce funzionali. Ma grazie comunque. – codepleb

+0

@TrudleR Se hanno esteso lambda nel modo in cui stai pensando, allora sarebbero uguali a classi anonime, quindi quale sarebbe il punto? – immibis

+0

risposta precisa grazie. – greenhorn