package p13_lambdy;

public class Lambdy {

    public static void main(String[] args) {
        // Od Javy 8, aby sworzyć obiekt zgodny z interfejsem, można użyć wyrażenia lambda:
        FunkcjaLiczbowa f1 = x -> x*x;

        // f1 jest obiektem pewnej automatycznie tworzonej klasy, która implementuje interfejs.
        System.out.println(f1);
        if(f1 instanceof FunkcjaLiczbowa) {
            System.out.println("Potwierdzam - wszystko OK");
        }
        
        // na takim obiekcie można wywołać metodę z interfejsu:
        System.out.println(f1.oblicz(5));
        
        // Aby można było zastosować wyrażenie lambda do danego interfejsu, to musi to być
        // INTERFEJS FUNKCYJNY, czyli taki, że jest w nim tylko jedna metoda do zaimplementowania.
        // Dzięki temu kompilator wie, że to, co zapisujemy za pomocą strzałek, jest implementacją właśnie tej metody.
        
        // MouseListener nie jest funkcyjny, bo ma zadeklarowanych 6 metod
        // java.awt.event.MouseListener ml = event -> {System.out.println("lalala");};
        
        // ActionListener jest funkcyjny, bo ma zadeklarowaną 1 metodę
        java.awt.event.ActionListener al = event -> {System.out.println("bum bum");};
        
        // przykład nieco bardziej rozbudowanej lambdy, gdzie jest kilka kroków, a na końcu return.
        FunkcjaLiczbowa f2 = (double argument) -> {
            double czescCalkowita = (long)argument;
            double czescUlamkowa = argument % 1;
            return 10 * czescCalkowita + czescUlamkowa;
        };
        
        System.out.println(f2.oblicz(13));
        System.out.println(f2.oblicz(14.65));
        System.out.println();
        
        // Jeśli istnieje metoda, której nagłówek pasuje do naszego interfejsu, to zamiast używać lambdy:
        FunkcjaLiczbowa p1 = x -> Math.sqrt(x);
        System.out.println(p1);
        
        // Aby kompilator zrozumiał, o co chodzi w wyrażeniu lambda, musi wiedzieć, do jakiego interfejsu ma to pasować.
        // Tutaj brakuje kontekstu i taka labda jest niepoprawna:
        // System.out.println(x -> x*100);
        
        // można bezpośrednio wskazać tę metodę ("method reference")
        FunkcjaLiczbowa p2 = Math::sqrt;
        
        System.out.println(p2);
        System.out.println(p1.oblicz(100));
        System.out.println(p2.oblicz(256));
        System.out.println(p2.oblicz(2));
    }

}
