Na czym polega wykorzystanie interfejsu funkcjonalnego w Javie 8?

Natknąłem się na nowy termin o nazwie Functional Interface W Java 8.

Mogłem znaleźć tylko jedno zastosowanie tego interfejsu podczas pracy z wyrażeniami lambda .

Java 8 udostępnia wbudowane interfejsy funkcjonalne i jeśli chcemy zdefiniować dowolny interfejs funkcjonalny, możemy użyć adnotacji @FunctionalInterface. Pozwoli nam zadeklarować tylko jedną metodę w interfejsie.

Na przykład:

@FunctionalInterface
interface MathOperation {
    int operation(int a, int b);
}

Jak przydatny jest w Javie 8 inny niż tylko praca z wyrażeniami lambda ?

Pytanie tutaj jest inne od tego, które zadałem. Pytanie, po co nam funkcjonalny interfejs podczas pracy z wyrażeniem Lambda. Moje pytanie brzmi: po co używać funkcjonalnego interfejsuinnego niż bezpośrednio z wyrażeniami lambda?

Author: Ahmad Al-Kurdi, 2016-04-27

10 answers

@FunctionalInterface adnotacja jest przydatna do sprawdzania czasu kompilacji kodu. Nie możesz mieć więcej niż jednej metody poza static, default i abstrakcyjne metody, które nadpisują metody w {[6] } w twoim @FunctionalInterface lub dowolnym innym interfejsie używanym jako interfejs funkcjonalny.

Ale możesz używać lambda bez tej adnotacji, jak również możesz nadpisać metody bez @Override adnotacji.

From docs

Interfejs funkcjonalny ma dokładnie jedną abstrakcyjną metodę. Od default metody mają implementację, nie są abstrakcyjne. Jeśli interfejs deklaruje metodę abstrakcyjną nadrzędną wobec jednej z publicznych metod java.lang.Obiekt, który również nie liczy się do interfejsu metody abstrakcyjne liczą się, ponieważ każda implementacja interfejsu będzie mieć implementację z Javy.lang.Obiekt lub gdzie indziej

To może być użyte w wyrażeniu lambda:

public interface Foo {
  public void doSomething();
}

To Nie może być użyte w lambdzie wyrażenie:

public interface Foo {
  public void doSomething();
  public void doSomethingElse();
}

Ale To da błąd kompilacji :

@FunctionalInterface
public interface Foo {
  public void doSomething();
  public void doSomethingElse();
}

Nieprawidłowa adnotacja '@ FunctionalInterface'; Foo nie jest funkcją interfejs

 92
Author: Sergii Bishyr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-03 04:20:29

Funkcjonalne interfejsy mają jedną funkcjonalność do wykazania. Na przykład do celów porównania używany jest porównywalny interfejs z pojedynczą metodą "compareTo". W Javie 8 zdefiniowano wiele funkcjonalnych interfejsów , które mają być szeroko stosowane w wyrażeniach lambda .

Wprowadzono adnotację - @FunctionalInterface, która może być używana do błędów na poziomie kompilatora, gdy interfejs, który dodałeś, nie jest poprawnym interfejsem funkcjonalnym.

@FunctionalInterface
 interface MathOperation {
      int operation(int a, int b);
 }

Spróbujmy dodać Inna abstrakcyjna metoda:

@FunctionalInterface
 interface MathOperation {
      int operation(int a, int b);
      int operationMultiply(int a, int b);
 }

Powyżej spowoduje błąd kompilatora, jak podano poniżej:

Unexpected @FunctionalInterface annotation
@FunctionalInterface ^ MathOperation is not a functional interface
multiple non-overriding abstract methods found in interface MathOperation

Interfejs funkcjonalny jest poprawny, nawet jeśli adnotacja @FunctionalInterface zostałaby pominięta. Służy tylko do informowania kompilatora o wymuszeniu pojedynczej abstrakcyjnej metody wewnątrz interfejsu.

 interface MathOperation {
      int operation(int a, int b);
 }

Koncepcyjnie interfejs funkcjonalny ma dokładnie jedną abstrakcyjną metodę. Ponieważ metody domyślne mają implementację, nie są abstrakcyjne. Ponieważ metody domyślne nie są abstrakcyjne, jesteś darmowe dodawanie domyślnych metod do funkcjonalnego interfejsu, ile chcesz.

Poniżej znajduje się poprawny interfejs funkcjonalny:

@FunctionalInterface
 interface MathOperation {
      int operation(int a, int b);
      default void doSomeMathOperation(){
       //Method body
      }
 }

Jeśli interfejs deklaruje abstrakcyjną metodę nadpisującą jedną z publicznych metod Javy.lang.Obiekt, który również nie liczy do abstrakcyjnych metod interfejsu, ponieważ każda implementacja interfejsu będzie miała implementację z Javy.lang.Obiekt lub gdzie indziej.

Np. Poniżej znajduje się prawidłowa funkcjonalność interfejs, mimo że zadeklarował dwie abstrakcyjne metody. Dlaczego? Ponieważ jedna z tych abstrakcyjnych metod " equals ()", która ma sygnaturę równą publicznej metodzie w klasie obiektu.

@FunctionalInterface
 interface MathOperation {
      int operation(int a, int b);
      @Override
      public String toString();  //Overridden from Object class
      @Override
      public boolean equals(Object obj); //Overridden from Object class
 }

Podczas gdy zamierzone użycie interfejsów funkcjonalnych jest dla wyrażeń lambda, odniesienia do metod i odniesienia do konstruktorów , nadal mogą być używane, jak każdy interfejs, z anonimowymi klasami, zaimplementowanymi przez klasy lub utworzonymi przez metody fabryczne.

 49
Author: Prakash Hari Sharma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-27 14:35:50

Dokumentacja rzeczywiście robi różnicę między celem

Typ adnotacji informacyjnej używany do wskazania, że deklaracja typu interfejsu ma być interfejsem funkcjonalnym zgodnie ze specyfikacją języka Java.

I przypadek użycia

Zauważ, że instancje interfejsów funkcjonalnych mogą być tworzone za pomocą wyrażeń lambda, odniesień do metod lub odniesień do konstruktorów.

Którego sformułowanie nie wyklucza innych przypadków użycia w ogóle. Ponieważ głównym celem jest wskazanie functional interface, Twoje pytanie sprowadza się do "Czy istnieją inne przypadki użyciafunctional interfaces INNE niż wyrażenia lambda i odniesienia do metod/konstruktorów?"

Ponieważ functional interface jest konstrukcją języka Java zdefiniowaną przez specyfikację języka Java, tylko ta specyfikacja może odpowiedzieć na to pytanie:

JLS §9.8. Interfejsy Funkcjonalne :

Oprócz zwykłego procesu tworzenia instancji interfejsu poprzez deklarowanie i tworzenie instancji klasy (§15.9), instancje interfejsów funkcjonalnych mogą być tworzone za pomocą wyrażeń referencyjnych metody i wyrażeń lambda (§15.13, §15.27).

Więc specyfikacja języka Java nie mówi inaczej, jedynym przypadkiem użycia wspomnianym w tej sekcji jest tworzenie instancji interfejsu z wyrażeniami referencyjnymi metod i wyrażenia lambda. (Obejmuje to odwołania do konstruktorów, ponieważ są one odnotowane jako jedna z form wyrażenia odniesienia do metody w specyfikacji).

Więc w jednym zdaniu, Nie, Nie ma innego przypadku użycia tego w Java 8.

 9
Author: Holger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-27 08:34:19

Wcale nie. Wyrażenia Lambda są jedynym punktem tej adnotacji.

 8
Author: Louis Wasserman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-27 06:25:24

Wyrażenie lambda może być przypisane do typu functional interface, podobnie jak odwołania do metod i klasy anonimowe.

Jedną miłą rzeczą w specyficznych interfejsach funkcjonalnych w java.util.function jest to, że mogą one być tworzone w celu tworzenia nowych funkcji (takich jak Function.andThen i Function.compose, Predicate.and, itd.) ze względu na poręczne metody domyślne, które zawierają.

 5
Author: Hank D,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-27 06:46:44

Jak powiedzieli inni, interfejs funkcjonalny jest interfejsem, który eksponuje jedną metodę. Może mieć więcej niż jedną metodę, ale wszystkie inne muszą mieć domyślną implementację. Powodem, dla którego nazywa się go "funkcjonalnym interfejsem", jest to, że skutecznie działa jako funkcja. Ponieważ można przekazać interfejsy jako parametry, oznacza to, że funkcje są teraz "obywatelami pierwszej klasy", jak w funkcyjnych językach programowania. Ma to wiele zalet, a podczas korzystania ze strumienia zobaczysz je dość często API. Oczywiście, wyrażenia lambda są dla nich głównym oczywistym zastosowaniem.

 3
Author: Sina Madani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-27 14:39:56

Interfejs z tylko jedną abstrakcyjną metodą nazywa się interfejsem funkcjonalnym. Używanie @FunctionalInterface nie jest obowiązkowe, ale najlepiej jest używać go z funkcjonalnymi interfejsami, aby uniknąć przypadkowego dodawania dodatkowych metod. Jeśli interfejs jest adnotowany adnotacją @ FunctionalInterface i staramy się mieć więcej niż jedną abstrakcyjną metodę, powoduje to błąd kompilatora.

package com.akhi;
    @FunctionalInterface
    public interface FucnctionalDemo {

      void letsDoSomething();
      //void letsGo();      //invalid because another abstract method does not allow
      public String toString();    // valid because toString from Object 
      public boolean equals(Object o); //valid

      public static int sum(int a,int b)   // valid because method static
        {   
            return a+b;
        }
        public default int sub(int a,int b)   //valid because method default
        {
            return a-b;
        }
    }
 2
Author: Akhilesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-03 09:47:49

@FunctionalInterface czy nowa adnotacja została wydana w Javie 8 i zapewnia typy docelowe dla wyrażeń lambda i jest używana przy sprawdzaniu czasu kompilacji kodu.

Kiedy chcesz go użyć:

1-twój interfejs nie może mieć więcej niż jedną abstrakcyjną metodę, w przeciwnym razie zostanie podany błąd kompilacji.

1-twój interfejs powinien być czysty, co oznacza, że interfejs funkcjonalny ma być zaimplementowany przez klasy bezstanowe, exmple z pure is Comparator interfejs ponieważ nie zależy od stanu implementatorów, w tym przypadku nie zostanie podany błąd kompilacji, ale w wielu przypadkach nie będzie można używać lambda z tego typu interfejsami

Pakiet java.util.function zawiera różne interfejsy funkcjonalne ogólnego przeznaczenia, takie jak Predicate, Consumer, Function, i Supplier.

Należy również pamiętać, że można używać lambda bez tej adnotacji.

 1
Author: Ahmad Al-Kurdi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-17 17:50:41

Oprócz innych odpowiedzi, myślę, że główny powód "dlaczego używanie interfejsu funkcjonalnego innego niż bezpośrednio z wyrażeniami lambda" może być związany z naturą języka Java, który jest zorientowany obiektowo.

Główne atrybuty wyrażeń Lambda to: 1. Mogą być przekazywane około 2. i mogą być wykonane w przyszłości w określonym czasie (kilka razy). Teraz, aby wspierać tę funkcję w językach, niektóre inne języki zajmują się po prostu tą sprawą.

Na przykład w Java Script, a funkcja (funkcja anonimowa lub literały funkcji) może być zaadresowana jako obiekt. Tak więc, można je tworzyć w prosty sposób, a także można je przypisać do zmiennej i tak dalej. Na przykład:

var myFunction = function (...) {
    ...;
}
alert(myFunction(...));

Lub poprzez ES6, można użyć funkcji strzałki.

const myFunction = ... => ...

Do tej pory projektanci języka Java nie akceptowali obsługi wspomnianych funkcji w ten sposób (techniki programowania funkcyjnego). Uważają, że język Java jest zorientowany obiektowo i dlatego powinni rozwiązać ten problem poprzez Techniki zorientowane obiektowo. Nie chcą przegapić prostoty i spójności języka Java.

Dlatego używają interfejsów, ponieważ gdy potrzebny jest obiekt interfejsu z tylko jedną metodą (mam na myśli interfejs funkcjonalny), można go zastąpić wyrażeniem lambda. Np.:

ActionListener listener = event -> ...;
 1
Author: MMKarami,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-14 13:44:00

Możesz używać lambda w Javie 8

  public static void main(String[] args) {
    tentimes(inputPrm -> System.out.println(inputPrm));
    //tentimes(System.out::println);  // You can also replace lambda with static method reference
    }

    public static void tentimes(Consumer myFunction){
      for(int i = 0; i < 10; i++)
        myFunction.accept("hello");
    }

Aby uzyskać więcej informacji o Java Lambdas i FunctionalInterfaces

 1
Author: Akiner Alkan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-17 06:06:05