2014-07-15 5 views
12

Próbuję zmienić ten kod, aby użyć lambda zamiast anonimowej klasy. Jest to prosta lista elementów w GUI. Rejestruję innego słuchacza dla każdego przedmiotu, a ostatni utworzony element robi coś specjalnego po kliknięciu.Kod zachowuje się inaczej po konwersji klasy anonimowej na lambda

class ItemList { 
    interface OnClickListener { 
     void onClick(); 
    } 
    OnClickListener current; 
    OnClickListener newListener(final int n) { 
     return current = new OnClickListener() { 
      public void onClick() { 
       if (this == current) 
        System.out.println("doing something special (item #"+n+")"); 
       System.out.println("selected item #" + n); 
      } 
     }; 
    } 
    public static void main(String[] args) { 
     ItemList l = new ItemList(); 
     OnClickListener ocl1 = l.newListener(1); 
     OnClickListener ocl2 = l.newListener(2); 
     OnClickListener ocl3 = l.newListener(3); 
     ocl1.onClick(); 
     ocl2.onClick(); 
     ocl3.onClick(); 
    } 
} 

To działa zgodnie z oczekiwaniami:

$ javac ItemList.java && java ItemList 
selected item #1 
selected item #2 
doing something special (item #3) 
selected item #3 

Teraz mogę zmienić go użyć lambda zamiast anonimowego klasy:

class ItemList { 
    interface OnClickListener { 
     void onClick(); 
    } 
    OnClickListener current; 
    OnClickListener newListener(final int n) { 
     return current =() -> { 
      if (this == current) 
       System.out.println("doing something special (item #"+n+")"); 
      System.out.println("selected item #" + n); 
     }; 
    } 
    public static void main(String[] args) { 
     ItemList l = new ItemList(); 
     OnClickListener ocl1 = l.newListener(1); 
     OnClickListener ocl2 = l.newListener(2); 
     OnClickListener ocl3 = l.newListener(3); 
     ocl1.onClick(); 
     ocl2.onClick(); 
     ocl3.onClick(); 
    } 
} 

Ale teraz to już nie robi nic szczególnego na ostatni pozycja? Czemu? Czy == działa inaczej w lambdach? Myślałem, że to był błąd w retrolambdzie na początku, ale ten przykład działa na zwykłym JDK8 i nadal się dzieje.

$ javac A.java && java A 
selected item #1 
selected item #2 
selected item #3 
+1

Lambda naprawdę nie może odnosić się do "tego" w ich ciele. –

Odpowiedz

12

this wewnątrz lambda nie znaczy taki sam jak this wewnątrz anonimowej instancji klasy.

Wewnątrz lambda odnosi się do klasy otaczającej.

... wyrażenie lambda nie wprowadza nowego poziomu zakresu. W związku z tym można bezpośrednio uzyskać dostęp do pól, metod i zmiennych lokalnych otaczającego zakresu. ... Aby uzyskać dostęp do zmiennych w klasie otaczającej, użyj tego słowa kluczowego. ...

Wewnątrz instancji anonimowej klasy, to odnosi się do bieżącego obiektu

ciągu metody instancji lub konstruktora, jest to odniesienie do bieżącego obiektu - obiekt, którego metoda lub konstruktora jest nazywany

Dlatego w wyrażeniu lambda, this == current nigdy nie jest prawdą, ponieważ porównuje instancję klasy ItemList z wyrażeniem lambda typu OnClickListener.

+0

Nadal nie jest jasne, dlaczego prąd == to nigdy nie jest prawda. Ponieważ otaczająca klasa jest taka sama, powinniśmy zobaczyć trzy "coś" w danych wyjściowych. –

+0

@OlegGryb Klasa otaczająca to ItemList, więc nigdy nie jest równa obecnej (która jest wyrażeniem lambda typu OnClickListener). – Eran

+0

Masz rację, nie przemyślałeś tego, więc current.onClick() powinien nadal działać, jeśli chcę go używać w ten sposób. –