Bisakah sebuah java lambda memiliki lebih dari 1 parameter?


158

Di Jawa, mungkinkah lambda menerima berbagai jenis?

Yaitu: Variabel tunggal berfungsi:

    Function <Integer, Integer> adder = i -> i + 1;
    System.out.println (adder.apply (10));

Varargs juga berfungsi:

    Function <Integer [], Integer> multiAdder = ints -> {
        int sum = 0;
        for (Integer i : ints) {
            sum += i;
        }
        return sum;
    };

    //.... 
    System.out.println ((multiAdder.apply (new Integer [] { 1, 2, 3, 4 })));

Tetapi saya menginginkan sesuatu yang dapat menerima berbagai jenis argumen, misalnya:

    Function <String, Integer, Double, Person, String> myLambda = a , b, c, d->  {
    [DO STUFF]
    return "done stuff"
    };

Penggunaan utama adalah memiliki fungsi inline kecil di dalam fungsi untuk kenyamanan.

Saya telah melihat-lihat google dan memeriksa Paket Fungsi Java, tetapi tidak dapat menemukannya. Apakah ini mungkin?

Jawaban:


178

Mungkin saja jika Anda mendefinisikan antarmuka fungsional dengan beberapa parameter tipe. Tidak ada tipe bawaan seperti itu. (Ada beberapa tipe terbatas dengan beberapa parameter.)

@FunctionalInterface
interface Function6<One, Two, Three, Four, Five, Six> {
    public Six apply(One one, Two two, Three three, Four four, Five five);
}

public static void main(String[] args) throws Exception {
    Function6<String, Integer, Double, Void, List<Float>, Character> func = (a, b, c, d, e) -> 'z';
}

Saya sudah menyebutnya di Function6sini. Nama sesuai dengan kebijaksanaan Anda, coba saja untuk tidak berbenturan dengan nama yang ada di perpustakaan Java.


Juga tidak ada cara untuk mendefinisikan sejumlah variabel tipe parameter, jika itu yang Anda tanyakan.


Beberapa bahasa, seperti Scala, mendefinisikan sejumlah tipe bawaan, dengan parameter tipe 1, 2, 3, 4, 5, 6, dll.


58
Anda selalu dapat menggunakan Currying:Function<One, Function<Two, Function<Three, Function<Four, Function<Five, Six>>>>> func = a -> b -> c -> d -> e -> 'z';
Holger

@ SotiriosDelimanolis: Saya lebih suka memilih nama yang berbeda dari Functionyang bentrok dengan java.util.function.Function<T,R>yang mungkin tidak jelas untuk pemula.
Nikolas

@ Nikolas Itu masuk akal. Diedit.
Sotirios Delimanolis

39

Untuk sesuatu dengan 2 parameter, Anda dapat menggunakan BiFunction. Jika Anda membutuhkan lebih banyak, Anda dapat mendefinisikan antarmuka fungsi Anda sendiri, seperti:

@FunctionalInterface
public interface FourParameterFunction<T, U, V, W, R> {
    public R apply(T t, U u, V v, W w);
}

Jika ada lebih dari satu parameter, Anda harus meletakkan tanda kurung di sekitar daftar argumen, seperti:

FourParameterFunction<String, Integer, Double, Person, String> myLambda = (a, b, c, d) -> {
    // do something
    return "done something";
};

35

Untuk kasus ini, Anda bisa menggunakan antarmuka dari pustaka default (java 1.8):

java.util.function.BiConsumer
java.util.function.BiFunction

Ada contoh kecil (bukan yang terbaik) dari metode default di antarmuka:

default BiFunction<File, String, String> getFolderFileReader() {
    return (directory, fileName) -> {
        try {
            return FileUtils.readFile(directory, fileName);
        } catch (IOException e) {
            LOG.error("Unable to read file {} in {}.", fileName, directory.getAbsolutePath(), e);
        }
        return "";
    };
}}

5
Anda akan mendapatkan lebih banyak suara dari penggemar Java8 jika Anda mengubah pertanyaan Anda untuk menggambarkan bagaimana antarmuka tersebut dapat digunakan untuk memenuhi persyaratan.
Martin Cowie

3
BiFunction memungkinkan Anda untuk mendefinisikan hanya fungsi dua argumen, pertanyaannya adalah tentang fungsi dengan sejumlah argumen
Dmitry Klochkov

8

Untuk memanfaatkan lambda: Ada tiga jenis operasi:
1. Terima parameter -> Konsumen
2. Uji parameter pengembalian boolean -> Predikat
3. Manipulasi parameter dan nilai balik -> Fungsi

Java Fungsional antarmuka hingga dua parameter:
antarmuka parameter tunggal Fungsi Predikat
Konsumen Dua antarmuka parameter BiConsumer BiPredicate BiFunction







Untuk lebih dari dua , Anda harus membuat antarmuka fungsional sebagai berikut (Jenis konsumen):

@FunctionalInterface
public interface FiveParameterConsumer<T, U, V, W, X> {
    public void accept(T t, U u, V v, W w, X x);
}

1

Alternatif lain, tidak yakin apakah ini berlaku untuk masalah khusus Anda tetapi untuk beberapa itu mungkin berlaku adalah untuk digunakan UnaryOperatordi perpustakaan java.util.function. di mana ia mengembalikan tipe yang sama yang Anda tentukan, jadi Anda menempatkan semua variabel Anda dalam satu kelas dan apakah itu sebagai parameter:

public class FunctionsLibraryUse {

    public static void main(String[] args){
        UnaryOperator<People> personsBirthday = (p) ->{
            System.out.println("it's " + p.getName() + " birthday!");
            p.setAge(p.getAge() + 1);
            return p;
        };
        People mel = new People();
        mel.setName("mel");
        mel.setAge(27);
        mel = personsBirthday.apply(mel);
        System.out.println("he is now : " + mel.getAge());

    }
}
class People{
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

Jadi kelas yang Anda miliki, dalam hal ini Person, dapat memiliki banyak variabel instan dan tidak perlu mengubah parameter ekspresi lambda Anda.

Bagi yang berminat, saya telah menulis catatan tentang cara menggunakan perpustakaan java.util.function: http://sysdotoutdotprint.com/index.php/2017/04/28/java-util-function-library/


1

Anda juga bisa menggunakan perpustakaan jOOL - https://github.com/jOOQ/jOOL

Ini sudah menyiapkan antarmuka fungsi dengan berbagai parameter. Misalnya, Anda dapat menggunakan org.jooq.lambda.function.Function3, dll dari Function0hingga Function16.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.