Meslekten olmayan kişiler için Java 8 Tedarikçi ve Tüketici açıklaması


105

Java öğrenen Java dışı bir programcı olarak, şu anda okuyorum Supplierve Consumerarayüzler yapıyorum . Ve onların kullanımları ve anlamları etrafında kafamı dolduramıyorum. Bu arayüzleri ne zaman ve neden kullanırsınız? Birisi bana basit bir meslekten olmayan örnek verebilir mi… Doc örneklerini anladığım kadarıyla yeterince özlü bulmuyorum.


4
API Doc Her Sayfa bir bağlantı için tıklayabilirsiniz üstündeki “KULLANIMINI” etiketli etti Consumerve Supplierayrıca arayabilir öğretici için Consumer...
Holger

8
Stuart Marks'ın cevabına bayılıyorum. Ve bence aşağıda cevap veren çoğu kişi konuyu kaçırdı. Sorun, Tedarikçiler, Tüketiciler ve Fonksiyonların "nasıl" yazılacağı değil. Bu, dünyada "neden" istiyorsun? Onlara alışkın olmayan biri için kodu çok daha karmaşık hale getiriyorlar. Ancak bunları kullanmanın yararı net değil.
anton1980

Görebildiğim kadarıyla (ve teğetsel açıklamalarla ilgili hayal kırıklığınızı paylaşıyorum) bu, bir kod parçasında kullanılan bir nesneden hem nesne türünü hem de nesne muamelesini soyutlamanın basit bir yolu. Bu, aynı kodun sadece farklı yeni sınıfları tanımlayarak ve bunları Tedarikçi ve Tüketici arayüzlerine enjekte ederek birçok farklı nesne türüne uygulanmasına izin verir. Bu nedenle, bir polis kayıt sisteminde, tüm şüpheliler için aynı yüzeysel kod kullanılır, ancak her biri için nihai çıktı her bir şüphelinin sınıflandırmasına bağlıdır, örneğin 'vatandaş', 'küçük', 'hırsız', 'suçlu', 'sertleştirilmiş', vb.
Gövde

Yanıtlar:


97

Bu Tedarikçi:

public Integer getInteger() {
    return new Random().nextInt();
}

Bu Tüketici:

public void sum(Integer a, Integer b) {
    System.out.println(a + b);
}

Dolayısıyla meslekten olmayan terimlerle, bir tedarikçi bir değer döndüren bir yöntemdir (dönüş değerinde olduğu gibi). Oysa tüketici, bir miktar değer tüketen (yöntem argümanında olduğu gibi) ve bunlar üzerinde bazı işlemler yapan bir yöntemdir.

Bunlar aşağıdaki gibi bir şeye dönüşecek:

// 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);

Kullanım konusuna gelince, en temel örnek şu olacaktır: Stream#forEach(Consumer)yöntem. Üzerinde yinelediğiniz akıştaki öğeyi tüketen ve her biri üzerinde bazı eylemler gerçekleştiren bir Tüketici alır. Muhtemelen yazdırın.

Consumer<String> stringConsumer = (s) -> System.out.println(s.length());
Arrays.asList("ab", "abc", "a", "abcd").stream().forEach(stringConsumer);

3
Öyleyse, bir Tedarikçi 'bir şey' döndüren bir yöntemin örneğini yaratmanın bir yolu mu?
james emanon

3
@jamesemanon Kesinlikle. Bu bir yöntem başvurusu veya bir lambda olabilir.
Rohit Jain

15
Yöntemi doğrudan çağırmak yerine bunun faydası nedir? Bunun nedeni, Tedarikçinin bir aracı gibi hareket edip bu "getiri" değerini teslim edebilmesi mi?
james emanon

1
Tüketici <Tamsayı, Tamsayı> geçerli değil. Bir tüketicinin tek bir tür parametresi vardır.
nascar

2
Peki neden böyle bir yapı yaratılsın? Java ile hangi problem çözülür?
Trunk

179

İçindekiler gibi işlevsel arabirimlerin anlamını kavramakta güçlük çekmenizin nedeni java.util.function, burada tanımlanan arabirimlerin herhangi bir anlamı olmamasıdır! Temelde anlambilim değil yapıyı temsil etmek için bulunurlar .

Bu, çoğu Java API'si için alışılmadık bir durumdur. Sınıf veya arabirim gibi tipik Java API'sinin anlamı vardır ve temsil ettiği şey için zihinsel bir model geliştirebilir ve üzerindeki işlemleri anlamak için bunu kullanabilirsiniz. java.util.ListÖrneğin düşünün . A List, diğer nesnelerin bulunduğu bir kaptır. Bir dizileri ve indeksi var. Listede bulunan nesnelerin sayısı tarafından döndürülür size(). Her nesnenin 0..size-1 (dahil) aralığında bir dizini vardır. İ indeksindeki nesne çağrı yapılarak alınabilir list.get(i). Ve benzeri.

İşlevsel arayüzlerin java.util.functionböyle bir anlamı yoktur. Bunun yerine, bağımsız değişkenlerin sayısı, dönüş değerlerinin sayısı ve (bazen) bir bağımsız değişken veya dönüş değerinin ilkel olup olmadığı gibi bir işlevin yapısını temsil eden arabirimlerdir . Dolayısıyla Function<T,R>, T türünde tek bir bağımsız değişken alan ve R türünden bir değer döndüren bir işlevi temsil eden bir şeyimiz var . Bu kadar. Bu işlev ne işe yarar? Tek bir argüman alıp tek bir değer döndürdüğü sürece her şeyi yapabilir. Bu nedenle için belirtim Function<T,R>, "Bir bağımsız değişkeni kabul eden ve bir sonuç üreten bir işlevi temsil eder" den biraz daha fazlasıdır.

Açıkça, kod yazarken anlamı vardır ve bu anlam bir yerden gelmelidir. İşlevsel arayüzler söz konusu olduğunda anlam, kullanıldıkları bağlamdan gelir. Arayüzün Function<T,R>tek başına bir anlamı yoktur. Bununla birlikte, java.util.Map<K,V>API'de aşağıdakiler vardır:

V computeIfAbsent(K key, Function<K,V> mappingFunction)

(kısalık için joker karakterler seçilmiştir)

Ah, bu kullanımı Functionbir "eşleme fonksiyonu" olarak. Bu ne yapar? Bu bağlamda, keyharitada halihazırda mevcut değilse, eşleme işlevi çağrılır ve anahtar verilir ve bir değer üretmesi beklenir ve ortaya çıkan anahtar / değer çifti haritaya eklenir.

Bu nedenle, teknik özelliklere Function(veya bu konuda diğer işlevsel arayüzlerden herhangi birine) bakıp ne anlama geldiklerini anlamaya çalışamazsınız. Ne anlama geldiklerini anlamak için diğer API'lerde nerede kullanıldıklarına bakmanız gerekir ve bu anlam yalnızca bu bağlam için geçerlidir.


4
Yani temelde, yalnızca tür olarak işlev görür
Jack Guo

Başka bir yararlı bilgi de, işlevsel arayüzlerin kodunuza davranış ekleyebilecek birden fazla uygulanan yönteme sahip olabileceğidir
Jhon Mario Lotero

28

A Supplier, bağımsız değişken almayan ve bir değer döndüren herhangi bir yöntemdir. İşi tam anlamıyla beklenen bir sınıfın bir örneğini sağlamaktır. Örneğin, bir 'alıcı' yöntemine yapılan her başvuru birSupplier

public Integer getCount(){
    return this.count;
}

Örnek yöntem başvurusu myClass::getCount, bir örneğidir Supplier<Integer>.

A Consumer, bağımsız değişkenler alan ve hiçbir şey döndürmeyen herhangi bir yöntemdir. Yan etkileri nedeniyle çağrılır. Java terimleriyle, a Consumer, bir voidyöntem için bir deyimdir . 'ayarlayıcı' yöntemleri iyi bir örnektir:

public void setCount(int count){
    this.count = count;
}

Örnek yöntem başvurusu myClass::setCountbir Consumer<Integer>ve örneğidir IntConsumer.

A Function<A,B>, bir türden bir argüman alan ve başka birini döndüren herhangi bir yöntemdir. Bu bir 'dönüşüm' olarak adlandırılabilir. Bir Function<A,B>alır Ave bir döndürür B. Önemli olan, belirli bir değer için A, işlevin her zaman belirli bir değeri döndürmesi gerektiğidir B. Ave Baslında aşağıdakiler gibi aynı türde olabilir:

public Integer addTwo(int i){
    return i+2;
}

Örnek yöntem referansı myClass:addTwoa Function<Integer, Integer>ve a'dır ToIntFunction<Integer>.

Alıcıya Sınıf yöntemi başvurusu, bir işlevin başka bir örneğidir.

public Integer getCount(){
    return this.count;
}

Sınıf yöntemi referansı MyClass::getCountbir Function<MyClass,Integer>ve örneğidir ToIntFunction<MyClass>.


16

Neden Tüketici / Tedarikçi / diğer işlevsel arayüzler java.util.function paketinde tanımlanmıştır : Tüketici ve Tedarikçi, Java 8'de sağlanan yerleşik işlevsel arabirimlerin çoğu arasında ikisidir. Tüm bu yerleşik işlevsel arabirimlerin amacı, ortak fonksiyon tanımlayıcılara (fonksiyonel yöntem imzaları / tanımları) sahip fonksiyonel arayüzler için hazır bir "şablon" sağlamak.

Diyelim ki, bir T tipini başka bir R tipine dönüştürmek için bir ihtiyacımız var diyelim.Bunun gibi bir parametre olarak tanımlanan herhangi bir fonksiyonu bir metoda geçireceksek, o zaman bu metodun fonksiyonel / soyut metodu parametre alan bir Fonksiyonel Arayüz tanımlaması gerekecektir. T tipi girdi olarak ve çıktı olarak R tipi bir parametre verir. Şimdi, bunun gibi birçok senaryo olabilir ve programcı (lar) kendi ihtiyaçları için çok sayıda işlevsel arayüz tanımlamaya başlayabilir. Bu tür bir senaryodan kaçınmak, programlamayı kolaylaştırmak ve fonksiyonel arayüzlerin kullanımında ortak bir standart getirmek için Predicate, Function, Consumer & Supplier gibi bir dizi yerleşik fonksiyonel arayüz tanımlanmıştır.

Tüketici ne yapar : Tüketici işlevsel arayüzü bir girişi kabul eder, bu girişle bir şeyler yapar ve herhangi bir çıktı vermez. Tanımı şuna benzer (Java Kaynağından) -

@FunctionalInterface
public interface Consumer<T> {
 void accept(T t);
}

Burada accept () bir girdi alan ve çıktı döndürmeyen işlevsel \ soyut yöntemdir. Dolayısıyla, bir Tamsayı girmek istiyorsanız, bununla çıktı olmadan bir şeyler yapın, o zaman kendi arayüzünüzü tanımlamak yerine bir Tüketici örneği kullanın.

Tedarikçi ne yapar : Tedarikçi işlevsel arayüzü herhangi bir girdi almaz, ancak bir çıktı döndürür. Bu şekilde tanımlanmıştır (Java Kaynağından) -

@FunctionalInterface
public interface Supplier<T> {
  T get();
}

Bir şeyi döndüren bir işleve ihtiyaç duyduğunuz her yerde, örneğin bir Tamsayı, ancak çıktı almayan bir işleve bir Supplier örneğini kullanın.

Tüketici ve Tedarikçi arayüzlerinin örnek kullanımıyla birlikte daha fazla netliğe ihtiyaç duyulması halinde, blog yazılarıma aynı şekilde başvurabilirsiniz - http://www.javabrahman.com/java-8/java-8-java-util- function-tüketici-öğretici-örneklerle / ve http://www.javabrahman.com/java-8/java-8-java-util-function-supplier-tutorial-with-examples/


12

1. Anlam

Sorumun cevabımı bakınız burada ve aynı zamanda başka burada ama kısaca bu yeni Arayüzler sağlamak kongre ve tanımlayıcılığı herkesin kullanması için sağlar (+ gibi eğlenceli yöntem zincirleme.forEach(someMethod().andThen(otherMethod()))

2. Farklılıklar

Tüketici : Bir şey alır, bir şey yapar, hiçbir şey döndürmez:void accept(T t)

Tedarikçi: Hiçbir şey almaz, bir şey döndürür: T get()(Tüketicinin tersi, temelde evrensel bir 'alıcı' yöntemi)

3. Kullanım

// Consumer: It takes something (a String) and does something (prints it) 
    List<Person> personList = getPersons();

     personList.stream()
                    .map(Person::getName)    
                    .forEach(System.out::println); 

Tedarikçi: tekrarlayan kodu sarın, örneğin kod yürütme zamanlaması

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;
    }
}

0

Laymen terimleriyle,

tedarikçi, verileri herhangi bir veri tüketmeden tedarik edecektir. Programlama açısından, herhangi bir argüman almayan ancak bir değer döndüren bir yöntem. Yeni değerler oluşturmak için kullanılır.

http://codedestine.com/java-8-supplier-interface/

tüketici verileri tüketecek ancak herhangi bir veri iade etmeyecektir. Programlama terimlerinde, birden çok argüman alan ve herhangi bir değer döndürmeyen bir yöntem.

http://codedestine.com/java-8-consumer-interface/


0

Tüketici ve tedarikçi, java tarafından sağlanan arayüzlerdir. Tüketici, liste öğeleri üzerinde yineleme için kullanılır ve tedarikçi, tedarik nesnelerinin

kod gösterimi ile kolayca anlayabilirsiniz.

Tüketici

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);

    }

}

Tedarikçi

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());
    }

}

0

En basit cevap şu olabilir:

Bir Tüketici, İşlev <T, Void> olarak görülebilir. Bir Tedarikçi, İşlev <Geçersiz, T> olarak görüntülenebilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.