Jako programista nie Java nauki Java, czytam o Supplier
i Consumer
interfejsy w tej chwili. I nie mogę pojąć ich użycia i znaczenia. Kiedy i dlaczego miałbyś używać tych interfejsów? Czy ktoś może mi podać prosty przykład dla laika… Uważam, że przykłady Doca nie są wystarczająco zwięzłe, aby moje zrozumienie.
102
Consumer
iSupplier
może też przeszukać poradnik dlaConsumer
...Odpowiedzi:
To jest Dostawca:
public Integer getInteger() { return new Random().nextInt(); }
To jest konsument:
public void sum(Integer a, Integer b) { System.out.println(a + b); }
Więc w kategoriach laika dostawca jest metodą, która zwraca pewną wartość (jak w przypadku wartości zwracanej). Natomiast konsument jest metodą, która zużywa jakąś wartość (jak w argumencie metody) i wykonuje na nich pewne operacje.
Te zmienią się w coś takiego:
// new operator itself is a supplier, of the reference to the newly created object Supplier<List<String>> listSupplier = ArrayList::new; Consumer<String> printConsumer = a1 -> System.out.println(a1); BiConsumer<Integer, Integer> sumConsumer = (a1, a2) -> System.out.println(a1 + a2);
Jeśli chodzi o użycie, bardzo podstawowym przykładem będzie:
Stream#forEach(Consumer)
metoda. Pobiera Konsumenta, który zużywa element ze strumienia, po którym iterujesz, i wykonuje na każdym z nich pewną akcję. Prawdopodobnie je wydrukuje.Consumer<String> stringConsumer = (s) -> System.out.println(s.length()); Arrays.asList("ab", "abc", "a", "abcd").stream().forEach(stringConsumer);
źródło
Powodem, dla którego masz trudności ze zrozumieniem znaczenia funkcjonalnych interfejsów, takich jak te w,
java.util.function
jest to, że zdefiniowane tutaj interfejsy nie mają żadnego znaczenia! Są obecne głównie w celu przedstawienia struktury , a nie semantyki .Jest to nietypowe dla większości interfejsów API języka Java. Typowy interfejs API języka Java, taki jak klasa lub interfejs, ma znaczenie i można opracować model mentalny dla tego, co reprezentuje, i wykorzystać go do zrozumienia wykonywanych na nim operacji. Rozważmy
java.util.List
na przykład. AList
to pojemnik z innymi przedmiotami. Mają sekwencję i indeks. Liczba obiektów zawartych na liście jest zwracana przezsize()
. Każdy obiekt ma indeks z zakresu 0..size-1 (włącznie). Obiekt pod indeksem i można pobrać wywołująclist.get(i)
. I tak dalej.Funkcjonalne interfejsy
java.util.function
nie mają takiego znaczenia. Zamiast tego są interfejsami, które po prostu reprezentują strukturę funkcji, taką jak liczba argumentów, liczba zwracanych wartości i (czasami) to, czy argument lub wartość zwracana jest prymitywem. Tak więc mamy cośFunction<T,R>
co stanowi funkcję, która pobiera jeden argument typu T i zwraca wartość typu R . Otóż to. Co robi ta funkcja? Cóż, może zrobić wszystko ... o ile przyjmuje pojedynczy argument i zwraca pojedynczą wartość. Dlatego specyfikacja forFunction<T,R>
to niewiele więcej niż „Reprezentuje funkcję, która przyjmuje jeden argument i generuje wynik”.Oczywiście, kiedy piszemy kod, ma on znaczenie i to znaczenie musi skądś pochodzić. W przypadku funkcjonalnych interfejsów znaczenie wynika z kontekstu, w jakim są używane. Interfejs
Function<T,R>
nie ma żadnego znaczenia w izolacji. Jednak wjava.util.Map<K,V>
interfejsie API są następujące:V computeIfAbsent(K key, Function<K,V> mappingFunction)
(dla zwięzłości pominięto symbole wieloznaczne)
Ach, to użycie
Function
jest jako „funkcja mapowania”. Co to robi? W tym kontekście, jeślikey
nie jest jeszcze obecna w mapie, wywoływana jest funkcja odwzorowania, otrzymuje klucz i oczekuje się, że wygeneruje wartość, a wynikowa para klucz-wartość jest wstawiana do mapy.Nie możesz więc spojrzeć na specyfikację
Function
(lub żaden z innych funkcjonalnych interfejsów, jeśli o to chodzi) i spróbować rozróżnić, co one oznaczają. Musisz przyjrzeć się, gdzie są używane w innych interfejsach API, aby zrozumieć, co oznaczają, a znaczenie to dotyczy tylko tego kontekstu.źródło
A
Supplier
to dowolna metoda, która nie przyjmuje argumentów i zwraca wartość. Jego zadaniem jest dosłownie dostarczenie instancji oczekiwanej klasy. Na przykład każde odwołanie do metody pobierającej to plikSupplier
public Integer getCount(){ return this.count; }
Jego odwołanie do metody wystąpienia
myClass::getCount
jest wystąpieniemSupplier<Integer>
.A
Consumer
to dowolna metoda, która przyjmuje argumenty i nic nie zwraca. Jest wywoływany ze względu na skutki uboczne. W języku Java aConsumer
jest idiomem dlavoid
metody. Dobrym przykładem są metody „ustawiające”:public void setCount(int count){ this.count = count; }
Jego odwołanie do metody wystąpienia
myClass::setCount
jest wystąpieniemConsumer<Integer>
iIntConsumer
.A
Function<A,B>
to dowolna metoda, która przyjmuje argument jednego typu i zwraca inny. Można to nazwać „transformacją”.Function<A,B>
TrwaA
i zwracaB
. Warto zauważyć, że dla danej wartościA
funkcja powinna zawsze zwracać określoną wartośćB
.A
iB
może być w rzeczywistości tego samego typu, na przykład:public Integer addTwo(int i){ return i+2; }
Jego odwołanie do metody wystąpienia
myClass:addTwo
to aFunction<Integer, Integer>
i aToIntFunction<Integer>
.Odwołanie do metody klasy do metody pobierającej to kolejny przykład funkcji.
public Integer getCount(){ return this.count; }
Jego odwołanie do metody klasy
MyClass::getCount
jest wystąpieniemFunction<MyClass,Integer>
iToIntFunction<MyClass>
.źródło
Dlaczego w pakiecie java.util.function są zdefiniowane interfejsy konsumenta / dostawcy / inne interfejsy funkcjonalne : Konsument i Dostawca to dwa spośród wielu wbudowanych interfejsów funkcjonalnych dostępnych w Javie 8. Celem wszystkich wbudowanych interfejsów funkcjonalnych jest dostarczenie gotowego „szablonu” dla interfejsów funkcjonalnych posiadających wspólne deskryptory funkcji (sygnatury / definicje metod funkcjonalnych).
Powiedzmy, że mamy wymagane przekonwertowanie typu T na inny typ R. Jeśli mielibyśmy przekazać jakąkolwiek funkcję zdefiniowaną w ten sposób jako parametr do metody, wówczas ta metoda musiałaby zdefiniować interfejs funkcjonalny, którego metoda funkcjonalna / abstrakcyjna przyjmuje parametr typu T jako wejście i daje parametr typu R jako wyjście. Takich scenariuszy mogłoby być wiele i programiści mogliby w końcu zdefiniować wiele funkcjonalnych interfejsów dla swoich potrzeb. Aby uniknąć tego rodzaju scenariuszy, ułatwić programowanie i wprowadzić wspólny standard w korzystaniu z interfejsów funkcjonalnych, zdefiniowano zestaw wbudowanych interfejsów funkcjonalnych, takich jak predykat, funkcja, konsument i dostawca.
Co robi konsument : interfejs funkcjonalny konsumenta przyjmuje dane wejściowe, robi coś z tymi danymi wejściowymi i nie przekazuje żadnych danych wyjściowych. Jego definicja jest następująca (z Java Source) -
@FunctionalInterface public interface Consumer<T> { void accept(T t); }
W tym przypadku accept () jest metodą funkcjonalną \ abstrakcyjną, która pobiera dane wejściowe i nie zwraca żadnego wyniku. Tak więc, jeśli chcesz wprowadzić liczbę całkowitą, zrób coś z nią bez wyjścia, a następnie zamiast definiować własny interfejs użyj instancji Consumer.
Co robi Dostawca : Funkcjonalny interfejs dostawcy nie przyjmuje żadnych danych wejściowych, ale zwraca dane wyjściowe. Jest tak zdefiniowany (z Java Source) -
@FunctionalInterface public interface Supplier<T> { T get(); }
Gdziekolwiek potrzebujesz funkcji, która coś zwraca, powiedz liczbę całkowitą, ale nie pobiera danych wyjściowych, użyj instancji Supplier.
W przypadku, gdy potrzebna jest większa przejrzystość, wraz z przykładowym wykorzystaniem, interfejsów konsumenta i dostawcy, możesz polecać moje posty na blogu na tym samym - http://www.javabrahman.com/java-8/java-8-java-util- function-customer-tutorial-with-examples / i http://www.javabrahman.com/java-8/java-8-java-util-function-supplier-tutorial-with-examples/
źródło
1. Znaczenie
Zobacz moje odpowiedzi na moje pytanie tutaj, a także inne tutaj , ale w skrócie te nowe interfejsy zapewniają konwencję i opisowość dla każdego do użycia (+ funky łańcuchowe metody, takie jak
.forEach(someMethod().andThen(otherMethod()))
2. Różnice
Konsument : coś bierze, robi, nic nie zwraca:
void accept(T t)
Dostawca: nic nie bierze, coś zwraca:
T get()
(odwrócenie konsumenta, w zasadzie uniwersalna metoda „pobierająca”)3. Użytkowanie
// Consumer: It takes something (a String) and does something (prints it) List<Person> personList = getPersons(); personList.stream() .map(Person::getName) .forEach(System.out::println);
Dostawca: opakuj powtarzalny kod, np. Czas wykonania kodu
public class SupplierExample { public static void main(String[] args) { // Imagine a class Calculate with some methods Double result1 = timeMe(Calculate::doHeavyComputation); Double result2 = timeMe(Calculate::doMoreComputation); } private static Double timeMe(Supplier<Double> code) { Instant start = Instant.now(); // Supplier method .get() just invokes whatever it is passed Double result = code.get(); Instant end = Instant.now(); Duration elapsed = Duration.between(start,end); System.out.println("Computation took:" + elapsed.toMillis()); return result; } }
źródło
W kategoriach laików
dostawca dostarczy dane, ale bez ich wykorzystywania. W terminologii programowania metoda, która nie przyjmuje żadnego argumentu, ale zwraca wartość. Służy do generowania nowych wartości.
http://codedestine.com/java-8-supplier-interface/
konsument zużyje dane i nie zwróci żadnych danych. W terminologii programowania metoda, która przyjmuje wiele argumentów i nie zwraca żadnej wartości.
http://codedestine.com/java-8-consumer-interface/
źródło
Konsument i dostawca to interfejsy dostarczane przez java. Konsument jest używany do iteracji po elementach listy, a dostawca jest używany do dostarczania obiektów
możesz łatwo zrozumieć dzięki demonstracji kodu.
Konsument
package com.java.java8; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; /** * The Class ConsumerDemo. * * @author Ankit Sood Apr 20, 2017 */ public class ConsumerDemo { /** * The main method. * * @param args * the arguments */ public static void main(String[] args) { List<String> str = new ArrayList<>(); str.add("DEMO"); str.add("DEMO2"); str.add("DEMO3"); /* Consumer is use for iterate over the List */ Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String t) { /* Print list element on consile */ System.out.println(t); } }; str.forEach(consumer); } }
Dostawca
package com.java.java8; import java.util.function.Supplier; /** * The Class SupplierDemo. * * @author Ankit Sood Apr 20, 2017 */ public class SupplierDemo { /** * The main method. * * @param args * the arguments */ public static void main(String[] args) { getValue(() -> "Output1"); getValue(() -> "OutPut2"); } /** * Gets the value. * * @param supplier * the supplier * @return the value */ public static void getValue(Supplier<?> supplier) { System.out.println(supplier.get()); } }
źródło
Najprostszą odpowiedzią może być:
Konsument może być postrzegany jako Function <T, Void>. Dostawca może być postrzegany jako funkcja <Void, T>.
źródło