Java lambda'nın 1'den fazla parametresi olabilir mi?


158

Java'da, lambda'nın birden fazla farklı türü kabul etmesi mümkün müdür?

Yani: Tek değişkenli işler:

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

Varargs ayrıca çalışır:

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

Ama birçok farklı türde argümanı kabul edebilecek bir şey istiyorum, örneğin:

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

Ana kullanım, kolaylık sağlamak için işlevler içinde küçük satır içi işlevlere sahip olmaktır.

Google'a baktım ve Java'nın İşlev Paketini inceledim, ancak bulamadım. Mümkün mü?

Yanıtlar:


178

Birden fazla tip parametresine sahip böyle bir fonksiyonel arayüz tanımlamanız mümkündür. Böyle bir yerleşik tip yoktur. (Birden fazla parametreli birkaç sınırlı tür vardır.)

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

Function6Burada aradım . Ad sizin takdirinize bağlıdır, Java kitaplıklarındaki mevcut adlarla çakışmamaya çalışın.


İstediğiniz şey buysa, değişken sayıda tip parametresi tanımlamanın bir yolu da yoktur.


Scala gibi bazı diller, 1, 2, 3, 4, 5, 6 vb. Tür parametreleriyle bu tür yerleşik bir dizi tanımlar.


58
Currying'ı her zaman kullanabilirsiniz:Function<One, Function<Two, Function<Three, Function<Four, Function<Five, Six>>>>> func = a -> b -> c -> d -> e -> 'z';
Holger

@SotiriosDelimanolis: Doğrusu dan farklı bir ad seçerdim Functionhangi çatışmalarjava.util.function.Function<T,R> o başlayanlar için belirsiz olabilir.
Nikolas

@Nikolas Bu makul. Düzenlenen.
Sotirios Delimanolis

39

2 parametreli bir şey için kullanabilirsiniz BiFunction. Daha fazlasına ihtiyacınız varsa, kendi işlev arayüzünüzü şöyle tanımlayabilirsiniz:

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

Birden fazla parametre varsa, argüman listesine parantez koymanız gerekir, şöyle:

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

35

Bu durumda, varsayılan kitaplıktaki arayüzleri kullanabilirsiniz (java 1.8):

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

Arayüzde varsayılan yöntemin küçük (en iyi değil) bir örneği vardır:

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
Sorunu değiştirerek bu arayüzlerin gereksinimi karşılamak için nasıl kullanılabileceğini göstermek için Java8 hayranlarından daha fazla oy alacaksınız.
Martin Cowie

3
BiFunction yalnızca iki bağımsız değişken işlevini tanımlamanızı sağlar, soru, herhangi bir sayıda bağımsız değişkeni olan işlevlerle ilgilidir
Dmitry Klochkov

8

Lambda kullanmak için: Üç tür işlem vardır:
1. Parametre kabul et -> Tüketici
2. Boolean test parametresi döndürme -> Tahmin
3. Parametre ve dönüş değeri değiştirme -> İşlev

İki parametre kadar Java Fonksiyonel arayüzü:
arayüzü Tek parametre
Tüketici
Yüklem
Fonksiyonu

arayüzü İki parametre
BiConsumer
BiPredicate
Bifonksiyonel

İkiden fazla için, aşağıdaki gibi işlevsel bir arayüz oluşturmanız gerekir (Tüketici tipi):

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

1

Başka bir alternatif, bunun özel sorununuz için geçerli olup olmadığından emin değil, ancak bazıları için geçerli olabilir UnaryOperatorjava.util.function kütüphanesinde kullanmaktır . burada belirttiğiniz aynı türü döndürür, böylece tüm değişkenlerinizi bir sınıfa koyarsınız ve bu bir parametre olarak mıdır:

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

Yani sahip olduğunuz sınıf, bu durumda Person çok sayıda örnek değişkenine sahip olabilir ve lambda ifadenizin parametresini değiştirmek zorunda kalmaz.

İlgilenenler için java.util.function kütüphanesinin nasıl kullanılacağı ile ilgili notlar yazdım: http://sysdotoutdotprint.com/index.php/2017/04/28/java-util-function-library/


1

Ayrıca jOOL kütüphanesini de kullanabilirsiniz - https://github.com/jOOQ/jOOL

Zaten farklı sayıda parametre ile fonksiyon arayüzleri hazırlamıştır. Örneğin, kullanabilirsiniz org.jooq.lambda.function.Function3dan vb Function0için yukarı Function16.

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.