Penjelasan Pemasok & Konsumen Java 8 untuk orang awam

103

Sebagai programmer non-Java yang mempelajari Java, saya membaca tentang Supplierdan Consumerantarmuka saat ini. Dan saya tidak bisa memahami penggunaan dan maknanya. Kapan dan mengapa Anda akan menggunakan antarmuka ini? Dapatkah seseorang memberi saya contoh orang awam yang sederhana tentang ini… Saya menemukan contoh Doc tidak cukup ringkas untuk pemahaman saya.

james emanon
sumber
4
Setiap Halaman Dokumen API memiliki tautan berlabel "GUNAKAN" di bagian atas yang dapat Anda klik Consumerdan SupplierAnda juga dapat mencari tutorial untuk Consumer
Holger
7
Saya suka jawaban dari Stuart Marks. Dan saya pikir kebanyakan orang yang menjawab di bawah ini melewatkan intinya. Pertanyaannya bukanlah "bagaimana" menulis Pemasok, Konsumen, dan Fungsi. Ini adalah "mengapa" di dunia ini yang Anda inginkan? Untuk orang yang tidak terbiasa dengannya, mereka membuat kodenya jauh lebih kompleks. Tetapi manfaat menggunakannya tidak jelas.
anton1980
Sejauh yang saya bisa lihat (dan saya berbagi rasa frustrasi Anda dengan deskripsi tangensial) itu hanya cara yang apik untuk mengabstraksi tipe objek dan perlakuan objek dari objek yang digunakan dalam sepotong kode. Hal ini memungkinkan penerapan kode yang sama ini ke berbagai jenis objek dengan hanya mendefinisikan kelas baru yang berbeda dan memasukkannya ke dalam antarmuka Pemasok dan Konsumen. Jadi, dalam sistem pencatatan polisi, kode dangkal yang sama digunakan untuk semua tersangka tetapi hasil cetak akhir untuk masing-masing tergantung pada klasifikasi masing-masing tersangka, misalnya 'warga negara', 'kecil', 'larcen', 'penjahat', 'keras', dll.
Batang

Jawaban:

96

Ini adalah Pemasok:

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

Ini Konsumen:

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

Jadi dalam istilah awam, pemasok adalah metode yang mengembalikan beberapa nilai (seperti dalam nilai pengembaliannya). Padahal, konsumen adalah metode yang mengkonsumsi beberapa nilai (seperti dalam argumen metode), dan melakukan beberapa operasi padanya.

Itu akan berubah menjadi seperti ini:

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

Adapun penggunaan, contoh yang paling mendasar adalah: Stream#forEach(Consumer)metode. Dibutuhkan Konsumen, yang mengkonsumsi elemen dari arus yang Anda iterasi, dan melakukan beberapa tindakan pada masing-masingnya. Mungkin mencetaknya.

Consumer<String> stringConsumer = (s) -> System.out.println(s.length());
Arrays.asList("ab", "abc", "a", "abcd").stream().forEach(stringConsumer);
Rohit Jain
sumber
3
Jadi, Pemasok adalah cara untuk membuat contoh metode yang mengembalikan 'sesuatu'?
james emanon
3
@jamesemanon Persis. Itu mungkin referensi metode, atau lambda.
Rohit Jain
15
Apa keuntungan dari ini daripada memanggil metode secara langsung? Apakah karena Pemasok dapat bertindak seperti perantara dan menyerahkan nilai "pengembalian" itu?
James emanon
1
Konsumen <Integer, Integer> tidak valid. Seorang konsumen memiliki parameter tipe tunggal.
nascar
2
Tapi MENGAPA membuat konstruksi seperti itu? Masalah apa yang diselesaikan dengan memilikinya di Java?
Batang
179

Alasan Anda mengalami kesulitan dalam memahami arti antarmuka fungsional seperti yang ada di dalamnya java.util.functionadalah karena antarmuka yang ditentukan di sini tidak memiliki arti! Mereka hadir terutama untuk mewakili struktur , bukan semantik .

Ini tidak umum untuk sebagian besar Java API. Java API yang khas, seperti kelas atau antarmuka, memiliki arti, dan Anda dapat mengembangkan model mental untuk apa yang diwakilinya dan menggunakannya untuk memahami operasi di dalamnya. Pertimbangkan java.util.Listmisalnya. A Listadalah wadah benda lain. Mereka memiliki urutan dan indeks. Jumlah objek yang terdapat dalam daftar dikembalikan oleh size(). Setiap objek memiliki indeks dalam kisaran 0..size-1 (inklusif). Objek pada indeks i dapat diambil dengan memanggil list.get(i). Dan seterusnya.

Antarmuka fungsional java.util.functiontidak memiliki arti seperti itu. Sebaliknya, mereka adalah antarmuka yang hanya mewakili struktur suatu fungsi, seperti jumlah argumen, jumlah nilai yang dikembalikan, dan (terkadang) apakah argumen atau nilai yang dikembalikan adalah primitif. Dengan demikian kita memiliki sesuatu seperti Function<T,R>yang merupakan fungsi yang mengambil satu argumen tipe T dan mengembalikan nilai tipe R . Itu dia. Apa fungsi itu? Yah, itu bisa melakukan apa saja ... selama itu membutuhkan satu argumen dan mengembalikan satu nilai. Itulah mengapa spesifikasi untuk Function<T,R>tidak lebih dari "Merupakan fungsi yang menerima satu argumen dan menghasilkan hasil."

Jelasnya, ketika kita menulis kode, itu memiliki makna, dan makna itu harus datang dari suatu tempat. Dalam kasus antarmuka fungsional, artinya berasal dari konteks di mana mereka digunakan. Antarmuka Function<T,R>tidak memiliki arti dalam isolasi. Namun, di java.util.Map<K,V>API, ada yang berikut ini:

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

(karakter pengganti dieliminasi untuk singkatnya)

Ah, penggunaan Functionini sebagai "fungsi pemetaan". Apa fungsinya? Dalam konteks ini, jika keybelum ada di peta, fungsi pemetaan dipanggil dan diberikan kunci dan diharapkan menghasilkan nilai, dan pasangan kunci-nilai yang dihasilkan dimasukkan ke dalam peta.

Jadi, Anda tidak dapat melihat spesifikasi untuk Function(atau antarmuka fungsional lainnya, dalam hal ini) dan mencoba memahami apa artinya. Anda harus melihat di mana mereka digunakan di API lain untuk memahami apa artinya, dan arti itu hanya berlaku untuk konteks itu.

Stuart Marks
sumber
4
Jadi pada dasarnya, itu hanya berfungsi sebagai tipe
Jack Guo
Mungkin informasi lain yang berguna adalah bahwa antarmuka fungsional dapat memiliki beberapa metode yang diterapkan yang dapat menambahkan perilaku ke kode Anda
Jhon Mario Lotero
28

A Supplieradalah metode apa pun yang tidak membutuhkan argumen dan mengembalikan nilai. Tugasnya secara harfiah adalah menyediakan contoh kelas yang diharapkan. Misalnya, setiap referensi ke metode 'pengambil' adalah aSupplier

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

Referensi metode instance-nya myClass::getCountadalah instance dari Supplier<Integer>.

A Consumeradalah metode apa pun yang mengambil argumen dan tidak mengembalikan apa pun. Itu dipanggil untuk efek sampingnya. Dalam istilah Java, a Consumeradalah ungkapan untuk voidmetode. Metode 'penyetel' adalah contoh yang bagus:

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

Referensi metode instance-nya myClass::setCountadalah instance dari Consumer<Integer>dan IntConsumer.

A Function<A,B>adalah metode apa pun yang mengambil argumen dari satu tipe, dan mengembalikan tipe lain. Ini bisa disebut sebagai 'transformasi'. The Function<A,B>mengambil Adan mengembalikan B. Penting untuk diperhatikan bahwa untuk nilai tertentu A, fungsi tersebut harus selalu mengembalikan nilai tertentu B. Adan Bsebenarnya bisa berjenis sama, seperti berikut ini:

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

Referensi metode instansinya myClass:addTwoadalah a Function<Integer, Integer>dan a ToIntFunction<Integer>.

Referensi metode Kelas ke pengambil adalah contoh lain dari suatu fungsi.

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

Referensi metode kelasnya MyClass::getCountadalah turunan dari Function<MyClass,Integer>dan ToIntFunction<MyClass>.

Steve K
sumber
15

Mengapa Konsumen / Pemasok / antarmuka fungsional lainnya didefinisikan dalam paket java.util.function : Konsumen dan Pemasok adalah dua, di antara banyak, antarmuka fungsional bawaan yang disediakan di Java 8. Tujuan dari semua antarmuka fungsional bawaan ini adalah untuk menyediakan "template" yang siap untuk antarmuka fungsional yang memiliki deskriptor fungsi umum (tanda tangan / definisi metode fungsional).

Katakanlah kita memiliki kebutuhan untuk mengubah tipe T ke tipe lain R. Jika kita melewatkan fungsi apa pun yang didefinisikan seperti ini sebagai parameter ke suatu metode, maka metode itu perlu mendefinisikan Antarmuka Fungsional yang metode fungsional / abstraknya mengambil parameter dari tipe T sebagai input dan memberikan parameter tipe R sebagai output. Sekarang, mungkin ada banyak skenario seperti ini dan programmer akhirnya akan menentukan beberapa antarmuka fungsional untuk kebutuhan mereka. Untuk menghindari skenario semacam ini, mempermudah pemrograman & membawa standar umum dalam penggunaan antarmuka fungsional, satu set antarmuka fungsional bawaan seperti Predikat, Fungsi, Konsumen & Pemasok telah ditentukan.

Apa yang dilakukan Konsumen : Antarmuka fungsional konsumen menerima masukan, melakukan sesuatu dengan masukan tersebut dan tidak memberikan keluaran apa pun. Definisinya seperti ini (dari Sumber Java) -

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

Di sini accept () adalah metode fungsional \ abstrak yang tidak mengambil masukan dan tidak mengembalikan keluaran. Jadi, jika Anda ingin memasukkan Integer, lakukan sesuatu dengannya tanpa output, alih-alih menentukan antarmuka Anda sendiri, gunakan instance Consumer.

Apa yang dilakukan Pemasok : Antarmuka fungsional pemasok tidak menerima masukan apa pun tetapi mengembalikan satu keluaran. Ini didefinisikan seperti ini (dari Sumber Java) -

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

Di mana pun Anda membutuhkan fungsi yang mengembalikan sesuatu, katakanlah Integer, tetapi tidak mengambil keluaran, gunakan contoh Pemasok.

Jika lebih jelas, bersama dengan contoh penggunaan, antarmuka Konsumen & Pemasok diperlukan maka Anda dapat merujuk posting blog saya di tempat yang sama - http://www.javabrahman.com/java-8/java-8-java-util- fungsi-konsumen-tutorial-dengan-contoh / dan http://www.javabrahman.com/java-8/java-8-java-util-function-supplier-tutorial-with-examples/

Dhruv Rai Puri
sumber
12

1. Arti

Lihat jawaban saya atas pertanyaan saya di sini dan juga pertanyaan lain di sini , tetapi singkatnya Antarmuka baru ini memberikan konvensi dan deskripsi untuk digunakan semua orang (+ rangkaian metode yang funky seperti.forEach(someMethod().andThen(otherMethod()))

2. Perbedaan

Konsumen : Mengambil sesuatu, melakukan sesuatu, tidak mengembalikan apa-apa:void accept(T t)

Pemasok: Tidak mengambil apa-apa, mengembalikan sesuatu: T get()(kebalikan dari Konsumen, pada dasarnya metode 'pengambil' universal)

3. Penggunaan

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

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

Pemasok: membungkus kode berulang, misalnya waktu eksekusi kode

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;
    }
}
Andrejs
sumber
0

Dalam istilah Laymen,

pemasok akan memasok data tetapi tanpa mengonsumsi data apa pun. Dalam istilah pemrograman, metode yang tidak mengambil argumen apa pun tetapi mengembalikan nilai. Ini digunakan untuk menghasilkan nilai baru.

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

konsumen akan mengkonsumsi data dan tidak mengembalikan data apapun. Dalam istilah pemrograman, metode yang mengambil banyak argumen dan tidak mengembalikan nilai apa pun.

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

lalitbhagtani.dll
sumber
0

Konsumen dan pemasok adalah antarmuka yang disediakan oleh java. Konsumen digunakan untuk iterasi atas elemen daftar dan pemasok digunakan untuk objek suplai

Anda dapat dengan mudah memahami dengan demonstrasi kode.

Konsumen

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

    }

}

Pemasok

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

}
Ankit Sood
sumber
0

Jawaban paling sederhana bisa jadi:

Konsumen dapat dipandang sebagai Fungsi <T, Void>. Pemasok dapat dipandang sebagai Fungsi <Void, T>.

Yashwin Munsadwala
sumber